OpenVeo Manage AngularJS back end

API Docs for: 1.0.0-alpha.0
Show:

File: app/client/admin/js/ovManage/ManageableDetailController.js

'use strict';

(function(app) {

  /* global Ps */
  /**
   * Defines the manageable detail controller to manage view displaying details about a manageable.
   */
  function ManageableDetailController(
    $scope,
    $filter,
    $uibModal,
    $timeout,
    $rootScope,
    ManageFactory,
    GroupFactory,
    DeviceFactory,
    ManageableFactory,
    entityService,
    MANAGE_NAME,
    DEVICE_STATUS,
    MANAGEABLE_TYPES
  ) {
    var self = this,
      today = new Date(),
      actionEl = document.querySelector('.item-detail .action-page'),
      detailEl = document.querySelector('.item-detail .detail-page'),
      historyEl = document.querySelector('.item-detail .history-page');

    // The actually selected manageable
    self.selectedManageable = null;

    // Datepicker options
    self.popupBegin = {
      opened: false,
      minDate: today
    };
    self.popupEnd = {
      opened: false
    };

    // Minimum schedule duration allowed
    self.minDuration = new Date();
    self.minDuration.setHours(0);
    self.minDuration.setMinutes(1);
    self.minDuration.setSeconds(0);

    self.zeroTimeDate = new Date().setHours(0, 0, 0, 0);

    /**
     * Validates that begin and end dates of the new scheduled job are not in conflicts with the other scheduled jobs.
     *
     * @method validateSchedule
     * @private
     * @param {Object} schedule Schedule object with :
     *   - **Date** beginDate The begin date of the schedule
     *   - **Date** endDate The end date of the schedule
     *   - **Number** duration The schedule duration in milliseconds
     *   - **Boolean** recurrent true is this is a daily schedule, false otherwise
     * @return {Boolean} true if valid, false otherwise
     */
    function validateSchedule(schedule) {
      var validationError = null;

      var handleError = function(message) {
        $scope.$emit('setAlert', 'danger', message, 4000);
      };

      if (self.selectedManageable.type === MANAGEABLE_TYPES.GROUP) {
        validationError = GroupFactory.isValidSchedule(self.selectedManageable.id, schedule);
        if (validationError) {
          handleError(validationError.message);
          return false;
        }
      } else if (self.selectedManageable.type === MANAGEABLE_TYPES.DEVICE) {
        var group = (self.selectedManageable.group) ? GroupFactory.getGroup(self.selectedManageable.group) : null;
        validationError = DeviceFactory.isValidSchedule(self.selectedManageable.id, schedule, group);
        if (validationError) {
          handleError(validationError.message);
          return false;
        }
      }

      return true;
    }

    /**
     * Displays an error message for each given errors.
     *
     * @method displayErrors
     * @private
     * @param {Array} errors The list of errors
     * @param {String} message The message to display for each error
     */
    function displayErrors(errors, message) {
      errors.forEach(function(error) {
        $scope.$emit('setAlert', 'danger', $filter('translate')(message, null, {
          code: error.code,
          name: $filter('translate')(error.name)
        }), 4000);
      });
    }

    /**
     * Closes the details panel.
     *
     * @method closeDetail
     */
    self.closeDetail = function() {
      $scope.manage.showDetail = false;
      $scope.manage.openedItem = null;
      $scope.organizeLayout(false);
      GroupFactory.setGroupsProperty('isSelected', false);
      DeviceFactory.setDevicesProperty('isSelected', false);

      $timeout(function() {
        $scope.setActivePage(0);
      }, 350);

      // Destroy scrollbars
      Ps.destroy(actionEl);
      Ps.destroy(detailEl);
      Ps.destroy(historyEl);
    };

    /**
     * Displays the input to update the manageable's name.
     *
     * @method displayNameForm
     */
    self.displayNameForm = function() {
      self.selectedManageableName = $filter('translate')(self.selectedManageable.name);
      self.selectedManageable.displayInputName = !self.selectedManageable.displayInputName;
    };

    /**
     * Updates manageable's name.
     *
     * @method updateName
     * @param {String} name The new manageable name
     */
    self.updateName = function(name) {
      var type = null;

      if (self.selectedManageable.type === MANAGEABLE_TYPES.DEVICE)
        type = MANAGEABLE_TYPES.DEVICE;
      else
        type = MANAGEABLE_TYPES.GROUP;

      ManageFactory.updateName(self.selectedManageable.id, name, type).then(function() {
        self.selectedManageable.name = name;
        self.selectedManageable.displayInputName = !self.selectedManageable.displayInputName;
      }, function(error) {
        $scope.$emit('setAlert', 'danger', $filter('translate')('MANAGE.MANAGEABLE.UPDATE_NAME_ERROR', null, {
          code: error.code
        }), 4000);
        self.selectedManageable.displayInputName = !self.selectedManageable.displayInputName;
      });
    };

    /**
     * Adds a new schedule.
     *
     * @method addSchedule
     */
    self.addSchedule = function() {
      var durationDate = self.itemSchedule.schedule.durationDate;
      var duration = ((durationDate.getHours() * 60) + durationDate.getMinutes()) * 60 * 1000;
      var type = null;

      if (self.selectedManageable.type === MANAGEABLE_TYPES.GROUP)
        type = MANAGEABLE_TYPES.GROUP;
      else
        type = MANAGEABLE_TYPES.DEVICE;

      // Add begin time to begin date
      self.itemSchedule.schedule.beginDate.setHours(self.itemSchedule.schedule.beginTime.getHours());
      self.itemSchedule.schedule.beginDate.setMinutes(self.itemSchedule.schedule.beginTime.getMinutes());

      var schedule = {
        beginDate: self.itemSchedule.schedule.beginDate,
        endDate: self.itemSchedule.schedule.endDate,
        duration: duration,
        recurrent: self.itemSchedule.schedule.recurrent,
        preset: self.itemSchedule.schedule.preset
      };

      if (validateSchedule(schedule)) {
        ManageFactory.addSchedule(self.selectedManageable.id, schedule, type).then(function() {
          $scope.$emit('setAlert', 'success', $filter('translate')('MANAGE.MANAGEABLE.ADD_SCHEDULE_SUCCESS'), 4000);
        }, function(error) {
          $scope.$emit('setAlert', 'danger', $filter('translate')('MANAGE.MANAGEABLE.ADD_SCHEDULE_ERROR', null, {
            code: error.code
          }), 4000);
        });
      }
    };

    /**
     * Validates the end date regarding the begin date.
     * End date should not be inferior to begin date.
     *
     * @method validateEndDate
     */
    self.validateEndDate = function() {
      if (self.itemSchedule.schedule.beginDate > self.itemSchedule.schedule.endDate)
        self.itemSchedule.schedule.endDate = new Date(self.itemSchedule.schedule.beginDate.getTime());
    };

    /**
     * Starts a new recording session on the selected manageable.
     *
     * @method startRecord
     */
    self.startRecord = function() {
      var ids = [];

      if (self.selectedManageable.type === MANAGEABLE_TYPES.GROUP) {

        // Manageable is a group
        // Start recording on its available devices
        self.selectedManageable.devices.forEach(function(device) {
          if (device.status !== DEVICE_STATUS.STARTING &&
              device.status !== DEVICE_STATUS.STOPPING &&
              !device.inputs.error)
            ids.push(device.id);
        });

      } else
        ids.push(self.selectedManageable.id);

      // Start record
      var preset = (self.itemSchedule.schedule.preset) ? self.itemSchedule.schedule.preset : null;
      ManageFactory.startRecord(ids, preset).catch(function(errors) {
        displayErrors(errors, 'MANAGE.DEVICE.START_RECORD_ERROR');
      });
    };

    /**
     * Stops recording session on the selected manageable.
     *
     * @method startRecord
     */
    self.stopRecord = function() {
      var ids = [];

      if (self.selectedManageable.type === MANAGEABLE_TYPES.GROUP) {

        // Item is a group
        // Stop recording its started devices
        self.selectedManageable.devices.forEach(function(device) {
          if (device.status === DEVICE_STATUS.STARTED)
            ids.push(device.id);
        });

      } else
        ids.push(self.selectedManageable.id);

      // Stop record
      ManageFactory.stopRecord(ids).catch(function(errors) {
        displayErrors(errors, 'MANAGE.DEVICE.STOP_RECORD_ERROR');
      });
    };

    /**
     * Creates a new tag on the recording session of the selected manageable.
     *
     * @method startRecord
     */
    self.tagRecord = function() {
      var ids = [];

      if (self.selectedManageable.type === MANAGEABLE_TYPES.GROUP) {

        // Item is a group
        // Stop recording its started devices
        self.selectedManageable.devices.forEach(function(device) {
          if (device.status === DEVICE_STATUS.STARTED)
            ids.push(device.id);
        });

      } else
        ids.push(self.selectedManageable.id);

      // Tag record
      ManageFactory.tagRecord(ids).catch(function(errors) {
        displayErrors(errors, 'MANAGE.DEVICE.INDEX_RECORD_ERROR');
      });
    };

    /**
     * Gets selected manageable's preset's name.
     *
     * @method getPresetName
     * @param {String} id The preset id
     * @return {String|Null} The preset name or null if not found
     */
    self.getPresetName = function(id) {
      if (id) {
        var preset = ManageableFactory.getPreset(self.selectedManageable, id);

        if (preset)
          return preset.name;
      }

      return null;
    };

    /**
     * Resets the action form.
     *
     * @method resetActionForm
     */
    self.resetActionForm = function() {
      var beginTimeDate = new Date();
      var durationDate = new Date();
      beginTimeDate.setHours(0);
      beginTimeDate.setMinutes(0);
      beginTimeDate.setSeconds(0);
      durationDate.setHours(0);
      durationDate.setMinutes(1);
      durationDate.setSeconds(0);
      self.itemSchedule = {
        schedule: {
          beginTime: beginTimeDate,
          durationDate: durationDate
        }
      };

      if ($scope.actionForm) {
        $scope.actionForm.$setPristine();
        $scope.actionForm.$setUntouched();
      }

      if (self.selectedManageable && self.selectedManageable.presets && self.selectedManageable.presets[0]) {
        var preset = self.selectedManageable.presets[0].id;
        self.itemSchedule.schedule.preset = preset;
        self.validatePreset(preset);
      }
    };

    /**
     * Removes a schedule from selected manageable.
     *
     * @method removeSchedule
     * @private
     * @param {String} scheduleId The schedule id
     */
    function removeSchedule(scheduleId) {
      var schedule = null;

      // Find schedule
      for (var i = 0; i < self.selectedManageable.schedules.length; i++) {
        if (self.selectedManageable.schedules[i].id === scheduleId) {
          schedule = self.selectedManageable.schedules[i];
          break;
        }
      }

      var beginDate = new Date(schedule.beginDate);
      var endDate = new Date(beginDate.getTime() + schedule.duration);
      var beginTime = beginDate.getHours() + ':' + beginDate.getMinutes();
      var endTime = endDate.getHours() + ':' + endDate.getMinutes();
      var now = new Date();
      var nowTime = now.getHours() + ':' + now.getMinutes();
      var type = null;

      if (self.selectedManageable.type === MANAGEABLE_TYPES.GROUP)
        type = MANAGEABLE_TYPES.GROUP;
      else
        type = MANAGEABLE_TYPES.DEVICE;

      if ((beginDate <= now && endDate >= now) ||
         (schedule.recurrent && beginTime <= nowTime && endTime >= nowTime && beginDate <= now)
      ) {

        // Schedule in progress
        $scope.$emit('setAlert', 'danger', $filter('translate')('MANAGE.MANAGEABLE.SCHEDULE_IN_PROGRESS_ERROR'), 4000);

      } else {
        ManageFactory.removeSchedule(self.selectedManageable.id, scheduleId, type).then(function() {
          $scope.$emit('setAlert', 'success',
                       $filter('translate')('MANAGE.MANAGEABLE.REMOVE_SCHEDULE_SUCCESS'), 4000);
        }, function(error) {
          $scope.$emit('setAlert', 'danger', $filter('translate')('MANAGE.MANAGEABLE.REMOVE_SCHEDULE_ERROR', null, {
            code: error.code
          }), 4000);
        });
      }
    }

    /**
     * Removes an historic from selected manageable.
     *
     * @method removeHistoric
     * @private
     * @param {String} historicId The historic id
     */
    function removeHistoric(historicId) {
      var type = null;
      if (self.selectedManageable.type === MANAGEABLE_TYPES.GROUP)
        type = MANAGEABLE_TYPES.GROUP;
      else
        type = MANAGEABLE_TYPES.DEVICE;

      ManageFactory.removeHistoric(self.selectedManageable.id, historicId, type).then(function() {
        $scope.$emit('setAlert', 'success', $filter('translate')('MANAGE.MANAGEABLE.REMOVE_HISTORIC_SUCCESS'), 4000);
      }, function(error) {
        $scope.$emit('setAlert', 'danger', $filter('translate')('MANAGE.MANAGEABLE.REMOVE_HISTORIC_ERROR', null, {
          code: error.code
        }), 4000);
      });
    }

    /**
     * Removes the whole history.
     *
     * @method removeHistory
     * @private
     */
    function removeHistory() {
      ManageFactory.removeHistory(self.selectedManageable.id, self.selectedManageable.type).then(function() {
        $scope.$emit('setAlert', 'success', $filter('translate')('MANAGE.MANAGEABLE.REMOVE_HISTORY_SUCCESS'), 4000);
      }, function(error) {
        $scope.$emit('setAlert', 'danger', $filter('translate')('MANAGE.MANAGEABLE.REMOVE_HISTORY_ERROR', null, {
          code: error.code
        }), 4000);
      });
    }

    /**
     * Removes a device.
     *
     * @method removeDevice
     * @private
     * @param {String} id The id of the device to remove
     */
    function removeDevice(id) {
      ManageFactory.remove(id, MANAGEABLE_TYPES.DEVICE).then(function() {
        $scope.$emit('setAlert', 'success', $filter('translate')('MANAGE.DEVICE.REMOVE_SUCCESS'), 4000);
        $rootScope.$broadcast('manageable.closeDetails');
      }, function(error) {
        $scope.$emit('setAlert', 'danger', $filter('translate')('MANAGE.DEVICE.REMOVE_ERROR', null, {
          code: error.code
        }), 4000);
      });
    }

    /**
     * Opens a modal to remove something.
     *
     * @method openRemoveModal
     * @param {String} id The id of the object to remove
     * @param {String} action The type of action to perform
     */
    self.openRemoveModal = function(id, action) {
      var modalInstance = $uibModal.open({
        templateUrl: 'removeModal.html',
        controller: ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
          $scope.ok = function() {
            $uibModalInstance.close(true);
          };

          $scope.cancel = function() {
            $uibModalInstance.dismiss('cancel');
          };
        }]
      });

      modalInstance.result.then(function() {
        switch (action) {
          case 'REMOVE_DEVICE':
            removeDevice(id);
            break;
          case 'REMOVE_SCHEDULE':
            removeSchedule(id);
            break;
          case 'REMOVE_HISTORY':
            removeHistoric(id);
            break;
          case 'PURGE_HISTORY':
            removeHistory();
            break;
          default:
            break;
        }
      }, function() {
        // Do nothing
      });
    };

    /**
     * Validates the selected manageable's inputs regarding the given preset id.
     *
     * It is not possible to start a recording session if the inputs of the
     * selected manageable does not correspond to the preset configuration.
     * e.g. It is not possible to start a recording session with slides extraction
     * without a desktop input.
     *
     * @method validatePreset
     * @param {String} presetId The id of the preset
     */
    self.validatePreset = function(presetId) {
      var model = self.selectedManageable.type === MANAGEABLE_TYPES.DEVICE ? DeviceFactory : GroupFactory;
      model.validatePreset(self.selectedManageable.id, presetId);
    };

    // Listen event to load the selected manageable details
    $scope.$on('manageable.load', function(event, itemId, isGroup) {
      if (self.selectedManageable && self.selectedManageable.id === itemId) {
        self.selectedManageable.isSelected = true;
        return;
      }

      // Get the new selected manageable
      self.selectedManageable = isGroup ? GroupFactory.getGroup(itemId) : DeviceFactory.getDevice(itemId);

      // Unselect all manageables
      GroupFactory.setGroupsProperty('isSelected', false);
      DeviceFactory.setDevicesProperty('isSelected', false);

      // Select the new manageable
      self.selectedManageable.isSelected = true;

      // Reset action form
      self.resetActionForm();

    });

    // Listen event to close manageable details window
    $scope.$on('manageable.closeDetails', function(event) {
      self.closeDetail();
    });

    // Listen event to go to the previous page
    $scope.$on('back', function(event) {
      $scope.back();
    });

    // Watch for devices' changes
    $scope.$watch('vm.selectedManageable.devices', function() {
      if (self.selectedManageable && self.selectedManageable.devices)
        self.validatePreset(self.itemSchedule.schedule.preset);
    }, true);

    // Watch for preset changes
    $scope.$watch('vm.selectedManageable.presets', function() {
      if (self.selectedManageable && self.selectedManageable.presets && self.selectedManageable.presets[0]) {
        var preset = self.selectedManageable.presets[0].id;
        self.itemSchedule.schedule.preset = preset;
        self.validatePreset(preset);
      }
    });

    // Listen to window resize event to update height of elements
    window.addEventListener('resize', function() {
      actionEl.setAttribute('style', 'height:' + parseInt(window.innerHeight - 100) + 'px');
      detailEl.setAttribute('style', 'height:' + parseInt(window.innerHeight - 100) + 'px');
      historyEl.setAttribute('style', 'height:' + parseInt(window.innerHeight - 100) + 'px');
    });

    self.resetActionForm();
  }

  app.controller('ManageManageableDetailController', ManageableDetailController);
  ManageableDetailController.$inject = [
    '$scope',
    '$filter',
    '$uibModal',
    '$timeout',
    '$rootScope',
    'ManageFactory',
    'ManageGroupFactory',
    'ManageDeviceFactory',
    'ManageManageableFactory',
    'entityService',
    'MANAGE_NAME',
    'MANAGE_DEVICE_STATUS',
    'MANAGE_MANAGEABLE_TYPES'
  ];

})(angular.module('ov.manage'));