<commit_before>import logger from 'winston'
import * as authorisation from './authorisation'
import * as utils from '../utils'
import { ChannelModelAPI } from '../model/channels'
import { ClientModelAPI } from '../model/clients'
import { MediatorModelAPI } from '../model/mediators'
import { UserModelAPI } from '../model/users'
import { ContactGroupModelAPI } from '../model/contactGroups'
import { KeystoreModelAPI } from '../model/keystore'

// Map string parameters to collections
const collections = {
  Channels: ChannelModelAPI,
  Clients: ClientModelAPI,
  Mediators: MediatorModelAPI,
  Users: UserModelAPI,
  ContactGroups: ContactGroupModelAPI,
  KeystoreModelAPI
}

// Function to remove properties from export object
function removeProperties (obj) {
  const propertyID = '_id'
  const propertyV = '__v'

  for (const prop in 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
function getUniqueIdentifierForCollection (collection, doc) {
  let uid
  let uidKey
  switch (collection) {
    case 'Channels':
      uidKey = 'name'
      uid = doc.name
      break
    case 'Clients':
      uidKey = 'clientID'
      uid = doc.clientID
      break
    case 'Mediators':
      uidKey = 'urn'
      uid = doc.urn
      break
    case 'Users':
      uidKey = 'email'
      uid = doc.email
      break
    case 'ContactGroups':
      uidKey = 'groups'
      uid = doc.groups
      break
    default:
      logger.debug(`Unhandeled case for ${collection} in getUniqueIdentifierForCollection`)
      break
  }
  const returnObj = {}
  returnObj[uidKey] = uid
  return returnObj
}

// Build response object
function buildResponseObject (model, doc, status, message, uid) {
  return {
    model,
    record: doc,
    status,
    message,
    uid
  }
}

// API endpoint that returns metadata for export
export async function getMetadata (ctx) {
  // Test if the user is authorised
  if (!authorisation.inGroup('admin', ctx.authenticated)) {
    return utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to getMetadata denied.`, 'info')
  }

  try {
    const exportObject = {}

    // Return all documents from all collections for export
    for (const col in collections) {
      exportObject[col] = await collections[col].find().lean().exec()
      for (let doc of Array.from(exportObject[col])) {
        if (doc._id) {
          doc = removeProperties(doc)
        }
      }
    }

    ctx.body = [exportObject]
    ctx.status = 200
  } catch (e) {
    ctx.body = e.message
    utils.logAndSetResponse(ctx, 500, `Could not fetch specified metadata via the API ${e}`, 'error')
  }
}

async function handleMetadataPost (ctx, action) {
  // Test if the user is authorised
  if (!authorisation.inGroup('admin', ctx.authenticated)) {
    return utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to importMetadata denied.`, 'info')
  }

  try {
    let status
    const returnObject = []
    const insertObject = ctx.request.body

    for (const key in insertObject) {
      const insertDocuments = insertObject[key]
      for (let doc of Array.from(insertDocuments)) {
        let error
        let uid
        try {
          let result
          if (!(key in 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 === 'Keystore') {
            result = await collections[key].find().exec()
            uid = ''
          } else {
            const uidObj = getUniqueIdentifierForCollection(key, doc)
            uid = uidObj[Object.keys(uidObj)[0]]
            result = await collections[key].find(uidObj).exec()
          }

          if (action === 'import') {
            if (result && (result.length > 0) && result[0]._id) {
              if (doc._id) { delete doc._id }
              result = await collections[key].findById(result[0]._id).exec()
              result.set(doc)
              result.set('updatedBy', utils.selectAuditFields(ctx.authenticated))
              await result.save()
              status = 'Updated'
            } else {
              doc = new (collections[key])(doc)
              result = await doc.save()
              status = 'Inserted'
            }
          }

          if (action === 'validate') {
            if (result && (result.length > 0) && result[0]._id) {
              status = 'Conflict'
            } else {
              doc = new (collections[key])(doc)
              error = doc.validateSync()<commit_msg>Fix channel imports<commit_after>import logger from 'winston'
import * as authorisation from './authorisation'
import * as utils from '../utils'
import { ChannelModelAPI } from '../model/channels'
import { ClientModelAPI } from '../model/clients'
import { MediatorModelAPI } from '../model/mediators'
import { UserModelAPI } from '../model/users'
import { ContactGroupModelAPI } from '../model/contactGroups'
import { KeystoreModelAPI } from '../model/keystore'

// Map string parameters to collections
const collections = {
  Channels: ChannelModelAPI,
  Clients: ClientModelAPI,
  Mediators: MediatorModelAPI,
  Users: UserModelAPI,
  ContactGroups: ContactGroupModelAPI,
  KeystoreModelAPI
}

// Function to remove properties from export object
function removeProperties (obj) {
  const propertyID = '_id'
  const propertyV = '__v'

  for (const prop in 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
function getUniqueIdentifierForCollection (collection, doc) {
  let uid
  let uidKey
  switch (collection) {
    case 'Channels':
      uidKey = 'name'
      uid = doc.name
      break
    case 'Clients':
      uidKey = 'clientID'
      uid = doc.clientID
      break
    case 'Mediators':
      uidKey = 'urn'
      uid = doc.urn
      break
    case 'Users':
      uidKey = 'email'
      uid = doc.email
      break
    case 'ContactGroups':
      uidKey = 'groups'
      uid = doc.groups
      break
    default:
      logger.debug(`Unhandeled case for ${collection} in getUniqueIdentifierForCollection`)
      break
  }
  const returnObj = {}
  returnObj[uidKey] = uid
  return returnObj
}

// Build response object
function buildResponseObject (model, doc, status, message, uid) {
  return {
    model,
    record: doc,
    status,
    message,
    uid
  }
}

// API endpoint that returns metadata for export
export async function getMetadata (ctx) {
  // Test if the user is authorised
  if (!authorisation.inGroup('admin', ctx.authenticated)) {
    return utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to getMetadata denied.`, 'info')
  }

  try {
    const exportObject = {}

    // Return all documents from all collections for export
    for (const col in collections) {
      exportObject[col] = await collections[col].find().lean().exec()
      for (let doc of Array.from(exportObject[col])) {
        if (doc._id) {
          doc = removeProperties(doc)
        }
      }
    }

    ctx.body = [exportObject]
    ctx.status = 200
  } catch (e) {
    ctx.body = e.message
    utils.logAndSetResponse(ctx, 500, `Could not fetch specified metadata via the API ${e}`, 'error')
  }
}

async function handleMetadataPost (ctx, action) {
  // Test if the user is authorised
  if (!authorisation.inGroup('admin', ctx.authenticated)) {
    return utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to importMetadata denied.`, 'info')
  }

  try {
    let status
    const returnObject = []
    const insertObject = ctx.request.body

    for (const key in insertObject) {
      const insertDocuments = insertObject[key]
      for (let doc of Array.from(insertDocuments)) {
        let error
        let uid
        try {
          let result
          if (!(key in 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 === 'Keystore') {
            result = await collections[key].find().exec()
            uid = ''
          } else {
            const uidObj = getUniqueIdentifierForCollection(key, doc)
            uid = uidObj[Object.keys(uidObj)[0]]
            result = await collections[key].find(uidObj).exec()
          }

          if (action === 'import') {
            if (result && (result.length > 0) && result[0]._id) {
              if (doc._id) { delete doc._id }
              result = await collections[key].findById(result[0]._id).exec()
              result.set(doc)
              result.set('updatedBy', utils.selectAuditFields(ctx.authenticated))
              await result.save()
              status = 'Updated'
            } else {
              doc = new (collections[key])(doc)
              doc.set('updatedBy', utils.selectAuditFields(ctx.authenticated))
              result = await doc.save()
              status = 'Inserted'
            }
          }

          if (action === 'validate') {
            if (result && (result.length > 0) && result[0]._id) {
              status = 'Conflict'
            } else {
              doc = new (collections[key])(doc)
              doc.set('updatedBy', utils.selectAuditFields(ctx.authenticated))
              error = doc.validateSync()
{'fraction_non_alphanumeric': 0.11308921707465103, 'fraction_numerical': 0.003641513251062108, 'mean_word_length': 2.408135125818683, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4077431', 'n_tokens_mistral': 2825, 'n_tokens_neox': 2758, 'n_words': 837}