Source: cognito.js

'use strict'

const AWS = require('aws-sdk')
const { cleanCognitoKeys } = require('./helpers')

const cog = new AWS.CognitoIdentityServiceProvider({ region: process.env.AWS_REGION })
const errors = require('./errors')

const paramDefaults = {
  UserPoolId: process.env.COGNITO_USERPOOL_ID,
}

/**
 * @namespace cognito
 */
const cognito = {}

/**
 * Get all users from the specified user group
 * @param  {string} group - The name of the group to fetch users from
 * @return {array}        - An array of users with cleaned properties
 */
cognito.getGroupUsers = (group) => {
  const params = {
    ...paramDefaults,
    GroupName: group,
  }

  return new Promise((resolve, reject) => {
    cog.listUsersInGroup(params, (error, data) => {
      if (error) {
        reject(error)
      } else {
        resolve(data.Users.map(cleanCognitoKeys))
      }
    })
  })
}

/**
 * Get a user from the specified user ID
 * @param  {string} id - The id of the user to fetch
 * @return {promise}   - A promise that resolves to the user object with cleaned properties
 */
cognito.getUser = (id) => {
  const params = {
    ...paramDefaults,
    Filter: `sub = "${id}"`,
  }

  return new Promise((resolve, reject) => {
    cog.listUsers(params, (error, data) => {
      if (error) {
        reject(error)
      } else if (data.Users.length === 0) {
        reject(new errors.UserNotFoundError())
      } else {
        resolve(cleanCognitoKeys(data.Users[0]))
      }
    })
  })
}

/**
 * Get all users from the user pool
 * @return {promise}   - A promise that resolves to the user object with cleaned properties
 */
cognito.getAllUsers = () => {
  const params = {
    ...paramDefaults,
  }

  return new Promise((resolve, reject) => {
    cog.listUsers(params, (error, data) => {
      if (error) {
        reject(error)
      } else {
        resolve(cleanCognitoKeys(data.Users))
      }
    })
  })
}

/**
 * Get the groups a user belongs to
 * @param  {string} id - The ID of the user to look up
 * @return {promise}   - A promise that resolves to an array of group names
 */
cognito.getUserGroups = id => (
  cognito.getUser(id)
    .then((user) => {
      const params = {
        ...paramDefaults,
        Username: user.username,
      }

      return new Promise((resolve, reject) => {
        cog.adminListGroupsForUser(params, (error, data) => {
          if (error) {
            reject(error)
          } else {
            resolve(data.Groups.map(group => group.GroupName))
          }
        })
      })
    })
)

/**
 * Update a user's Cognito attributes
 * @param  {string} id         - The ID of the user to edit
 * @param  {object} attributes - The attributes to change
 * @return {promise}           - A promisethat resolves on completion
 */
cognito.updateUserAttributes = (id, attributes) => {
  const emptyValues = [null, undefined]

  return cognito.getUser(id)
    .then((user) => {
      const params = {
        ...paramDefaults,
        Username: user.username,
        UserAttributes: Object.entries(attributes)
          // Map attributes and replace null values with empty strings
          .map(([key, value]) => ({
            Name: key,
            Value: emptyValues.includes(value) ? '' : value,
          })),
      }

      return new Promise((resolve, reject) => {
        cog.adminUpdateUserAttributes(
          params,
          (error) => {
            if (error) {
              reject(error)
            } else {
              resolve()
            }
          }
        )
      })
    })
}

module.exports = cognito