Source: controllers/admin.controller.js

/**
 * Admin controller
 *
 * @module controllers/admin
 * @see module:controllers
 */

/* Packages */
const express = require('express');
const weekNumber = require('current-week-number');
const {
  spawn,
} = require('child_process');

/* Models */
const Data = require('./../models/data');
const SensorHub = require('./../models/sensorhub');
const User = require('./../models/user');
const Config = require('./../models/config');

/* Constants */
const router = express.Router();

/* Middlewares */
const {
  isAdmin,
} = require('./../middlewares');

/**
 * Renders the admin page.
 *
 * @name Admin
 * @path {GET} /admin
 * @code {200} if the request is successful
 */
router.get('/', isAdmin, (req, res, next) => {
  User.find({}).exec()
    .then(users => SensorHub.find({}).exec()
      .then(sensorHubs => [users, sensorHubs]))
    .then(([users, sensorHubs]) => Config.find({}).exec()
      .then(configs => [users, sensorHubs, configs]))
    .then(([users, sensorHubs, configs]) => {
      res.render('admin', {
        users,
        sensorHubs,
        configs,
      });
    })
    .catch((err) => {
      next(err);
    });
});

/**
 * Flips the inMargin field of a data-object.
 *
 * @name Flip
 * @path {GET} /admin
 * @params {String} :id mongodb _id of the object to flip.
 * @code {302} if the request is successful
 * @code {500} if the request is failed
 */
router.get('/flip/:id', isAdmin, (req, res, next) => {
  Data.findOne({
    _id: req.params.id,
  }).exec()
    .then((data) => {
      if (data == null) {
        next(new Error('Not found'));
        return;
      }

      const date = new Date(data.Timestamp);

      let type = 0;
      if (data.Type === 'temperature') {
        type = 0;
      } else if (data.Type === 'gasses') {
        type = 1;
      } else {
        type = 2;
      }

      let {
        inMargin,
      } = data;
      if (inMargin === 0) {
        inMargin = 1;
      } else {
        inMargin = 0;
      }

      const py = spawn('python', ['ml.py']);
      const pyData = [
        date.getDay() - 1,
        weekNumber(date),
        date.getUTCHours(),
        type,
        parseInt(data.Value, 10),
        inMargin,
      ];

      let dataString = '';
      py.stdout.on('data', (output) => {
        dataString += output.toString();
      });

      py.stdout.on('end', () => {
        const output = JSON.parse(dataString)[0];
        // eslint-disable-next-line no-param-reassign
        data.inMargin = output;
        data.save()
          .then(() => {
            res.redirect('back');
          })
          .catch((err) => {
            next(err);
          });
      });

      py.stdin.write(JSON.stringify(pyData));
      py.stdin.end();
    })
    .catch((err) => {
      next(err);
    });
});

/**
 * Renders a specific sensorhub edit page.
 *
 * @name editsensor
 * @path {GET} /editsensor/:SerialID
 * @params {String} :SerialID is the SerialID of the limit.
 */
router.get('/editsensor/:SerialID', isAdmin, (req, res, next) => {
  SensorHub.findOne({
    SerialID: req.params.SerialID,
  }).exec()
    .then((SerialID) => {
      if (SerialID === null) {
        next(new Error(`Could not find sensorhub with ID: '${req.params.SerialID}'!`));
        return;
      }
      res.render('editsensor', {
        SerialID,
      });
    })
    .catch((err) => {
      next(err);
    });
});

/**
 * Saves the changes to an sensorhub
 *
 * @name Profile
 * @path {POST} /editsensor/:SerialID
 */
router.post('/editsensor/:SerialID', isAdmin, (req, res, next) => {
  const {
    Latitude,
    Longitude,
  } = req.body;

  SensorHub.findOne({
    SerialID: req.params.SerialID,
  }).exec()
    .then((sensorHub) => {
      if (!sensorHub) {
        next(new Error(`Could not find sensorhub with ID: '${req.params.SerialID}'!`));
        return;
      }

      if (Latitude) {
        // eslint-disable-next-line no-param-reassign
        sensorHub.Latitude = Latitude;
      }

      if (Longitude) {
        // eslint-disable-next-line no-param-reassign
        sensorHub.Longitude = Longitude;
      }

      sensorHub.save();

      res.redirect('/admin');
    })
    .catch((err) => {
      next(err);
    });
});

/**
 * Renders a specific config page.
 *
 * @name config
 * @path {GET} /config/:valueID
 * @params {String} :valueID is the SerialID of the config.
 */
router.get('/config/:valueID', isAdmin, (req, res, next) => {
  Config.findOne({
    valueID: req.params.valueID,
  }).exec()
    .then((valueID) => {
      if (valueID === null) {
        next(new Error(`Could not find config with ID: '${req.params.valueID}'!`));
        return;
      }
      res.render('config', {
        valueID,
      });
    })
    .catch((err) => {
      next(err);
    });
});

/**
 * Saves the changes to an config
 *
 * @name Profile
 * @path {POST} /config/:valueID
 */
router.post('/config/:valueID', isAdmin, (req, res, next) => {
  const {
    value,
  } = req.body;

  if (!value) {
    res.redirect('/admin');
    return;
  }

  Config.findOne({
    valueID: req.params.valueID,
  }).exec()
    .then((config) => {
      if (!config) {
        next(new Error(`Could not find config with ID: '${req.params.valueID}'!`));
        return;
      }

      // eslint-disable-next-line no-param-reassign
      config.value = value;
      config.save();

      res.redirect('/admin');
    })
    .catch((err) => {
      next(err);
    });
});

/**
 * Uploads a logo.
 *
 * @name Upload logo
 * @path {POST} /admin/upload-logo
 * @code {200} if a PNG file is uploaded successfully
 * @code {400} if no files or the wrong file type is uploaded
 */
router.post('/upload-logo', isAdmin, (req, res, next) => {
  if (!req.files) {
    res.status(400).send('No files were uploaded.');
    return;
  }

  /* The name of the input field is used to retrieve the uploaded file. */
  const {
    logo,
  } = req.files;

  /* Checks if image is a PNG file. */
  if (logo.mimetype !== 'image/png') {
    res.redirect(400, '/admin');
    return;
  }

  /* Uses the mv() method to save this file. */
  logo.mv('./public/logo.png', (err) => {
    if (err) {
      next(err);
    } else {
      res.redirect(200, '/admin');
    }
  });
});

/* Exports */
module.exports = router;