dataplug-io/toggl-dataplug

View on GitHub
lib/collections/projects.js

Summary

Maintainability
A
55 mins
Test Coverage
const { URL } = require('url')
const dataplug = require('@dataplug/dataplug')
const { PagedHttpGetReader } = require('@dataplug/dataplug-http')
const { JsonStreamReader } = require('@dataplug/dataplug-json')
const config = require('../config')

const schema = {
  type: 'object',
  definitions: {},
  properties: {
    id: {
      description: 'Project ID',
      type: 'integer'
    },
    name: {
      description: 'The name of the project',
      type: 'string'
    },
    workspace_id: {
      description: 'Workspace ID, where the project will be saved',
      type: 'integer'
    },
    wid: {
      description: 'Workspace ID, where the project will be saved',
      type: 'integer'
    },
    client_id: {
      description: 'Client ID',
      type: ['integer', 'null']
    },
    cid: {
      description: 'Client ID',
      type: ['integer', 'null']
    },
    active: {
      description: 'Whether the project is archived or not',
      type: 'boolean'
    },
    is_private: {
      description: 'Whether project is accessible for only project users or for all workspace users',
      type: 'boolean'
    },
    template: {
      description: 'Whether the project can be used as a template',
      type: 'boolean'
    },
    template_id: {
      description: 'ID of the template project used on current project\'s creation',
      type: ['integer', 'null']
    },
    billable: {
      description: 'Whether the project is billable or not',
      type: 'boolean'
    },
    auto_estimates: {
      description: 'Whether the estimated hours are automatically calculated based on task estimations or manually fixed based on the value of \'estimated_hours\'',
      type: 'boolean'
    },
    estimated_hours: {
      description: 'If auto_estimates is true then the sum of task estimations is returned, otherwise user inserted hours',
      type: ['integer', 'null']
    },
    at: {
      description: 'Timestamp indicating when the time task was last updated',
      type: 'string',
      format: 'date-time'
    },
    created_at: {
      description: 'Timestamp indicating when the project was created',
      type: 'string',
      format: 'date-time'
    },
    server_deleted_at: {
      description: 'Timestamp indicating when the project was deleted',
      type: ['string', 'null'],
      format: 'date-time'
    },
    color: {
      description: 'ID of the color selected for the project',
      type: 'string'
    },
    rate: {
      description: 'Hourly rate of the project',
      type: ['integer', 'null']
    },
    currency: {
      description: 'Billable amount currency',
      type: ['string', 'null']
    },
    actual_hours: {
      description: 'Completed hours of the project',
      type: ['integer', 'null']
    }
  },
  additionalProperties: false,
  required: ['id']
}

const configDeclaration = config.declaration.extended((declaration) => declaration
  .parameters({
    workspace: {
      description: 'The workspace ID to query data from',
      type: 'integer',
      required: true
    },
    active: {
      description: 'To filter projects by their state',
      enum: ['true', 'false', 'both'],
      default: 'both'
    },
    actualHours: {
      description: 'Get the completed hours per project',
      type: 'boolean',
      default: false
    },
    onlyTemplates: {
      description: 'Get only project templates',
      enum: ['true', 'false'],
      default: 'false'
    }
  })
)

const queryMapping = config.mapping.query.extended((mapping) => mapping
  .asIs('active')
  .rename('actualHours', 'actual_hours')
  .rename('onlyTemplates', 'only_templates')
)

const factory = (params) => {
  const url = new URL(`api/v9/workspaces/${params.workspace}/projects`, params.endpoint)
  const nextPage = (page, data) => {
    if (data) {
      const currentPage = data.page || 1
      if (currentPage * data.per_page < data.total_count) {
        page.query.page = currentPage + 1

        return true
      }
    }

    return false
  }
  const transformFactory = () => new JsonStreamReader('!.data.*')
  const query = queryMapping.apply(params)
  const headers = config.mapping.headers.apply(params)

  return new PagedHttpGetReader(url, nextPage, {
    transformFactory,
    query,
    headers
  })
}

const source = dataplug.source(configDeclaration, factory)

module.exports = {
  origin: 'toggl',
  name: 'projects',
  schema,
  source
}