Nanocloud/nanocloud

View on GitHub
api/controllers/StorageController.js

Summary

Maintainability
F
4 days
Test Coverage
/**
 * Nanocloud turns any traditional software into a cloud solution, without
 * changing or redeveloping existing source code.
 *
 * Copyright (C) 2016 Nanocloud Software
 *
 * This file is part of Nanocloud.
 *
 * Nanocloud is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Nanocloud is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General
 * Public License
 * along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

/**
 * StorageController
 *
 * @description :: Server-side logic for managing uploads
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

/* globals AccessToken, ConfigService, Machine, PlazaService, Storage, StorageService, Team, User */

const Promise = require('bluebird');

module.exports = {

  /**
   * Create a directory in user's storage
   *
   * @method upload
   * @public true
   */
  create: function(req, res) {
    let filename = req.query.filename;
    let promise = null;

    if (req.allParams().teams === 'true') {
      promise = Promise.props({
        user: User.findOne(req.user.id).populate('team'),
        config: ConfigService.get('teamStorageAddress', 'teamStoragePort')
      })
        .then((result) => {
          return {
            hostname: result.config.teamStorageAddress,
            port: result.config.teamStoragePort,
            username: result.user.team.username
          };
        });
    } else {
      promise = Storage.findOne({
        user: req.user.id
      });
    }

    promise.then((storage) => {
      return PlazaService.createDirectory(storage, filename);
    })
      .then(() => {
        return this.files(req, res);
      })
      .catch(res.negotiate);
  },

  /**
   * Delete a file or a directory
   *
   * @method upload
   * @public true
   */
  destroy: function(req, res) {
    let filename = req.query.filename;
    let promise = null;

    if (req.allParams().teams === 'true') {
      promise = Promise.props({
        user: User.findOne(req.user.id).populate('team'),
        config: ConfigService.get('teamStorageAddress', 'teamStoragePort')
      })
        .then((result) => {
          return {
            hostname: result.config.teamStorageAddress,
            port: result.config.teamStoragePort,
            username: result.user.team.username
          };
        });
    } else {
      promise = Storage.findOne({
        user: req.user.id
      });
    }

    promise.then((storage) => {
      return PlazaService.remove(storage, filename);
    })
      .then(() => {
        return this.files(req, res);
      })
      .catch(res.negotiate);
  },

  /**
   * Upload a file in user's storage
   *
   * @method upload
   * @public true
   */
  upload: function(req, res) {
    let user = req.user;
    let filename = req.query.filename;
    let promise = null;

    if (req.allParams().teams === 'true') {
      promise = Promise.props({
        user: User.findOne(req.user.id).populate('team'),
        config: ConfigService.get('teamStorageAddress', 'teamStoragePort')
      })
        .then((result) => {
          return Promise.resolve({
            hostname: result.config.teamStorageAddress,
            port: result.config.teamStoragePort,
            username: result.user.team.username
          });
        });
    } else {
      promise = StorageService.findOrCreate(user)
        .then((storage) => {
          return StorageService.checkUploadLimit(storage, parseInt(req.headers['content-length'], 10))
            .then(() => {
              return storage;
            });
        });
    }

    promise.then((storage) => {
      return new Promise(function(resolve, reject) {
        req.file(filename).upload({
          maxBytes: 0
        }, function(error, uploadedFiles) {
          return error ? reject(error) : resolve(uploadedFiles);
        });
      })
        .then((uploadedFiles) => {
          // If no files were uploaded, respond with an error.
          if (uploadedFiles.length === 0){
            return res.badRequest('No file was uploaded');
          }

          return PlazaService.upload(storage, uploadedFiles[0]);
        })
        .then((response) => {
          return res.ok(response.body);
        })
        .catch((err) => {
          if (err.statusCode === 403) {
            return res.forbidden(err.message);
          }
          return res.negotiate(err);
        });
    });
  },

  /**
   * files get a list of files
   *
   * @method files
   * @public true
   */
  files: function(req, res) {

    let getFiles;
    let machine = req.allParams().machine;

    if (machine) {
      getFiles = Machine.findOne(machine)
        .then((machine) => {
          return PlazaService.files({
            hostname: machine.ip,
            port: machine.plazaport
          }, req.allParams().path || 'C:\\');
        });
    } else if (req.allParams().teams === 'true') {
      if (! req.user.team) {
        return res.send({data: []});
      }
      getFiles = Team.findOne(req.user.team)
        .then((team) => {
          if (team === undefined) {
            return res.badRequest('Cannot find the team you belong to');
          }

          return ConfigService.get('teamStorageAddress', 'teamStoragePort')
            .then((config) => {
              return PlazaService.files({
                hostname: config.teamStorageAddress,
                port: config.teamStoragePort
              }, '/home/' + team.username + '/' + (req.allParams().path || ''));
            });
        })
        .catch(res.negotiate);
    } else {
      getFiles = StorageService.findOrCreate(req.user)
        .then((storage) => {
          return PlazaService.files(storage, '/home/' + storage.username)
            .then((files) => {
              return StorageService.storageSize(storage)
                .then((size) => {
                  files.meta = {
                    storageSize: size
                  };
                  return files;
                });
            });
        });
    }
    getFiles.then((files) => {
      return res.send(files);
    })
      .catch(res.negotiate);
  },

  /**
   * download a file from storage
   *
   * @method download
   * @public true
   */
  download: function(req, res) {
    let filename = req.query.filename;
    let downloadToken = req.query.token;

    AccessToken.findOne({
      id: downloadToken.split(':')[0]
    })
      .then((accessToken) => {
        if (req.allParams().teams === 'true') {
          return Promise.props({
            user: User.findOne(accessToken.userId).populate('team'),
            config: ConfigService.get('teamStorageAddress', 'teamStoragePort')
          })
            .then((result) => {
              return {
                hostname: result.config.teamStorageAddress,
                port: result.config.teamStoragePort,
                username: result.user.team.username
              };
            });
        } else {
          return Storage.findOne({
            user: accessToken.userId
          });
        }
      })
      .then((storage) => {
        return PlazaService.download(storage, '/home/' + storage.username + '/' + filename);
      })
      .then((dataStream) => {
        return dataStream.pipe(res.attachment(filename));
      })
      .catch((err) => {
        return res.negotiate(err);
      });
  },

  /**
   * token create a one hour token for download
   *
   * @method token
   * @public true
   */
  token: function(req, res) {
    let user = req.user;
    let filename = req.query.filename;

    AccessToken.findOne({userId: user.id}, (err, accessToken) => {
      if (err !== null) {
        return res.negotiate(err);
      }
      return res.send(200, {
        token: StorageService.createToken(accessToken, filename)
      });
    });
  },

  /**
   * rename is used to rename files
   *
   * @method rename
   * @public true
   */
  rename: function(req, res) {
    let filename = req.query.filename;
    let newFilename = req.query.newfilename;
    let promise = null;

    if (req.allParams().teams === 'true') {
      promise = Promise.props({
        user: User.findOne(req.user.id).populate('team'),
        config: ConfigService.get('teamStorageAddress', 'teamStoragePort')
      })
        .then((result) => {
          return {
            hostname: result.config.teamStorageAddress,
            port: result.config.teamStoragePort,
            username: result.user.team.username
          };
        });
    } else {
      promise = Storage.findOne({
        user: req.user.id
      });
    }

    promise.then((storage) => {
      return PlazaService.rename(storage, filename, newFilename);
    })
      .then(() => {
        return this.files(req, res);
      })
      .catch(res.negotiate);
  },

  update: function(req, res) {
    return res.forbidden();
  }
};