Name

sn_mab_api.UpdateConfigurationService

Description

No description available

Script

var UpdateConfigurationService = Class.create();

UpdateConfigurationService.prototype = {

  initialize: function () {
      this.errorHandler = new sn_mab_api.ErrorHandler();
      this.mobileDAOCache = new sn_mab_api.MobileDAOCache();
      this.validationHandler = new sn_mab_api.ValidationHandler();
      this.recordValidator = new sn_mab_api.RecordValidator();
      this.configSortingService = new sn_mab_api.ConfigSortingService();
      this.fieldEncryptor = new sn_mab_api.MobileFieldEncryptor();
      this.operations = ['inserts', 'updates', 'deletes'];
  },

  /**
   *
   * @param payload {{}}
   * @return {{}}
   */
  processRecords: function (payload) {
      var idMap = {};
      this.validateAllTables(payload);

      for (var i = 0; i < this.operations.length; i++) {
          var operation = this.operations[i];
          if (operation === 'deletes') {
              this.processDeletes(this.configSortingService.sortNodes(payload[operation]), idMap);
          } else {
              this.preProcessInsertsAndUpdates(payload[operation]);
              this.processInsertsAndUpdates(this.configSortingService.sortNodes(payload[operation]), idMap);
          }
          if (this.containsError(idMap)) {
              return idMap;
          }
      }

      return idMap;
  },

  preProcessInsertsAndUpdates: function(records) {
      // encrypt any password2 fields before field objects are flattened
      this.encryptAnyPassword2Fields(records);
      // flatten all records to avoid issues with sorting and id replacements
      this.flattenRecords(records);
  },

  processInsertsAndUpdates: function (sortedRecords, idMap) {
      for (var i = 0; i < sortedRecords.length; i++) {
          var record = sortedRecords[i];
          var table = record.tableName;

          var mobileAppBuilderDao = this.mobileDAOCache.getDAO(this._snakeCaseString(table));

          this.replaceReference(record.fields, idMap);

          var response = this.insertOrUpdate(record.sysId, record.fields, mobileAppBuilderDao);

          if (!response) return;

          idMap[record.sysId] = response;
      }
  },

  /**
   *
   * @param sysId {String}
   * @param record {{}}
   * @param mobileAppBuilderDao {MobileAppBuilderDAO}
   * @return {{sys_id: null, message: string, operation: string, table: MobileAppBuilderDAO.table, is_success: boolean}}
   */
  insertOrUpdate: function (sysId, record, mobileAppBuilderDao) {
      var operation = this.isGeneratedId(sysId) ? 'insert' : 'update';

      if (operation === 'update') {
          record.sys_id = sysId;
      }

      if (record.sys_class_name) record.sys_class_name = this._snakeCaseString(record.sys_class_name);

      var invalidReferences = this.getInvalidReferences(record);

      if (invalidReferences.length > 0) {
  		this.errorHandler.throwBadRequestError('invalid reference from field(s) ' + invalidReferences.join(','));
      }

      try {
          var realSysId = mobileAppBuilderDao.saveRecord(record);
      } catch (error) {
  		this.errorHandler.throwBadRequestError('unable to ' + operation + ' record into table ' + mobileAppBuilderDao.table + ' - ' + error.message);
      }

      // currently this condition might not ever be met. we need to update the dao to include lastErrorMessage
      if (!realSysId) {
  		this.errorHandler.throwBadRequestError('unable to ' + operation + ' record: ' + realSysId + ' into table ' + mobileAppBuilderDao.table);
      }

      // if we got to this point the record is assumed to have saved
      return {
          sys_id: realSysId,
          is_success: true,
          message: 'successfully ' + operation + ' record: ' + realSysId + ' into table ' + mobileAppBuilderDao.table,
          operation: operation,
          table: mobileAppBuilderDao.table
      };
  },

  encryptPassword2Fields: function(record, tableName) {
      for (var fieldName in record) {
          var field = record[fieldName];
          if (typeof field === 'object' && 'type' in field) {
              if (field.type === 'password2')
                  record[fieldName] = this.fieldEncryptor.encrypt(this._snakeCaseString(tableName), fieldName, field.value);
          } else if (typeof field === 'string' && ['map_provider_app_secret', 'location_provider_app_secret'].indexOf(fieldName) > -1)  {
              record[fieldName] = this.fieldEncryptor.encrypt(this._snakeCaseString(tableName), fieldName, field);
          }
      }
  },

  encryptAnyPassword2Fields: function (records) {
      for (var tableName in records) {
          var recordsPerTable = records[tableName];
          for (var sysId in recordsPerTable) {
              this.encryptPassword2Fields(recordsPerTable[sysId], tableName);
          }
      }
  },

  flattenRecords: function (records) {
      for (var tableName in records) {
          var recordsPerTable = records[tableName];

          for (var sysId in recordsPerTable) {
              var record = recordsPerTable[sysId];
              recordsPerTable[sysId] = this.flattenRecord(record);
          }
      }
  },

  flattenRecord: function (record) {
      var flattenedRecord = {};

      for (var field in record) {
          var currValue = record[field];
          if (typeof currValue === 'object') {
              flattenedRecord[field] = currValue.value ? currValue.value : null;
          } else {
              flattenedRecord[field] = currValue;
          }
      }

      return flattenedRecord;
  },

  /**
   *
   * @param payload {{}}
   */
  validateAllTables: function (payload) {
      var operations = ['inserts', 'updates', 'deletes'];

      operations.forEach(function (operation) {
          var allRecords = payload[operation];

          if (!allRecords) return;

          Object.keys(allRecords).forEach(function (table) {
              if (!this.validationHandler.isValidTable(this._snakeCaseString(table))) {
                  this.errorHandler.throwBadRequestError("invalid table: " + table);
              }
          }.bind(this));
      }.bind(this));
  },

  /**
   *
   * @param record {{}}
   * @param idMap {{}}
   */
  replaceReference: function (record, idMap) {
      for (var field in record) {
          if (this.hasGeneratedId(record[field])) {
              var generatedIds = this.extractGeneratedIds(record[field]);
              generatedIds.forEach(function(generatedId) {
                  if (idMap[generatedId] && idMap[generatedId].sys_id) {
                      record[field] = record[field].replace(generatedId, idMap[generatedId].sys_id);
                  }                        
              });
          }
      }
  },

  /**
   * @param sortedRecords {[]}
   * @param idMap
   */
  processDeletes: function (sortedRecords, idMap) {
      for (var i = 0; i < sortedRecords.length; i++) {
          var record = sortedRecords[i];
          var table = record.tableName;

          var mobileAppBuilderDao = this.mobileDAOCache.getDAO(this._snakeCaseString(table));

          var response = this.deleteRecord(record.sysId, mobileAppBuilderDao);

          if (!response) return;

          idMap[record.sysId] = response;
      }
  },

  deleteRecord: function (sysId, mobileAppBuilderDao) {
      try {
          var isDeleted = mobileAppBuilderDao.deleteRecord(sysId);
      } catch (error) {
  		this.errorHandler.throwBadRequestError('unable to delete record from table ' + mobileAppBuilderDao.table + ' - ' + error.message);
      }

      if (!isDeleted) {
  		this.errorHandler.throwBadRequestError('unable to delete record: ' + sysId + ' from table ' + mobileAppBuilderDao.table);
      }

      return {
          is_success: true,
          sys_id: sysId,
          operation: 'delete',
          table: mobileAppBuilderDao.table,
          message: 'successfully deleted record: ' + sysId + ' from table ' + mobileAppBuilderDao.table
      };
  },


  /**
   *
   * @param idMap {{}}
   * @return {boolean}
   */
  containsError: function (idMap) {
      for (var sysId in idMap) {
          if (!idMap[sysId].is_success) {
              return true;
          }
      }

      return false;
  },

  /**
   *
   * @param value {String}
   * @return {boolean}
   */
  isGeneratedId: function (value) {
      return this.validationHandler.isGeneratedId(value);
  },

  /**
   *
   * @param value {String}
   * @return {boolean}
   */
  hasGeneratedId: function (value) {
      return this.validationHandler.hasGeneratedId(value);
  },

  /**
   * 
   * @param value {string}
   * @return {[]}
   */
  extractGeneratedIds: function (value) {
      return this.validationHandler.extractGeneratedIds(value);
  },

  /**
   * Checks to see if a record contains a reference the has not been replaced by a valid sysId
   * @param record {{}}
   * @return {[]}
   */
  getInvalidReferences: function (record) {
      var invalidFields = [];
      Object.keys(record).forEach(function (field) {
          if (this.isGeneratedId(record[field])) {
              invalidFields.push(field);
          }
      }.bind(this));

      return invalidFields;
  },

  // todo: move into a utility service
  _snakeCaseString: function (string) {
      return string.replace(/M2M/g, 'M2m').replace(/[A-Z]/g, function (capital) {
          return '_' + capital.toLowerCase();
      });
  },

  type: 'UpdateConfigurationService'
};

Sys ID

1e96c16db77220108223e126de11a906

Offical Documentation

Official Docs: