cozy-labs/cozy-desktop

View on GitHub
dev/remote/change-dir-exclusions.js

Summary

Maintainability
B
5 hrs
Test Coverage
require('../../core/globals')
const { app } = require('electron')
const yargs = require('yargs')
const treeify = require('treeify')
const path = require('path')
const OldCozyClient = require('cozy-client-js').Client
const { default: CozyClient, Q } = require('cozy-client')
const _ = require('lodash')

const { Config } = require('../../core/config')
const {
  DIR_TYPE,
  FILES_DOCTYPE,
  OAUTH_CLIENTS_DOCTYPE,
  ROOT_DIR_ID,
  TRASH_DIR_ID
} = require('../../core/remote/constants')

const args = (argv /*: Array<*> */ = process.argv) => {
  const config = yargs
    .env('Change directory exclusions')
    .usage('$0 [--list] [--add <directories>] [--remove <directories>]')
    .options({
      a: {
        alias: 'add',
        describe:
          'list directories to be excluded from the synchronization (directories already excluded will be ignored',
        type: 'array',
        requiresArg: true,
        default: []
      },
      r: {
        alias: 'remove',
        describe:
          'list directories to be re-included in the synchronization (directories already included will be ignored',
        type: 'array',
        requiresArg: true,
        default: []
      },
      l: {
        alias: 'list',
        describe:
          'list current directories and their exclusion state (i.e. True or False)'
      }
    })
    .help()
    .parse(argv)

  return config
}

async function changeDirExclusions(context, { add, remove }) {
  const { client } = context
  const addedDirs = await client.query(
    Q(FILES_DOCTYPE).where({ path: { $in: add } })
  )
  const removedDirs = await client.query(
    Q(FILES_DOCTYPE).where({ path: { $in: remove } })
  )

  const oauthClient = {
    _id: getClientId(context),
    _type: OAUTH_CLIENTS_DOCTYPE
  }
  const files = client.collection(FILES_DOCTYPE)
  await files.addNotSynchronizedDirectories(oauthClient, addedDirs.data)
  await files.removeNotSynchronizedDirectories(oauthClient, removedDirs.data)
}

function getClientId(context) {
  return context.config.client.clientID
}

function isExcludedFromSync(context, not_synchronized_on = []) {
  return not_synchronized_on.find(c => c.id === getClientId(context)) != null
}

async function getDirectoryContent(context) {
  const { client } = context
  const dir = { _id: ROOT_DIR_ID, path: '/', name: '/' }
  const dirContent = { [dir.name]: {} }
  let resp /*: { next: boolean, bookmark?: string, data: Object[] } */ = {
    next: true,
    data: []
  }
  while (resp && resp.next) {
    const queryDef = Q(FILES_DOCTYPE)
      .where({
        type: DIR_TYPE,
        name: {
          $ne: ''
        },
        _id: {
          $ne: TRASH_DIR_ID
        }
      })
      .indexFields(['path', 'name', '_id'])
      .sortBy([{ path: 'asc' }])
      .limitBy(10000)
      .offsetBookmark(resp.bookmark)

    resp = await client.query(queryDef)

    for (const j of resp.data) {
      const {
        attributes: { path: dirPath, name, not_synchronized_on },
        _deleted
      } = j
      if (_deleted) continue

      const parentPath = path.dirname(dirPath).split('/').slice(1).join('.')
      const key = parentPath === '' ? dir.name : `${dir.name}.${parentPath}`
      const parent = _.get(dirContent, key)
      if (!parent) continue

      if (isExcludedFromSync(context, not_synchronized_on)) {
        parent[`${name} (EXCLUDED)`] = {}
      } else {
        parent[name] = {}
      }
    }
  }
  return dirContent
}

async function showTree(context) {
  const tree = await getDirectoryContent(context)
  // eslint-disable-next-line no-console
  console.log(treeify.asTree(tree))
}

app
  .whenReady()
  .then(async () => {
    const { COZY_DESKTOP_DIR } = process.env

    const config = new Config(path.resolve(COZY_DESKTOP_DIR, '.cozy-desktop'))
    const oldClient = new OldCozyClient({
      version: 3,
      cozyURL: config.cozyUrl,
      oauth: {
        clientParams: config.client,
        storage: config
      }
    })
    await oldClient.authorize()
    const client = await CozyClient.fromOldOAuthClient(oldClient)
    const context = { client, config }

    const { list, add, remove } = args()
    if (list || (add.length === 0 && remove.length === 0)) {
      await showTree(context)
      return
    } else {
      await changeDirExclusions(context, { add, remove })
      // eslint-disable-next-line no-console
      console.log('Exclusions changed.')
      return
    }
  })
  .then(() => {
    return app.exit(0) // eslint-disable-line no-process-exit
  })
  .catch(err => {
    if (err.message === 'Device not configured') {
      // eslint-disable-next-line no-console
      console.log('\nYou need to register a dev client first.\n')
    } else {
      // eslint-disable-next-line no-console
      console.error(err)
    }
    app.exit(1)
  })