nitrotasks/nitro-server

View on GitHub
lib/controllers/helpers.js

Summary

Maintainability
B
5 hrs
Test Coverage
const User = require('../models/user')
const List = require('../models/list')
const Task = require('../models/task')
const ArchivedTask = require('../models/archivedtask')
const Meta = require('../models/meta')

const listOrderKey = 'list-order'

const listAttributes = [
  'id',
  'name',
  'notes',
  'sort',
  'updatedAt',
  'createdAt',
  'order'
]
const userAttributes = ['id', 'friendlyName', 'email']
const fullTaskAttributes = [
  'id',
  'name',
  'type',
  'notes',
  'completed',
  'date',
  'deadline',
  'priority',
  'updatedAt',
  'createdAt'
]
const filterByUser = userId => {
  return {
    model: User,
    attributes: [],
    where: {
      id: userId
    }
  }
}

const tasksDetails = function(fullDetails = false, reqQuery, userId, listId) {
  return new Promise((resolve, reject) => {
    const taskModel = {
      model: Task,
      attributes: ['id', 'updatedAt', 'createdAt']
    }
    // if we mutate fullDetails, bad things seem to happen :|
    const showAllDetails =
      fullDetails || ('tasks' in reqQuery && reqQuery.tasks.length > 0)
    if (showAllDetails) {
      taskModel.attributes = fullTaskAttributes

      if ('tasks' in reqQuery) {
        const options = reqQuery.tasks.split(',')
        taskModel.where = { id: options }
      }
    }
    const query = {
      attributes: listAttributes,
      include: [
        {
          model: User,
          attributes: userAttributes,
          where: {
            id: userId
          }
        },
        taskModel
      ]
    }
    List.findById(listId, query)
      .then(function(list) {
        if (list) {
          if (showAllDetails) {
            list.tasks = list.tasks.map(t => {
              t.priority = t.priority === null ? 0 : t.priority
              return t
            })
          }
          resolve(list)
        } else {
          reject({ code: 404, message: 'List could not be found.' })
        }
      })
      .catch(function(err) {
        reject({ code: 400, message: 'Invalid input syntax.' })
      })
  })
}

const archiveTasks = function(tasks, userId, listId) {
  return new Promise((resolve, reject) => {
    let taskList = null
    if ('tasks' in tasks) {
      taskList = tasks.tasks.split(',')
    }
    tasksDetails(true, {}, userId, listId)
      .then(list => {
        // For each of these tasks, add to archive list for both users
        const promises = []
        const toRemove = []
        const tasksObject = {}
        list.toJSON().tasks.forEach(item => {
          tasksObject[item.id] = item
        })
        list.users.forEach(user => {
          // this should traverse in order
          let currentHeader = null
          const adding = list
            .toJSON()
            .order.map(function(itemOrdered) {
              const item = tasksObject[itemOrdered]
              if (item.type === 'header' || item.type === 'header-collapsed') {
                currentHeader = item.name
              }
              item.header = currentHeader
              item.list = list.name
              return {
                ogId: item.id,
                data: JSON.stringify(item),
                userId: user.id
              }
            })
            .filter(item => {
              if (taskList === null || taskList.indexOf(item.ogId) > -1) {
                toRemove.push(item.ogId)
                return true
              }
              return false
            })
          promises.push(
            ArchivedTask.bulkCreate(adding, {
              validate: true
            })
          )
        })
        Promise.all(promises).then(() => {
          // remove item if it's found
          const newOrder = JSON.parse(JSON.stringify(list.order)).filter(
            function(item) {
              return toRemove.indexOf(item) === -1
            }
          )
          list
            .update({
              order: newOrder
            })
            .then(function() {
              Task.destroy({
                where: {
                  id: toRemove
                }
              }).then(function() {
                resolve(toRemove)
              })
            })
        })
      })
      .catch(reject)
  })
}

const getListOrder = async userId => {
  const currentListOrder = await Meta.findOne({
    where: { key: listOrderKey },
    include: filterByUser(userId)
  })
  let parsedCorrectly = false
  try {
    currentListOrder.value.slice()
    parsedCorrectly = true
  } catch (err) {
    // do nothing
  }
  if (currentListOrder === null || parsedCorrectly === false) {
    // needs to create data for the first time
    const lists = await List.findAll({
      attributes: ['id', 'createdAt'],
      include: filterByUser(userId),
      order: [['createdAt', 'DESC']]
    })
    const newOrder = lists.map(i => i.id)
    await Meta.create({
      key: listOrderKey,
      value: newOrder,
      userId: userId
    })
    // should take the second execution path the next time
    return await getListOrder(userId)
  }
  return currentListOrder
}

const appendToListOrder = async (userId, listId) => {
  const currentListOrder = await getListOrder(userId)
  let newOrder = currentListOrder.value.slice()
  let index = newOrder.indexOf(listId)

  // checks to make sure that item is not already in list
  if (index === -1) {
    newOrder.push(listId)

    await currentListOrder.update({
      value: newOrder
    })
  }
}

const removeFromListOrder = async (userId, listId) => {
  const currentListOrder = await getListOrder(userId)
  let newOrder = currentListOrder.value.slice()
  let index = newOrder.indexOf(listId)

  // checks to make sure that item is already in list
  if (index > -1) {
    newOrder.splice(index, 1)

    await currentListOrder.update({
      value: newOrder
    })
  }
}

module.exports = {
  tasksDetails: tasksDetails,
  archiveTasks: archiveTasks,
  fullTaskAttributes: fullTaskAttributes,
  getListOrder: getListOrder,
  appendToListOrder: appendToListOrder,
  removeFromListOrder: removeFromListOrder,
  filterByUser: filterByUser
}