linagora/openpaas-esn

View on GitHub
modules/linagora.esn.davproxy/backend/webserver/addressbooks/controller.js

Summary

Maintainability
F
1 wk
Test Coverage
'use strict';

const q = require('q');
const PATH = 'addressbooks';

module.exports = function(dependencies) {
  const logger = dependencies('logger');
  const contactModule = dependencies('contact');
  const proxy = require('../proxy')(dependencies)(PATH);
  const avatarHelper = require('./avatarHelper')(dependencies);

  return {
    createAddressbook,
    defaultHandler,
    deleteContact,
    getAddressbook,
    getAddressbooks,
    getContact,
    getContacts,
    getContactsFromDAV,
    searchContacts,
    moveContact,
    removeAddressbook,
    updateAddressbook,
    updateContact
  };

  function createAddressbook(req, res) {
    const options = {
      ESNToken: req.token && req.token.token ? req.token.token : '',
      davserver: req.davserver
    };

    const addressbook = {
      id: req.body.id,
      'dav:name': req.body.name,
      'carddav:description': req.body.description,
      'dav:acl': req.body.acl || ['dav:read', 'dav:write'],
      type: req.body.type,
      state: req.body.state,
      'openpaas:source': req.body['openpaas:source']
    };

    contactModule.lib.client(options)
      .addressbookHome(req.params.bookHome)
      .addressbook()
      .create(addressbook)
      .then(response => res.status(201).json(response.body))
      .catch(err => {
        const details = 'Error while creating addressbook on DAV server';

        logger.error(details, err);

        res.status(500).json({
          error: {
            code: 500,
            message: 'Server Error',
            details
          }
        });
      });
  }

  function removeAddressbook(req, res) {
    const options = {
      ESNToken: req.token && req.token.token ? req.token.token : '',
      davserver: req.davserver
    };

    contactModule.lib.client(options)
      .addressbookHome(req.params.bookHome)
      .addressbook(req.params.bookName)
      .remove()
      .then(() => res.status(204).json())
      .catch(err => {
        const details = 'Error while removing addressbook on DAV server';

        logger.error(details, err);

        res.status(500).json({
          error: {
            code: 500,
            message: 'Server Error',
            details
          }
        });
      });
  }

  function updateAddressbook(req, res) {
    const options = {
      ESNToken: req.token && req.token.token ? req.token.token : '',
      davserver: req.davserver
    };
    const modified = {
      'dav:name': req.body.name,
      'carddav:description': req.body.description,
      state: req.body.state
    };

    contactModule.lib.client(options)
      .addressbookHome(req.params.bookHome)
      .addressbook(req.params.bookName)
      .update(modified)
      .then(() => res.status(204).json())
      .catch(err => {
        const details = 'Error while updating addressbook on DAV server';

        logger.error(details, err);

        res.status(500).json({
          error: {
            code: 500,
            message: 'Server Error',
            details
          }
        });
      });
  }

  function getContactUrl(davserver, bookHome, bookName, contactId) {
    return [davserver, '/', PATH, '/', bookHome, '/', bookName, '/', contactId, '.vcf'].join('');
  }

  function getContactsFromDAV(req, res) {
    var options = {
      ESNToken: req.token && req.token.token ? req.token.token : '',
      davserver: req.davserver
    };

    contactModule.lib.client(options)
      .addressbookHome(req.params.bookHome)
      .addressbook(req.params.bookName)
      .vcard()
      .list(req.query)
      .then(function(data) {
        var body = data.body;
        var response = data.response;

        // inject text avatar if there's no avatar
        if (body && body._embedded && body._embedded['dav:item']) {
          q.all(body._embedded['dav:item'].map(function(davItem) {
            return avatarHelper.injectTextAvatar(req.user, req.params.bookHome, req.params.bookName, davItem.data)
              .then(function(newData) {
                davItem.data = newData;
              });
          })).then(function() {
            return res.status(response.statusCode).json(body);
          });
        } else {
          return res.status(response.statusCode).json(body);
        }
      }, function(err) {
        res.status(500).json({
          error: {
            code: 500,
            message: 'Server Error',
            details: err || 'Error while getting contacts from DAV server'
          }
        });
      });
  }

  function getContact(req, res) {
    var options = {
      ESNToken: req.token && req.token.token ? req.token.token : '',
      davserver: req.davserver
    };

    contactModule.lib.client(options)
      .addressbookHome(req.params.bookHome)
      .addressbook(req.params.bookName)
      .vcard(req.params.contactId)
      .get()
      .then(function(data) {
        avatarHelper.injectTextAvatar(req.user, req.params.bookHome, req.params.bookName, data.body).then(function(newBody) {
          res.set('ETag', data.response.headers.etag);

          return res.status(data.response.statusCode).json(newBody);
        });
      }, function(err) {
        res.status(500).json({
          error: {
            code: 500,
            message: 'Server Error',
            details: err || 'Error while getting contact from DAV server'
          }
        });
      });
  }

  function updateContact(req, res) {
    var headers = req.headers || {};

    headers.ESNToken = req.token && req.token.token ? req.token.token : '';

    // Workaround to avoid frontend accidentally save text avatar to backend
    req.body = avatarHelper.removeTextAvatar(req.body);
    // Since req.body has been modified so contentLength will not be the same
    // Delete it to avoid issule relating to contentLength while sending request
    delete headers['content-length'];

    var options = {
      ESNToken: headers.ESNToken,
      davserver: req.davserver
    };

    if (!headers['if-match']) {
      contactModule.lib.client(options)
        .addressbookHome(req.params.bookHome)
        .addressbook(req.params.bookName)
        .vcard(req.params.contactId)
        .create(req.body)
        .then(function(data) {
          res.status(data.response.statusCode).json(data.body);
        }, function(err) {
          var msg = 'Error while creating contact on DAV server';

          logger.error(msg, err);

          res.status(500).json({
            error: {
              code: 500,
              message: 'Server Error',
              details: msg
            }
          });
        });
    } else {
      return proxy.handle({
        onError: function(response, data, req, res, callback) {
          logger.error('Error while updating contact', req.params.contactId);
          return callback(null, data);
        },

        onSuccess: function(response, data, req, res, callback) {
          logger.debug('Success while updating contact %s', req.params.contactId);

          return callback(null, data);
        },
        json: true
      })(req, res);
    }

  }

  function deleteContact(req, res) {

    return proxy.handle({
      onError: function(response, data, req, res, callback) {
        logger.error('Error while deleting contact', req.params.contactId);
        return callback(null, data);
      },

      onSuccess: function(response, data, req, res, callback) {
        logger.debug('Success while deleting contact %s', req.params.contactId);

        return callback(null, data);
      }
    })(req, res);
  }

  function defaultHandler(req, res) {
    proxy.handle()(req, res);
  }

  function getContacts(req, res) {
    if (req.query.search) {
      const options = {
        user: req.user,
        search: req.query.search,
        limit: req.query.limit,
        page: req.query.page,
        addressbooks: [{
          bookHome: req.params.bookHome,
          bookNames: [req.params.bookName]
        }],
        ESNToken: req.token && req.token.token ? req.token.token : '',
        davserver: req.davserver,
        originalUrl: req.originalUrl
      };

      return _searchContacts(options)
        .then(result => {
          res.header('X-ESN-Items-Count', result.total_count);

          return res.status(200).json(result.data);
        })
        .catch(err => {
          const details = 'Error while searching contacts';

          logger.error(details, err);

          res.status(500).json({
            error: {
              code: 500,
              message: 'Server Error',
              details
            }
          });
        });
    }

    getContactsFromDAV(req, res);
  }

  function moveContact(req, res) {
    const options = {
      ESNToken: req.token && req.token.token ? req.token.token : '',
      davserver: req.davserver
    };
    const destAddressbook = req.headers.destination;

    contactModule.lib.client(options)
      .addressbookHome(req.params.bookHome)
      .addressbook(req.params.bookName)
      .vcard(req.params.contactId)
      .move(destAddressbook)
      .then(data => {
        res.status(data.response.statusCode).json();
      })
      .catch(err => {
        const msg = 'Error while moving contact on DAV server';

        logger.error(msg, err);

        res.status(500).json({
          error: {
            code: 500,
            message: 'Server Error',
            details: msg
          }
        });
      });
  }

  function searchContacts(req, res) {
    const options = {
      user: req.user,
      search: req.query.search,
      limit: req.query.limit,
      page: req.query.page,
      addressbooks: req.query.bookName ? [{
        bookHome: req.params.bookHome,
        bookNames: req.query.bookName.split(',')
      }] : [],
      ESNToken: req.token && req.token.token ? req.token.token : '',
      davserver: req.davserver,
      originalUrl: req.originalUrl
    };

    return _searchContacts(options)
      .then(result => {
        res.header('X-ESN-Items-Count', result.total_count);

        return res.status(200).json(result.data);
      })
      .catch(err => {
        const details = 'Error while searching contacts';

        logger.error(details, err);

        res.status(500).json({
          error: {
            code: 500,
            message: 'Server Error',
            details
          }
        });
      });
  }

  function getAddressbooks(req, res) {
    var options = {
      ESNToken: req.token && req.token.token ? req.token.token : '',
      davserver: req.davserver
    };
    const client = contactModule.lib.client(options);

    client
      .addressbookHome(req.params.bookHome)
      .addressbook()
      .list({ query: req.query })
      .then(data =>
        q.all(
          data.body._embedded['dav:addressbook']
            .map(addressbook => _populateSubscriptionSource(client, addressbook))
        )
        .then(() => data)
      )
      .then(function(data) {
        res.status(200).json(data.body);
      }, function(err) {
        logger.error('Error while getting addressbook list', err);
        res.status(500).json({
          error: {
            code: 500,
            message: 'Server Error',
            details: 'Error while getting addressbook list'
          }
        });
      });
  }

  function getAddressbook(req, res) {
    var options = {
      ESNToken: req.token && req.token.token ? req.token.token : '',
      davserver: req.davserver
    };
    const client = contactModule.lib.client(options);

    client
      .addressbookHome(req.params.bookHome)
      .addressbook(req.params.bookName)
      .get()
      .then(data => _populateSubscriptionSource(client, data.body))
      .then(
        body => res.status(200).json(body),
        err => {
          logger.error('Error while getting an addressbook', err.body || err);

          if (err.statusCode === 404) {
            return res.status(404).json({
              error: {
                code: 404,
                message: 'Not Found',
                details: `Addressbook ${req.params.bookName} is not found`
              }
            });
          }

          res.status(500).json({
            error: {
              code: 500,
              message: 'Server Error',
              details: 'Error while getting an addressbook'
            }
          });
        });
  }

  function _searchContacts(options) {
    const clientOptions = {
      ESNToken: options.ESNToken,
      davserver: options.davserver
    };

    return contactModule.lib.client(clientOptions)
      .searchContacts(options)
      .then(result => {
        const data = {
          _links: {
            self: {
              href: options.originalUrl
            }
          },
          _total_hits: result.total_count,
          _current_page: `${result.current_page}`,
          _embedded: {
            'dav:item': []
          }
        };

        return q.all(result.results.map((result, index) => {
          if (!result.body) {
            return;
          }

          return avatarHelper.injectTextAvatar(options.user, result.bookId, result.bookName, result.body)
            .then(newVcard => {
              data._embedded['dav:item'][index] = {
                _links: {
                  self: {
                    href: getContactUrl(options.davserver, result.bookId, result.bookName, result.contactId)
                  }
                },
                data: newVcard,
                'openpaas:addressbook': result['openpaas:addressbook']
              };
            });
        })).then(() => ({
          total_count: result.total_count,
          data
        }));
      });
  }

  function _populateSubscriptionSource(client, addressbook) {
    if (addressbook['openpaas:source']) {
      const parsedSourcePath = contactModule.lib.helper.parseAddressbookPath(addressbook['openpaas:source']);

      return client
        .addressbookHome(parsedSourcePath.bookHome)
        .addressbook(parsedSourcePath.bookName)
        .get()
        .then(data => {
          addressbook['openpaas:source'] = data.body;

          return addressbook;
        });
    }

    return q(addressbook);
  }
};