<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import uuid from 'uuid';
import { FormattedMessage } from 'react-intl';

import {
  cloneDeep,
  find,
  omit,
  differenceBy,
  get,
} from 'lodash';

import { LoadingView } from '@folio/stripes/components';

import { eachPromise, getRecordObject } from '../../components/util';

import UserForm from './UserForm';
import { toUserAddresses, getFormAddressList } from '../../components/data/converters/address';
import contactTypes from '../../components/data/static/contactTypes';
import { deliveryFulfillmentValues } from '../../constants';

function resourcesLoaded(obj, exceptions = []) {
  for (const resource in obj) {
    if (!exceptions.includes(resource)) {
      if (Object.prototype.hasOwnProperty.call(obj, resource)) {
        if (obj[resource] === null) {
          return false;
        }
        if (typeof obj[resource] === 'object') {
          if (Object.prototype.hasOwnProperty.call(obj[resource], 'isPending')) {
            if (obj[resource].isPending) {
              return false;
            }
          }
        }
      }
    }
  }
  return true;
}

class UserEdit extends React.Component {
  static propTypes = {
    stripes: PropTypes.object,
    resources: PropTypes.object,
    history: PropTypes.object,
    location: PropTypes.object,
    match: PropTypes.object,
    updateProxies: PropTypes.func,
    updateSponsors: PropTypes.func,
    updateServicePoints: PropTypes.func,
    getUserServicePoints: PropTypes.func,
    getPreferredServicePoint: PropTypes.func,
    mutator: PropTypes.object,
    getProxies: PropTypes.func,
    getSponsors: PropTypes.func,
  }

  getUser() {
    const { resources, match: { params: { id } } } = this.props;
    const selUser = (resources.selUser || {}).records || [];

    if (selUser.length === 0 || !id) return null;
    // Logging below shows this DOES sometimes find the wrong record. But why?
    // console.log(`getUser: found ${selUser.length} users, id '${selUser[0].id}' ${selUser[0].id === id ? '==' : '!='} '${id}'`);
    return selUser.find(u => u.id === id);
  }

  getUserFormValues() {
    const {
      getProxies,
      getSponsors,
      getPreferredServicePoint,
      getUserServicePoints,
      resources,
      match,
    } = this.props;

    const initialFormValues = {
      active: true,
      personal: {
        addresses: [],
        preferredContactTypeId: (find(contactTypes, { 'name': 'email' }) || {}).id,
      },
      requestPreferences: {
        holdShelf: true,
        delivery: false,
        defaultServicePointId: null,
        defaultDeliveryAddressTypeId: null,
      }
    };

    if (!match.params.id) return initialFormValues;

    const user = this.getUser();
    const userFormValues = cloneDeep(user);
    const formRecordValues = getRecordObject(
      resources,
      'permissions',
    );

    if (!userFormValues.personal) {
      userFormValues.personal = {};
    }

    userFormValues.personal.addresses = getFormAddressList(get(user, 'personal.addresses', []));

    return {
      ...userFormValues,
      ...formRecordValues,
      preferredServicePoint: getPreferredServicePoint(),
      proxies: getProxies(),
      sponsors: getSponsors(),
      servicePoints: getUserServicePoints(),
      requestPreferences: {
        ...initialFormValues.requestPreferences,
        ...get(this.props.resources, 'requestPreferences.records[0].requestPreferences[0]', {})
      },
    };
  }

  getUserFormData() {
    const {
      resources,
    } = this.props;
    const formData = getRecordObject(
      resources,
      'patronGroups',
      'addressTypes',
      'servicePoints',
    );

    return formData;
  }

  createRequestPreferences = (requestPreferencesData, userId) => {
    const { mutator } = this.props;
    const payload = {
      userId,
      fulfillment: deliveryFulfillmentValues.HOLD_SHELF,
      ...requestPreferencesData,
    };

    mutator.requestPreferences.POST(payload);
  }

  updateRequestPreferences = (requestPreferences) => {
    const {
      match,
      mutator,
    } = this.props;

    const payload = {
      userId: match.params.id,
      holdShelf: true,
      fulfillment: deliveryFulfillmentValues.HOLD_SHELF,
      ...requestPreferences,
    };

    mutator.requestPreferences.PUT(payload);
  }

  create = ({ requestPreferences, ...userFormData }) => {
    const { mutator, history, location: { search } } = this.props;
    const userData = cloneDeep(userFormData);
    const user = { ...userData, id: uuid() };
    user.personal.addresses = toUserAddresses(user.personal.addresses);
    user.personal.email = user.personal.email.trim();

    mutator.records.POST(user)
      .then(() => {
        this.createRequestPreferences(requestPreferences, user.id);
        return mutator.perms.POST({ userId: user.id, permissions: [] });
      })
      .then(() => {
        history.push(`/users/preview/${user.id}${search}`);
      });
  }

  formatCustomFieldsPayload(customFields) {
    const copiedCustomFields = { ...customFields };

    Object.keys(copiedCustomFields).forEach(customFieldId => {
      if (!copiedCustomFields[customFieldId]) {
        delete copiedCustomFields[customFieldId];
      }
    });

    return copiedCustomFields;
  }

  update({ requestPreferences, ...userFormData }) {
    const {
      updateProxies,
      updateSponsors,
      updateServicePoints,
      mutator,
      history,
      resources,
      match: { params },
      location: {
        state,
        search,
      },
      stripes,
    } = this.props;

    const user = cloneDeep(userFormData);
    const prevUser = resources?.selUser?.records?.[0] ?? {};

    if (get(resources, 'requestPreferences.records[0].totalRecords')) {
      this.updateRequestPreferences(requestPreferences);
    } else {
      this.createRequestPreferences(requestPreferences, user.id);
    }

    user.personal.addresses = toUserAddresses(user.personal.addresses); // eslint-disable-line no-param-reassign
    user.personal.email = user.personal.email.trim();

    const { proxies, sponsors, permissions, servicePoints, preferredServicePoint } = user;

    if (stripes.hasPerm('proxiesfor.item.put,proxiesfor.item.post')) {
      if (proxies) updateProxies(proxies);
      if (sponsors) updateSponsors(sponsors);
    }

    if (permissions) {
      this.updatePermissions(permissions);
    }

    if (servicePoints && stripes.hasPerm('inventory-storage.service-points-users.item.post,inventory-storage.service-points-users.item.put')) {
      updateServicePoints(servicePoints, preferredServicePoint);
    }

    const data = omit(user, ['creds', 'proxies', 'sponsors', 'permissions', 'servicePoints', 'preferredServicePoint']);
    const today = moment().endOf('day');
    const curActive = user.active;
    const prevActive = prevUser.active;

    const formattedCustomFieldsPayload = this.formatCustomFieldsPayload(data.customFields);

    data.customFields = formattedCustomFieldsPayload;

    // if active has been changed manually on the form
    // or if the expirationDate has been removed
    if (curActive !== prevActive || !user.expirationDate) {
      data.active = curActive;
    } else {
      data.active = (moment(user.expirationDate).endOf('day').isSameOrAfter(today));
    }

    mutator.selUser.PUT(data).then(() => {
      history.push({
        pathname: params.id ? `/users/preview/${params.id}` : '/users',
        search,
        state,
      });
    });
  }

  async updatePermissions(perms) {
    const mutator = this.props.mutator.permissions;
    const prevPerms = (this.props.resources.permissions || {}).records || [];
    const removedPerms = differenceBy(prevPerms, perms, 'id');
    const addedPerms = differenceBy(perms, prevPerms, 'id');

    await eachPromise(removedPerms, mutator.DELETE);
    await eachPromise(addedPerms, mutator.POST);
  }

  render() {
    const {
      history,
      resources,
      location,
      match: { params },
    } = this.props;

    if (!resourcesLoaded(resources, ['uniquenessValidator'])) {
      return (
        <LoadingView
          data-test-form-page
          paneTitle={params.id ?
            <FormattedMessage id="ui-users.edit" /> :
            <FormattedMessage id="ui-users.crud.createUser" />
          }
          defaultWidth="100%"
        />
      );
    }

    // data is information that the form needs, mostly to populate options lists

    // check to see if we are editing an existing user, and if the data on that user has finished loading.
    if (!this.getUser() && this.props.match.params.id) {
      return null;
    }
    const formData = this.getUserFormData();
    const onSubmit = params.id ? (record) => this.update(record) : (record) => this.create(record);

    return (
      <UserForm
        formData={formData}
        initialValues={this.getUserFormValues()} // values are strictly values...if we're editing (id param present) pull in existing values.
        onSubmit={onSubmit}
        onCancel={() => {
          history.push({
            pathname: params.id ? `/users/preview/${params.id}` : '/users',
            state: location.state,
          });
        }}
        uniquenessValidator={this.props.mutator.uniquenessValidator}
        match={this.props.match}
        location={location}
        history={history}
      />
    );
  }
}

export default UserEdit;
<commit_msg>wrapping checks into loading block<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import uuid from 'uuid';
import { FormattedMessage } from 'react-intl';

import {
  cloneDeep,
  find,
  omit,
  differenceBy,
  get,
} from 'lodash';

import { LoadingView } from '@folio/stripes/components';

import { eachPromise, getRecordObject } from '../../components/util';

import UserForm from './UserForm';
import { toUserAddresses, getFormAddressList } from '../../components/data/converters/address';
import contactTypes from '../../components/data/static/contactTypes';
import { deliveryFulfillmentValues } from '../../constants';

function resourcesLoaded(obj, exceptions = []) {
  for (const resource in obj) {
    if (!exceptions.includes(resource)) {
      if (Object.prototype.hasOwnProperty.call(obj, resource)) {
        if (obj[resource] === null) {
          return false;
        }
        if (typeof obj[resource] === 'object') {
          if (Object.prototype.hasOwnProperty.call(obj[resource], 'isPending')) {
            if (obj[resource].isPending) {
              return false;
            }
          }
        }
      }
    }
  }
  return true;
}

class UserEdit extends React.Component {
  static propTypes = {
    stripes: PropTypes.object,
    resources: PropTypes.object,
    history: PropTypes.object,
    location: PropTypes.object,
    match: PropTypes.object,
    updateProxies: PropTypes.func,
    updateSponsors: PropTypes.func,
    updateServicePoints: PropTypes.func,
    getUserServicePoints: PropTypes.func,
    getPreferredServicePoint: PropTypes.func,
    mutator: PropTypes.object,
    getProxies: PropTypes.func,
    getSponsors: PropTypes.func,
  }

  getUser() {
    const { resources, match: { params: { id } } } = this.props;
    const selUser = (resources.selUser || {}).records || [];

    if (selUser.length === 0 || !id) return null;
    // Logging below shows this DOES sometimes find the wrong record. But why?
    // console.log(`getUser: found ${selUser.length} users, id '${selUser[0].id}' ${selUser[0].id === id ? '==' : '!='} '${id}'`);
    return selUser.find(u => u.id === id);
  }

  getUserFormValues() {
    const {
      getProxies,
      getSponsors,
      getPreferredServicePoint,
      getUserServicePoints,
      resources,
      match,
    } = this.props;

    const initialFormValues = {
      active: true,
      personal: {
        addresses: [],
        preferredContactTypeId: (find(contactTypes, { 'name': 'email' }) || {}).id,
      },
      requestPreferences: {
        holdShelf: true,
        delivery: false,
        defaultServicePointId: null,
        defaultDeliveryAddressTypeId: null,
      }
    };

    if (!match.params.id) return initialFormValues;

    const user = this.getUser();
    const userFormValues = cloneDeep(user);
    const formRecordValues = getRecordObject(
      resources,
      'permissions',
    );

    if (!userFormValues.personal) {
      userFormValues.personal = {};
    }

    userFormValues.personal.addresses = getFormAddressList(get(user, 'personal.addresses', []));

    return {
      ...userFormValues,
      ...formRecordValues,
      preferredServicePoint: getPreferredServicePoint(),
      proxies: getProxies(),
      sponsors: getSponsors(),
      servicePoints: getUserServicePoints(),
      requestPreferences: {
        ...initialFormValues.requestPreferences,
        ...get(this.props.resources, 'requestPreferences.records[0].requestPreferences[0]', {})
      },
    };
  }

  getUserFormData() {
    const {
      resources,
    } = this.props;
    const formData = getRecordObject(
      resources,
      'patronGroups',
      'addressTypes',
      'servicePoints',
    );

    return formData;
  }

  createRequestPreferences = (requestPreferencesData, userId) => {
    const { mutator } = this.props;
    const payload = {
      userId,
      fulfillment: deliveryFulfillmentValues.HOLD_SHELF,
      ...requestPreferencesData,
    };

    mutator.requestPreferences.POST(payload);
  }

  updateRequestPreferences = (requestPreferences) => {
    const {
      match,
      mutator,
    } = this.props;

    const payload = {
      userId: match.params.id,
      holdShelf: true,
      fulfillment: deliveryFulfillmentValues.HOLD_SHELF,
      ...requestPreferences,
    };

    mutator.requestPreferences.PUT(payload);
  }

  create = ({ requestPreferences, ...userFormData }) => {
    const { mutator, history, location: { search } } = this.props;
    const userData = cloneDeep(userFormData);
    const user = { ...userData, id: uuid() };
    user.personal.addresses = toUserAddresses(user.personal.addresses);
    user.personal.email = user.personal.email.trim();

    mutator.records.POST(user)
      .then(() => {
        this.createRequestPreferences(requestPreferences, user.id);
        return mutator.perms.POST({ userId: user.id, permissions: [] });
      })
      .then(() => {
        history.push(`/users/preview/${user.id}${search}`);
      });
  }

  formatCustomFieldsPayload(customFields) {
    const copiedCustomFields = { ...customFields };

    Object.keys(copiedCustomFields).forEach(customFieldId => {
      if (!copiedCustomFields[customFieldId]) {
        delete copiedCustomFields[customFieldId];
      }
    });

    return copiedCustomFields;
  }

  update({ requestPreferences, ...userFormData }) {
    const {
      updateProxies,
      updateSponsors,
      updateServicePoints,
      mutator,
      history,
      resources,
      match: { params },
      location: {
        state,
        search,
      },
      stripes,
    } = this.props;

    const user = cloneDeep(userFormData);
    const prevUser = resources?.selUser?.records?.[0] ?? {};

    if (get(resources, 'requestPreferences.records[0].totalRecords')) {
      this.updateRequestPreferences(requestPreferences);
    } else {
      this.createRequestPreferences(requestPreferences, user.id);
    }

    user.personal.addresses = toUserAddresses(user.personal.addresses); // eslint-disable-line no-param-reassign
    user.personal.email = user.personal.email.trim();

    const { proxies, sponsors, permissions, servicePoints, preferredServicePoint } = user;

    if (stripes.hasPerm('proxiesfor.item.put,proxiesfor.item.post')) {
      if (proxies) updateProxies(proxies);
      if (sponsors) updateSponsors(sponsors);
    }

    if (permissions) {
      this.updatePermissions(permissions);
    }

    if (servicePoints && stripes.hasPerm('inventory-storage.service-points-users.item.post,inventory-storage.service-points-users.item.put')) {
      updateServicePoints(servicePoints, preferredServicePoint);
    }

    const data = omit(user, ['creds', 'proxies', 'sponsors', 'permissions', 'servicePoints', 'preferredServicePoint']);
    const today = moment().endOf('day');
    const curActive = user.active;
    const prevActive = prevUser.active;

    const formattedCustomFieldsPayload = this.formatCustomFieldsPayload(data.customFields);

    data.customFields = formattedCustomFieldsPayload;

    // if active has been changed manually on the form
    // or if the expirationDate has been removed
    if (curActive !== prevActive || !user.expirationDate) {
      data.active = curActive;
    } else {
      data.active = (moment(user.expirationDate).endOf('day').isSameOrAfter(today));
    }

    mutator.selUser.PUT(data).then(() => {
      history.push({
        pathname: params.id ? `/users/preview/${params.id}` : '/users',
        search,
        state,
      });
    });
  }

  async updatePermissions(perms) {
    const mutator = this.props.mutator.permissions;
    const prevPerms = (this.props.resources.permissions || {}).records || [];
    const removedPerms = differenceBy(prevPerms, perms, 'id');
    const addedPerms = differenceBy(perms, prevPerms, 'id');

    await eachPromise(removedPerms, mutator.DELETE);
    await eachPromise(addedPerms, mutator.POST);
  }

  render() {
    const {
      history,
      resources,
      location,
      match: { params },
    } = this.props;

    if (!resourcesLoaded(resources, ['uniquenessValidator']) || (!this.getUser() && this.props.match.params.id)) {
      return (
        <LoadingView
          data-test-form-page
          paneTitle={params.id ?
            <FormattedMessage id="ui-users.edit" /> :
            <FormattedMessage id="ui-users.crud.createUser" />
          }
          defaultWidth="100%"
        />
      );
    }

    // data is information that the form needs, mostly to populate options lists
    const formData = this.getUserFormData();
    const onSubmit = params.id ? (record) => this.update(record) : (record) => this.create(record);

    return (
      <UserForm
        formData={formData}
        initialValues={this.getUserFormValues()} // values are strictly values...if we're editing (id param present) pull in existing values.
        onSubmit={onSubmit}
        onCancel={() => {
          history.push({
            pathname: params.id ? `/users/preview/${params.id}` : '/users',
            state: location.state,
          });
        }}
        uniquenessValidator={this.props.mutator.uniquenessValidator}
        match={this.props.match}
        location={location}
        history={history}
      />
    );
  }
}

export default UserEdit;
<|endoftext|>


<commit_before>'use strict';

var validator = require('./utils/validator-extras').validator
  , extendModelValidations = require('./utils/validator-extras').extendModelValidations
  , Utils = require('./utils')
  , sequelizeError = require('./errors')
  , Promise = require('./promise')
  , DataTypes = require('./data-types')
  , _ = require('lodash');

/**
 * The Main Instance Validator.
 *
 * @param {Instance} modelInstance The model instance.
 * @param {Object} options A dict with options.
 * @constructor
 */
var InstanceValidator = module.exports = function(modelInstance, options) {
  options = options || {};

  if (options.fields && !options.skip) {
    options.skip = Utils._.difference(Object.keys(modelInstance.Model.attributes), options.fields);
  }

  // assign defined and default options
  this.options = Utils._.defaults(options, {
    skip: []
  });

  this.modelInstance = modelInstance;

  /**
   * Exposes a reference to validator.js. This allows you to add custom validations using `validator.extend`
   * @name validator
   */
  this.validator = validator;

  /**
   *  All errors will be stored here from the validations.
   *
   * @type {Array} Will contain keys that correspond to attributes which will
   *   be Arrays of Errors.
   */
  this.errors = [];

  /** @type {boolean} Indicates if validations are in progress */
  this.inProgress = false;

  extendModelValidations(modelInstance);
};

/** @define {string} The error key for arguments as passed by custom validators */
InstanceValidator.RAW_KEY_NAME = '__raw';

/**
 * The main entry point for the Validation module, invoke to start the dance.
 *
 * @return {Promise}
 */
InstanceValidator.prototype.validate = function() {
  if (this.inProgress) {
    throw new Error('Validations already in progress.');
  }
  this.inProgress = true;

  var self = this;
  return Promise.settle([
    self._builtinValidators(),
    self._customValidators()
  ]).then(function() {
    if (self.errors.length) {
      return new sequelizeError.ValidationError(null, self.errors);
    }
  });
};

/**
 * Invoke the Validation sequence:
 *   - Before Validation Model Hooks
 *   - Validation
 *   - After Validation Model Hooks
 *
 * @return {Promise}
 */
InstanceValidator.prototype.hookValidate = function() {
  var self = this;
  return self.modelInstance.Model.runHooks('beforeValidate', self.modelInstance, self.options).then(function() {
    return self.validate().then(function(error) {
      if (error) {
        throw error;
      }
    });
  }).then(function() {
    return self.modelInstance.Model.runHooks('afterValidate', self.modelInstance, self.options);
  }).return(self.modelInstance);
};

/**
 * Will run all the built-in validators.
 *
 * @return {Promise(Array.<Promise.PromiseInspection>)} A promise from .settle().
 * @private
 */
InstanceValidator.prototype._builtinValidators = function() {
  var self = this;

  // promisify all attribute invocations
  var validators = [];
  Utils._.forIn(this.modelInstance.rawAttributes, function(rawAttribute, field) {
    if (self.options.skip.indexOf(field) >= 0) {
      return;
    }

    var value = self.modelInstance.dataValues[field];

    if (!rawAttribute._autoGenerated && !rawAttribute.autoIncrement) {
      // perform validations based on schema
      self._validateSchema(rawAttribute, field, value);
    }

    if (self.modelInstance.validators.hasOwnProperty(field)) {
      validators.push(self._builtinAttrValidate.call(self, value, field));
    }
  });

  return Promise.settle(validators);
};

/**
 * Will run all the custom validators.
 *
 * @return {Promise(Array.<Promise.PromiseInspection>)} A promise from .settle().
 * @private
 */
InstanceValidator.prototype._customValidators = function() {

  var validators = [];
  var self = this;
  Utils._.each(this.modelInstance.$modelOptions.validate, function(validator,
    validatorType) {

    var valprom = self._invokeCustomValidator(validator, validatorType)
      // errors are handled in settling, stub this
      .catch(function() {});

    validators.push(valprom);
  });

  return Promise.settle(validators);
};

/**
 * Validate a single attribute with all the defined built-in validators.
 *
 * @param {*} value Anything.
 * @param {string} field The field name.
 * @return {Promise} A promise, will always resolve,
 *   auto populates error on this.error local object.
 * @private
 */
InstanceValidator.prototype._builtinAttrValidate = function(value, field) {
  var self = this;
  // check if value is null (if null not allowed the Schema pass will capture it)
  if (value === null || typeof value === 'undefined') {
    return Promise.resolve();
  }

  // Promisify each validator
  var validators = [];
  Utils._.forIn(this.modelInstance.validators[field], function(test,
    validatorType) {

    if (['isUrl', 'isURL', 'isEmail'].indexOf(validatorType) !== -1) {
      // Preserve backwards compat. Validator.js now expects the second param to isURL and isEmail to be an object
      if (typeof test === 'object' && test !== null && test.msg) {
        test = {
          msg: test.msg
        };
      } else if (test === true) {
        test = {};
      }
    }

    // Check for custom validator.
    if (typeof test === 'function') {
      return validators.push(self._invokeCustomValidator(test, validatorType, true, value, field));
    }

    var validatorPromise = self._invokeBuiltinValidator(value, test, validatorType, field);
    // errors are handled in settling, stub this
    validatorPromise.catch(function() {});
    validators.push(validatorPromise);
  });

  return Promise.settle(validators).then(this._handleSettledResult.bind(this, field));
};

/**
 * Prepare and invoke a custom validator.
 *
 * @param {Function} validator The custom validator.
 * @param {string} validatorType the custom validator type (name).
 * @param {boolean=} optAttrDefined Set to true if custom validator was defined
 *   from the Attribute
 * @return {Promise} A promise.
 * @private
 */
InstanceValidator.prototype._invokeCustomValidator = Promise.method(function(validator, validatorType, optAttrDefined, optValue, optField) {
  var validatorFunction = null;  // the validation function to call
  var isAsync = false;

  var validatorArity = validator.length;
  // check if validator is async and requires a callback
  var asyncArity = 1;
  var errorKey = validatorType;
  var invokeArgs;
  if (optAttrDefined) {
    asyncArity = 2;
    invokeArgs = optValue;
    errorKey = optField;
  }
  if (validatorArity === asyncArity) {
    isAsync = true;
  }

  if (isAsync) {
    if (optAttrDefined) {
      validatorFunction = Promise.promisify(validator.bind(this.modelInstance, invokeArgs));
    } else {
      validatorFunction = Promise.promisify(validator.bind(this.modelInstance));
    }
    return validatorFunction().catch(this._pushError.bind(this, false, errorKey));
  } else {
    return Promise.try(validator.bind(this.modelInstance, invokeArgs)).catch(this._pushError.bind(this, false, errorKey));
  }
});

/**
 * Prepare and invoke a build-in validator.
 *
 * @param {*} value Anything.
 * @param {*} test The test case.
 * @param {string} validatorType One of known to Sequelize validators.
 * @param {string} field The field that is being validated
 * @return {Object} An object with specific keys to invoke the validator.
 * @private
 */
InstanceValidator.prototype._invokeBuiltinValidator = Promise.method(function(value, test, validatorType, field) {
  // check if Validator knows that kind of validation test
  if (typeof validator[validatorType] !== 'function') {
    throw new Error('Invalid validator function: ' + validatorType);
  }

  // extract extra arguments for the validator
  var validatorArgs = test.args || test;

  if (!Array.isArray(validatorArgs)) {
    if (validatorType === 'isImmutable') {
      validatorArgs = [validatorArgs, field];
    } else if (validatorType === 'isIP') {
      validatorArgs = [];
    } else {
      validatorArgs = [validatorArgs];
    }
  } else {
    validatorArgs = validatorArgs.slice(0);
  }

  if (!validator[validatorType].apply(validator, [value].concat(validatorArgs))) {
  // extract the error msg
    throw test.msg || 'Validation ' + validatorType + ' failed';
  }
});

/**
 * Will validate a single field against its schema definition (isnull).
 *
 * @param {Object} rawAttribute As defined in the Schema.
 * @param {string} field The field name.
 * @param {*} value anything.
 * @private
 */
InstanceValidator.prototype._validateSchema = function(rawAttribute, field, value) {
  var error;

  if (rawAttribute.allowNull === false && ((value === null) || (value === undefined))) {
    error = new sequelizeError.ValidationErrorItem(field + ' cannot be null', 'notNull Violation', field, value);
    this.errors.push(error);
  }

  if (rawAttribute.type === DataTypes.STRING || rawAttribute.type instanceof DataTypes.STRING || rawAttribute.type === DataTypes.TEXT || rawAttribute.type instanceof DataTypes.TEXT) {
    if (Array.isArray(value) || (_.isObject(value) && !value._isSequelizeMethod) && !Buffer.isBuffer(value)) {
      error = new sequelizeError.ValidationErrorItem(field + ' cannot be an array or an object', 'string violation', field, value);
      this.errors.push(error);
    }
  }
};

/**
 * Handles the returned result of a Promise.settle.
 *
 * If errors are found it populates this.error.
 *
 * @param {string} field The attribute name.
 * @param {Array.<Promise.PromiseInspection>} Promise inspection objects.
 * @private
 */
InstanceValidator.prototype._handleSettledResult = function(field, promiseInspections) {
  var self = this;
  promiseInspections.forEach(function(promiseInspection) {
    if (promiseInspection.isRejected()) {
      var rejection = promiseInspection.error();
      self._pushError(true, field, rejection);
    }
  });
};

/**
 * Signs all errors retaining the original.
 *
 * @param {boolean} isBuiltin Determines if error is from builtin validator.
 * @param {string} errorKey The error key to assign on this.errors object.
 * @param {Error|string} rawError The original error.
 * @private
 */
InstanceValidator.prototype._pushError = function(isBuiltin, errorKey, rawError) {
  var message = rawError.message || rawError || 'Validation error';
  var error = new sequelizeError.ValidationErrorItem(message, 'Validation error', errorKey, rawError);
  error[InstanceValidator.RAW_KEY_NAME] = rawError;

  this.errors.push(error);
};
<commit_msg>Enable .validate(options.skip) to skip specific model/custom validators (feature request #4527)<commit_after>'use strict';

var validator = require('./utils/validator-extras').validator
  , extendModelValidations = require('./utils/validator-extras').extendModelValidations
  , Utils = require('./utils')
  , sequelizeError = require('./errors')
  , Promise = require('./promise')
  , DataTypes = require('./data-types')
  , _ = require('lodash');

/**
 * The Main Instance Validator.
 *
 * @param {Instance} modelInstance The model instance.
 * @param {Object} options A dict with options.
 * @constructor
 */
var InstanceValidator = module.exports = function(modelInstance, options) {
  options = options || {};

  if (options.fields && !options.skip) {
    options.skip = Utils._.difference(Object.keys(modelInstance.Model.attributes), options.fields);
  }

  // assign defined and default options
  this.options = Utils._.defaults(options, {
    skip: []
  });

  this.modelInstance = modelInstance;

  /**
   * Exposes a reference to validator.js. This allows you to add custom validations using `validator.extend`
   * @name validator
   */
  this.validator = validator;

  /**
   *  All errors will be stored here from the validations.
   *
   * @type {Array} Will contain keys that correspond to attributes which will
   *   be Arrays of Errors.
   */
  this.errors = [];

  /** @type {boolean} Indicates if validations are in progress */
  this.inProgress = false;

  extendModelValidations(modelInstance);
};

/** @define {string} The error key for arguments as passed by custom validators */
InstanceValidator.RAW_KEY_NAME = '__raw';

/**
 * The main entry point for the Validation module, invoke to start the dance.
 *
 * @return {Promise}
 */
InstanceValidator.prototype.validate = function() {
  if (this.inProgress) {
    throw new Error('Validations already in progress.');
  }
  this.inProgress = true;

  var self = this;
  return Promise.settle([
    self._builtinValidators(),
    self._customValidators()
  ]).then(function() {
    if (self.errors.length) {
      return new sequelizeError.ValidationError(null, self.errors);
    }
  });
};

/**
 * Invoke the Validation sequence:
 *   - Before Validation Model Hooks
 *   - Validation
 *   - After Validation Model Hooks
 *
 * @return {Promise}
 */
InstanceValidator.prototype.hookValidate = function() {
  var self = this;
  return self.modelInstance.Model.runHooks('beforeValidate', self.modelInstance, self.options).then(function() {
    return self.validate().then(function(error) {
      if (error) {
        throw error;
      }
    });
  }).then(function() {
    return self.modelInstance.Model.runHooks('afterValidate', self.modelInstance, self.options);
  }).return(self.modelInstance);
};

/**
 * Will run all the built-in validators.
 *
 * @return {Promise(Array.<Promise.PromiseInspection>)} A promise from .settle().
 * @private
 */
InstanceValidator.prototype._builtinValidators = function() {
  var self = this;

  // promisify all attribute invocations
  var validators = [];
  Utils._.forIn(this.modelInstance.rawAttributes, function(rawAttribute, field) {
    if (self.options.skip.indexOf(field) >= 0) {
      return;
    }

    var value = self.modelInstance.dataValues[field];

    if (!rawAttribute._autoGenerated && !rawAttribute.autoIncrement) {
      // perform validations based on schema
      self._validateSchema(rawAttribute, field, value);
    }

    if (self.modelInstance.validators.hasOwnProperty(field)) {
      validators.push(self._builtinAttrValidate.call(self, value, field));
    }
  });

  return Promise.settle(validators);
};

/**
 * Will run all the custom validators.
 *
 * @return {Promise(Array.<Promise.PromiseInspection>)} A promise from .settle().
 * @private
 */
InstanceValidator.prototype._customValidators = function() {
  var validators = [];
  var self = this;
  Utils._.each(this.modelInstance.$modelOptions.validate, function(validator, validatorType) {
    if (self.options.skip.indexOf(validatorType) >= 0) {
      return;
    }

    var valprom = self._invokeCustomValidator(validator, validatorType)
      // errors are handled in settling, stub this
      .catch(function() {});

    validators.push(valprom);
  });

  return Promise.settle(validators);
};

/**
 * Validate a single attribute with all the defined built-in validators.
 *
 * @param {*} value Anything.
 * @param {string} field The field name.
 * @return {Promise} A promise, will always resolve,
 *   auto populates error on this.error local object.
 * @private
 */
InstanceValidator.prototype._builtinAttrValidate = function(value, field) {
  var self = this;
  // check if value is null (if null not allowed the Schema pass will capture it)
  if (value === null || typeof value === 'undefined') {
    return Promise.resolve();
  }

  // Promisify each validator
  var validators = [];
  Utils._.forIn(this.modelInstance.validators[field], function(test,
    validatorType) {

    if (['isUrl', 'isURL', 'isEmail'].indexOf(validatorType) !== -1) {
      // Preserve backwards compat. Validator.js now expects the second param to isURL and isEmail to be an object
      if (typeof test === 'object' && test !== null && test.msg) {
        test = {
          msg: test.msg
        };
      } else if (test === true) {
        test = {};
      }
    }

    // Check for custom validator.
    if (typeof test === 'function') {
      return validators.push(self._invokeCustomValidator(test, validatorType, true, value, field));
    }

    var validatorPromise = self._invokeBuiltinValidator(value, test, validatorType, field);
    // errors are handled in settling, stub this
    validatorPromise.catch(function() {});
    validators.push(validatorPromise);
  });

  return Promise.settle(validators).then(this._handleSettledResult.bind(this, field));
};

/**
 * Prepare and invoke a custom validator.
 *
 * @param {Function} validator The custom validator.
 * @param {string} validatorType the custom validator type (name).
 * @param {boolean=} optAttrDefined Set to true if custom validator was defined
 *   from the Attribute
 * @return {Promise} A promise.
 * @private
 */
InstanceValidator.prototype._invokeCustomValidator = Promise.method(function(validator, validatorType, optAttrDefined, optValue, optField) {
  var validatorFunction = null;  // the validation function to call
  var isAsync = false;

  var validatorArity = validator.length;
  // check if validator is async and requires a callback
  var asyncArity = 1;
  var errorKey = validatorType;
  var invokeArgs;
  if (optAttrDefined) {
    asyncArity = 2;
    invokeArgs = optValue;
    errorKey = optField;
  }
  if (validatorArity === asyncArity) {
    isAsync = true;
  }

  if (isAsync) {
    if (optAttrDefined) {
      validatorFunction = Promise.promisify(validator.bind(this.modelInstance, invokeArgs));
    } else {
      validatorFunction = Promise.promisify(validator.bind(this.modelInstance));
    }
    return validatorFunction().catch(this._pushError.bind(this, false, errorKey));
  } else {
    return Promise.try(validator.bind(this.modelInstance, invokeArgs)).catch(this._pushError.bind(this, false, errorKey));
  }
});

/**
 * Prepare and invoke a build-in validator.
 *
 * @param {*} value Anything.
 * @param {*} test The test case.
 * @param {string} validatorType One of known to Sequelize validators.
 * @param {string} field The field that is being validated
 * @return {Object} An object with specific keys to invoke the validator.
 * @private
 */
InstanceValidator.prototype._invokeBuiltinValidator = Promise.method(function(value, test, validatorType, field) {
  // check if Validator knows that kind of validation test
  if (typeof validator[validatorType] !== 'function') {
    throw new Error('Invalid validator function: ' + validatorType);
  }

  // extract extra arguments for the validator
  var validatorArgs = test.args || test;

  if (!Array.isArray(validatorArgs)) {
    if (validatorType === 'isImmutable') {
      validatorArgs = [validatorArgs, field];
    } else if (validatorType === 'isIP') {
      validatorArgs = [];
    } else {
      validatorArgs = [validatorArgs];
    }
  } else {
    validatorArgs = validatorArgs.slice(0);
  }

  if (!validator[validatorType].apply(validator, [value].concat(validatorArgs))) {
  // extract the error msg
    throw test.msg || 'Validation ' + validatorType + ' failed';
  }
});

/**
 * Will validate a single field against its schema definition (isnull).
 *
 * @param {Object} rawAttribute As defined in the Schema.
 * @param {string} field The field name.
 * @param {*} value anything.
 * @private
 */
InstanceValidator.prototype._validateSchema = function(rawAttribute, field, value) {
  var error;

  if (rawAttribute.allowNull === false && ((value === null) || (value === undefined))) {
    error = new sequelizeError.ValidationErrorItem(field + ' cannot be null', 'notNull Violation', field, value);
    this.errors.push(error);
  }

  if (rawAttribute.type === DataTypes.STRING || rawAttribute.type instanceof DataTypes.STRING || rawAttribute.type === DataTypes.TEXT || rawAttribute.type instanceof DataTypes.TEXT) {
    if (Array.isArray(value) || (_.isObject(value) && !value._isSequelizeMethod) && !Buffer.isBuffer(value)) {
      error = new sequelizeError.ValidationErrorItem(field + ' cannot be an array or an object', 'string violation', field, value);
      this.errors.push(error);
    }
  }
};

/**
 * Handles the returned result of a Promise.settle.
 *
 * If errors are found it populates this.error.
 *
 * @param {string} field The attribute name.
 * @param {Array.<Promise.PromiseInspection>} Promise inspection objects.
 * @private
 */
InstanceValidator.prototype._handleSettledResult = function(field, promiseInspections) {
  var self = this;
  promiseInspections.forEach(function(promiseInspection) {
    if (promiseInspection.isRejected()) {
      var rejection = promiseInspection.error();
      self._pushError(true, field, rejection);
    }
  });
};

/**
 * Signs all errors retaining the original.
 *
 * @param {boolean} isBuiltin Determines if error is from builtin validator.
 * @param {string} errorKey The error key to assign on this.errors object.
 * @param {Error|string} rawError The original error.
 * @private
 */
InstanceValidator.prototype._pushError = function(isBuiltin, errorKey, rawError) {
  var message = rawError.message || rawError || 'Validation error';
  var error = new sequelizeError.ValidationErrorItem(message, 'Validation error', errorKey, rawError);
  error[InstanceValidator.RAW_KEY_NAME] = rawError;

  this.errors.push(error);
};
<|endoftext|>


<commit_before>Vps.Auto.GridFilter.ComboBox = function(config)
{
    Vps.Auto.GridFilter.ComboBox.superclass.constructor.call(this, config);

    var record = Ext.data.Record.create(['id', 'name'])
    var filterStore = new Ext.data.Store({
        reader: new Ext.data.ArrayReader({}, record),
        data: config.data
    });
    if (!config['default'] && filterStore.find('id', 0) == -1) {
        filterStore.insert(0, [new record({id: 0, name: 'all'})]);
		config['default'] = 0;
    }
    this.combo = new Ext.form.ComboBox({
            store: filterStore,
            displayField: 'name',
            valueField: 'id',
            mode: 'local',
            triggerAction: 'all',
            editable: false,
            width: config.width || 200
        });
    this.combo.setValue(config['default']);
    this.combo.on('select', function() {
        this.fireEvent('filter', this, this.getParams());
    }, this);
    this.toolbarItems.add(this.combo);
};

Ext.extend(Vps.Auto.GridFilter.ComboBox, Vps.Auto.GridFilter.Abstract, {
    reset: function() {
        this.combo.setValue(0);
    },
    getParams: function() {
        var params = {};
        params['query_'+this.id] = this.combo.getValue();
        return params;
    }
});

<commit_msg>AutoGrid: DefaultText in Filter einstellbar (statt 'all')<commit_after>Vps.Auto.GridFilter.ComboBox = function(config)
{
    Vps.Auto.GridFilter.ComboBox.superclass.constructor.call(this, config);

    var record = Ext.data.Record.create(['id', 'name'])
    var filterStore = new Ext.data.Store({
        reader: new Ext.data.ArrayReader({}, record),
        data: config.data
    });
    if (!config['default'] && filterStore.find('id', 0) == -1) {
        filterStore.insert(0, [new record({id: 0, name: config['defaultText'] ? config['defaultText'] : 'all'})]);
		config['default'] = 0;
    }
    this.combo = new Ext.form.ComboBox({
            store: filterStore,
            displayField: 'name',
            valueField: 'id',
            mode: 'local',
            triggerAction: 'all',
            editable: false,
            width: config.width || 200
        });
    this.combo.setValue(config['default']);
    this.combo.on('select', function() {
        this.fireEvent('filter', this, this.getParams());
    }, this);
    this.toolbarItems.add(this.combo);
};

Ext.extend(Vps.Auto.GridFilter.ComboBox, Vps.Auto.GridFilter.Abstract, {
    reset: function() {
        this.combo.setValue(0);
    },
    getParams: function() {
        var params = {};
        params['query_'+this.id] = this.combo.getValue();
        return params;
    }
});

<|endoftext|>


<commit_before>(function () {
    'use strict';
    /* globals console, exec, mkdir, __dirname */

    /**
     * Jetbrains WebStorm 9 project generation.
     *
     * @type {ideTemplate|exports}
     */
    var util = require('util'),
    IDE = require('../IDE'),
    fs = require('fs'),
    path = require('path'),
    _ = require('lodash');

    require('shelljs/global');

    var templateUtil;

    function WebStorm(ide) {

        WebStorm.super_.apply(this, ['webstorm']);

        templateUtil = ide;

        if (templateUtil.platform === ('unix' || 'darwin')) {
            this.executable = 'wstorm';
        } else {
            // todo in windows check if webstorm.exe exists otherwise prompt for a path and save it to disk}
            var webStormPath = path.resolve('/', 'Program Files (x86)/JetBrains/WebStorm 8.0.1/bin/WebStorm.exe');

            this.executable = '"' + webStormPath + '"';

            if (!templateUtil.fileExists(this.executable))
                console.error('Error the WebStorm.exe is not present at', this.executable);
        }
    }

    util.inherits(WebStorm, IDE);

    /**
     * Use the WebStorm executable to open a project programatically.
     *
     * @param location
     */
    WebStorm.prototype.open = function (location)
    {
        if (!this.validatePath(location)) return;

        var openCommand = this.executable + ' "' + location + '"';
        console.log(openCommand);

        if (templateUtil.platform === ('unix' || 'darwin'))
            exec(openCommand);
        else
            exec(openCommand);

        console.log('Please give WebStorm a chance to complete it\'s indexing before opening.');
    };

    /**
     * Create a new template context for an idea project.
     * if a custom context is provided it will override any default values of the resulting object.
     *
     * Example template context
     {
            projectName         : project.projectName,
            jshintPath          : '$PROJECT_DIR$/.jshintrc',
            jsDebugPort         : 9000,
            contentPaths        : [
                {
                    content: 'file://' + project.destination
                }
            ],
            libraries           : ['jasmine-DefinitelyTyped', 'angular'],
            selectedDebugName   : 'JavaScript Debug.' + project.projectName,
            jsDebugConfiguration: [
                {
                    name     : project.projectName,
                    uri: 'http://localhost:8000/app',
                    mapping  : {
                        url      : 'http://localhost:8000',
                        localFile: '$PROJECT_DIR$'
                    }
                }
            ],
            plainText           : [
                'file://$PROJECT_DIR$/build/app/main.js'
            ],
            resourceRoots       : [
                'file://$PROJECT_DIR$/src/js-lib'
            ],
            projectPane: fs.readFileSync(__dirname + '/projectPane.xml')
        };
     *
     * @param override
     * @returns {Result|Object}
     */
    WebStorm.prototype.createContext = function (override)
    {
        var defaultContext = {
            projectName             : 'NewProject',
            jshintPath              : './.jshintrc',
            jsDebugPort             : '63343',
            projectFolder           : '',
            selectedDebugName       : '',
            contentPaths            : [
                {
                    content : 'file://$MODULE_DIR$',
                    excluded: []
                }
            ],
            projectPane             : [],
            libraries               : [],
            vcs                     : [],
            jsDebugConfiguration    : [],
            nodejsDebugConfiguration: []
        };

        return _.merge(defaultContext, override);
    };

    /**
     * Shortcut to create a project context with the default values
     * This prevents an error in lodash template with undefined template tokens.
     *
     * @param projectName
     * @param contentPaths
     * @param jsDebugPort
     * @param jshintPath
     */
    WebStorm.prototype.createProjectContext = function (projectName, contentPaths, jsDebugPort, jshintPath)
    {
        return {
            projectName : projectName,
            jshintPath  : jshintPath,
            jsDebugPort : jsDebugPort,
            contentPaths: contentPaths
        };
    };

    /**
     * Create a new WebStorm .idea project at a given destination with
     * a specific template context.
     *
     * @param destination
     * @param context
     */
    WebStorm.prototype.createProject = function (destination, context)
    {
        context = this.createContext(context);

        var source = path.join(String(__dirname), 'template', 'project');
        destination = path.join(destination, '.idea');

        templateUtil.templateDirSync(source, destination, context);

        if (context.resourceRoots.length > 0)
            stubPlainTextFiles(context.plainText, destination);
    };

    /**
     * WebStorm will remove any plain text files specified on first open
     * if they do not exists.
     *
     * For example this lets files from a build be marked as plain text before they exist
     * by stubbing an empty file at their expected position.
     * @param resourceRoots
     * @param destination
     */
    function stubPlainTextFiles(resourceRoots, destination) {
        _.forEach(resourceRoots, function (resource) {
            // Replace the webstorm file:// scheme with an absolute file path
            var filePath = resource.replace('file://$PROJECT_DIR$', destination);
            filePath = filePath.replace('.idea/', '');
            // Extract the location from the file path to recursively create it if it doesn't exist.
            var location = filePath.replace(/[^\/]*$/, '');

            if (!fs.existsSync(location))
                mkdir('-p', location);

            if (!fs.existsSync(filePath))
                fs.writeFileSync(filePath, ' ', 'utf8');
        });
    }

    /**
     * WebStorm IDE settings path.
     *
     * Returns the IDE settings path based on the current platform.
     *
     * See more info from the jetbrains docs.
     * http://www.jetbrains.com/webstorm/webhelp/project-and-ide-settings.html
     *
     * @returns {*}
     */
    WebStorm.prototype.userPreferences = function ()
    {
        var location;

        if (templateUtil.platform === 'windows')
            location = path.join(templateUtil.HOME, '.WebStorm8', 'config');
        else
            location = path.join(templateUtil.HOME, 'Library', 'Preferences', 'WebStorm8');

        return location;
    };

    /**
     * Method for copying the WebStorm external tools configuration to the local
     * user preferences folders.
     *
     * http://www.jetbrains.com/webstorm/webhelp/external-tools.html
     *
     */
    WebStorm.prototype.copyExternalTools = function ()
    {
        var destination = path.join(this.userPreferences(), 'tools');
        var source = path.join(this.templateSource, 'idea', 'tools', '**', '*.*');

        templateUtil.cpRConflict(source, destination);
    };

    /**
     * Method for copying WebStorm file template configurations to the local
     * user preferences folders.
     *
     * http://www.jetbrains.com/webstorm/webhelp/file-and-code-templates.html
     *
     */
    WebStorm.prototype.copyFileTemplates = function ()
    {
        var destination = path.join(this.userPreferences(), 'fileTemplates');
        var source = path.join(this.templateSource, 'idea', 'fileTemplates', '**', '*.*');

        templateUtil.cpRConflict(source, destination);
    };

    module.exports = WebStorm;
}());
<commit_msg>fix (webstorm) use version 9 as default.<commit_after>(function () {
    'use strict';
    /* globals console, exec, mkdir, __dirname */

    /**
     * Jetbrains WebStorm 9 project generation.
     *
     * @type {ideTemplate|exports}
     */
    var util = require('util'),
    IDE = require('../IDE'),
    fs = require('fs'),
    path = require('path'),
    _ = require('lodash');

    require('shelljs/global');

    var templateUtil;

    function WebStorm(ide) {

        WebStorm.super_.apply(this, ['webstorm']);

        templateUtil = ide;

        if (templateUtil.platform === ('unix' || 'darwin')) {
            this.executable = 'wstorm';
        } else {
            // todo in windows check if webstorm.exe exists otherwise prompt for a path and save it to disk}
            var webStormPath = path.resolve('/', 'Program Files (x86)/JetBrains/WebStorm 8.0.1/bin/WebStorm.exe');

            this.executable = '"' + webStormPath + '"';

            if (!templateUtil.fileExists(this.executable))
                console.error('Error the WebStorm.exe is not present at', this.executable);
        }
    }

    util.inherits(WebStorm, IDE);

    /**
     * Use the WebStorm executable to open a project programatically.
     *
     * @param location
     */
    WebStorm.prototype.open = function (location)
    {
        if (!this.validatePath(location)) return;

        var openCommand = this.executable + ' "' + location + '"';
        console.log(openCommand);

        if (templateUtil.platform === ('unix' || 'darwin'))
            exec(openCommand);
        else
            exec(openCommand);

        console.log('Please give WebStorm a chance to complete it\'s indexing before opening.');
    };

    /**
     * Create a new template context for an idea project.
     * if a custom context is provided it will override any default values of the resulting object.
     *
     * Example template context
     {
            projectName         : project.projectName,
            jshintPath          : '$PROJECT_DIR$/.jshintrc',
            jsDebugPort         : 9000,
            contentPaths        : [
                {
                    content: 'file://' + project.destination
                }
            ],
            libraries           : ['jasmine-DefinitelyTyped', 'angular'],
            selectedDebugName   : 'JavaScript Debug.' + project.projectName,
            jsDebugConfiguration: [
                {
                    name     : project.projectName,
                    uri: 'http://localhost:8000/app',
                    mapping  : {
                        url      : 'http://localhost:8000',
                        localFile: '$PROJECT_DIR$'
                    }
                }
            ],
            plainText           : [
                'file://$PROJECT_DIR$/build/app/main.js'
            ],
            resourceRoots       : [
                'file://$PROJECT_DIR$/src/js-lib'
            ],
            projectPane: fs.readFileSync(__dirname + '/projectPane.xml')
        };
     *
     * @param override
     * @returns {Result|Object}
     */
    WebStorm.prototype.createContext = function (override)
    {
        var defaultContext = {
            projectName             : 'NewProject',
            jshintPath              : './.jshintrc',
            jsDebugPort             : '63343',
            projectFolder           : '',
            selectedDebugName       : '',
            contentPaths            : [
                {
                    content : 'file://$MODULE_DIR$',
                    excluded: []
                }
            ],
            projectPane             : [],
            libraries               : [],
            vcs                     : [],
            jsDebugConfiguration    : [],
            nodejsDebugConfiguration: []
        };

        return _.merge(defaultContext, override);
    };

    /**
     * Shortcut to create a project context with the default values
     * This prevents an error in lodash template with undefined template tokens.
     *
     * @param projectName
     * @param contentPaths
     * @param jsDebugPort
     * @param jshintPath
     */
    WebStorm.prototype.createProjectContext = function (projectName, contentPaths, jsDebugPort, jshintPath)
    {
        return {
            projectName : projectName,
            jshintPath  : jshintPath,
            jsDebugPort : jsDebugPort,
            contentPaths: contentPaths
        };
    };

    /**
     * Create a new WebStorm .idea project at a given destination with
     * a specific template context.
     *
     * @param destination
     * @param context
     */
    WebStorm.prototype.createProject = function (destination, context)
    {
        context = this.createContext(context);

        var source = path.join(String(__dirname), 'template', 'project');
        destination = path.join(destination, '.idea');

        templateUtil.templateDirSync(source, destination, context);

        if (context.resourceRoots.length > 0)
            stubPlainTextFiles(context.plainText, destination);
    };

    /**
     * WebStorm will remove any plain text files specified on first open
     * if they do not exists.
     *
     * For example this lets files from a build be marked as plain text before they exist
     * by stubbing an empty file at their expected position.
     * @param resourceRoots
     * @param destination
     */
    function stubPlainTextFiles(resourceRoots, destination) {
        _.forEach(resourceRoots, function (resource) {
            // Replace the webstorm file:// scheme with an absolute file path
            var filePath = resource.replace('file://$PROJECT_DIR$', destination);
            filePath = filePath.replace('.idea/', '');
            // Extract the location from the file path to recursively create it if it doesn't exist.
            var location = filePath.replace(/[^\/]*$/, '');

            if (!fs.existsSync(location))
                mkdir('-p', location);

            if (!fs.existsSync(filePath))
                fs.writeFileSync(filePath, ' ', 'utf8');
        });
    }

    /**
     * WebStorm IDE settings path.
     *
     * Returns the IDE settings path based on the current platform.
     *
     * See more info from the jetbrains docs.
     * http://www.jetbrains.com/webstorm/webhelp/project-and-ide-settings.html
     *
     * @returns {*}
     */
    WebStorm.prototype.userPreferences = function ()
    {
        var location;

        if (templateUtil.platform === 'windows')
            location = path.join(templateUtil.HOME, '.WebStorm9', 'config');
        else
            location = path.join(templateUtil.HOME, 'Library', 'Preferences', 'WebStorm9');

        return location;
    };

    /**
     * Method for copying the WebStorm external tools configuration to the local
     * user preferences folders.
     *
     * http://www.jetbrains.com/webstorm/webhelp/external-tools.html
     *
     */
    WebStorm.prototype.copyExternalTools = function ()
    {
        var destination = path.join(this.userPreferences(), 'tools');
        var source = path.join(this.templateSource, 'idea', 'tools', '**', '*.*');

        templateUtil.cpRConflict(source, destination);
    };

    /**
     * Method for copying WebStorm file template configurations to the local
     * user preferences folders.
     *
     * http://www.jetbrains.com/webstorm/webhelp/file-and-code-templates.html
     *
     */
    WebStorm.prototype.copyFileTemplates = function ()
    {
        var destination = path.join(this.userPreferences(), 'fileTemplates');
        var source = path.join(this.templateSource, 'idea', 'fileTemplates', '**', '*.*');

        templateUtil.cpRConflict(source, destination);
    };

    module.exports = WebStorm;
}());
<|endoftext|>


<commit_before>Polymer({
  is: 'arc-request-panel',

  properties: {
    /**
     * Current route params.
     */
    routeParams: Object,
    /**
     * Set by parent element to determine that this view is opened.
     */
    opened: Boolean,
    /**
     * Set by the `chrome-xhr-request` element. True if the proxy extension
     * is installed an connected to the application.
     */
    hasProxyInstalled: Boolean,
    /**
     * Current request object.
     */
    request: Object,
    /**
     * Keeps temp request data restored from the datastore / local store
     * to sync state between different stores and the UI.
     */
    proxyRequest: Object,
    /**
     * If set the panel will use the XHR proxy to send the request
     */
    useXhr: Boolean,
    // Currently selected project.
    projectId: String,
    // True to display cookie exchange instalkl banner.
    cookieBanner: Boolean
  },

  listeners: {
    'transport-request': '_onTransportRequested',
    'abort-request': '_abortHandler',
    'request-clear-state': '_clear'
  },

  observers: [
    '_routeChnaged(routeParams, opened)',
    '_openedChanged(opened)',
    '_proxyRequestChanged(proxyRequest.*)',
    '_requestChanged(request.*)',
    '_projectIdChanged(projectId)'
  ],

  attached: function() {
    this.listen(window, 'report-response', '_reportRequestHandler');
  },

  detached: function() {
    this.unlisten(window, 'report-response', '_reportRequestHandler');
  },

  _clear: function() {
    this.cookieBanner = false;
  },

  _routeChnaged: function(route, opened) {
    if (!opened || !route || !route.type) {
      return;
    }
    switch (route.type) {
      case 'saved':
      case 'history':
        let id = decodeURIComponent(this.routeParams.savedId || this.routeParams.historyId);
        this._restoreRequestData(id, route.type);
        break;
      case 'current':
      case 'drive':
        return;
      default:
        this.restoreLatest();
        break;
    }
  },

  _openedChanged: function(opened) {
    if (opened) {
      this._requestFeatures();
    } else {
      this._releaseFeatures();
    }
  },

  _requestFeatures: function() {
    this.fire('request-toolbar-features', {
      features: ['clearAll', 'save', 'xhrtoggle']
    }, {
      cancelable: true
    });
  },

  _releaseFeatures: function() {
    this.fire('release-toolbar-features', {}, {
      cancelable: true
    });
  },

  _onTransportRequested: function(e) {
    if (this.cookieBanner) {
      this.cookieBanner = false;
    }
    this.fire('url-history-store', {
      value: this.request.url
    }, {
      cancelable: true,
      composed: true
    });
    var panel;
    if (this.useXhr) {
      panel = this.$$('chrome-xhr-request');
    } else {
      panel = this.$$('chrome-socket-request');
    }
    panel.send(e.detail)
    .catch(cause => {
      console.error(cause);
    });
  },
  /**
   * Aborts the request.
   */
  _abortHandler: function() {
    var panel;
    if (this.useXhr) {
      panel = this.$$('chrome-xhr-request');
    } else {
      panel = this.$$('chrome-socket-request');
    }
    panel.abort();
    this.fire('url-history-store', {
      value: this.request.url
    }, {
      cancelable: true,
      composed: true
    });
  },
  /**
   * Handler for the XHR change event
   */
  _xhrChanged: function(e) {
    var requested = e.detail.value;
    e.preventDefault();
    e.stopPropagation();

    if (!this.hasProxyInstalled && requested) {
      this.$$('install-proxy-dialog').opened = true;
      return;
    }
    this.useXhr = requested;
    this.fire('send-analytics', {
      type: 'event',
      category: 'Request',
      action: 'Use XHR',
      label: requested + '',
    });
  },
  /**
   * Clears the request state
   */
  clearRequest: function(e) {
    this.set('request', {
      method: 'GET'
    });
    this.projectId = undefined;
    if (e && e.preventDefault) {
      e.preventDefault();
      e.stopPropagation();
    }
  },
  /**
   * Restores saved in the datastore request data.
   * @param {String} id ID of the record
   * @param {String} type Type of the stored data. Can be `saved`, `history` or
   * `drive`
   */
  _restoreRequestData: function(id, type) {
    type = type || 'saved';
    var dbName;
    switch (type) {
      case 'saved':
        dbName = 'saved-requests';
        break;
      case 'history':
        dbName = 'history-requests';
        break;
      case 'drive':
        dbName = 'saved-requests';
        break;
      default:
        this.fire('app-log', {
          'message': `${type} is not a type of a request.`,
          'level': 'error'
        });
        console.error('Can\'t restore request data. Type is unknown.', type);
        this.fire('send-analytics', {
          type: 'exception',
          description: 'Can\'t restore request of a type: ' + type + ' (ArcRequestPanel)',
          fatal: true
        });
        this.$.typeMissingToast.opened = true;
        return;
    }

    var db = new PouchDB(dbName);
    return db.get(id)
    .then((r) => {
      r.type = type;
      this.set('proxyRequest', r);
    })
    .catch((e) => {
      this.fire('app-log', {
        'message': e,
        'level': 'error'
      });
      console.error('Can\'t restore request data', e);
      this.$.missingRequestToast.opened = true;
    });
  },
  /**
   * Sets the `request` object when a proxy change.
   */
  _proxyRequestChanged: function(record) {
    if (!record || !record.base) {
      return;
    }
    var data = record.base;
    var base = {
      _id: data._id,
      type: data.type,
      headers: data.headers,
      legacyProject: data.legacyProject,
      method: data.method,
      name: data.name,
      payload: data.payload,
      url: data.url,
      description: data.description
    };
    if (data.legacyProject !== this.projectId) {
      this.set('projectId', data.legacyProject);
    }
    this.set('request', base);
  },
  // Restores latest request from local storage.
  restoreLatest: function() {
    this.$.latest.read();
  },

  // Handler for latest rectore call.
  _latestLoaded: function(e) {
    var obj = e.detail.value;
    if (!obj) {
      obj = {
        method: 'GET'
      };
    }
    this.set('request', obj);
  },

  _requestChanged: function(record) {
    if (!record || !record.base) {
      return;
    }
    var request = record.base;
    if (Object.keys(request).length === 1 && request.method && request.method === 'GET') {
      // Default value.
      return;
    }
    this.debounce('request-store', function() {
      this.$.latest.store();
    }, 100);
  },
  /**
   * Handler for the save event from the request editor.
   */
  _saveHandler: function(e) {
    this.onSave({});
    e.preventDefault();
    e.stopPropagation();
  },

  onSave: function(opts) {
    if (!this.request.url || !this.request.url.trim()) {
      return;
    }
    var type = this.request.type;
    var isDrive;
    var isSaved;
    if (type) {
      isDrive = type === 'google-drive';
      isSaved = type === 'saved';
    } else {
      isDrive = !!this.routeParams.externalId;
      isSaved = !!this.routeParams.savedId;
    }
    if ((isDrive || isSaved) && opts.source === 'shortcut' && !opts.shift) {
      return this._saveCurrent();
    }

    this.$.requestEditor.request = this.request;
    this.$.requestEditorContainer.opened = true;
    this.fire('send-analytics', {
      'type': 'event',
      'category': 'Engagement',
      'action': 'Click',
      'label': 'Save action initialization'
    });
  },

  _resizeEditorSheetContent: function() {
    this.$.requestEditor.notifyResize();
  },

  _cancelRequestEdit: function() {
    this.$.requestEditorContainer.opened = false;
    this.$.requestEditor.request = undefined;
  },

  _saveCurrent: function() {
    var data = Object.assign({}, this.proxyRequest, this.request);
    var opts = {
      isDrive: this.request.type === 'google-drive',
      projectId: this.projectId,
      name: data.name,
      description: data.description
    };

    this._dispatchSaveRequest(opts, data);
    this.fire('send-analytics', {
      'type': 'event',
      'category': 'Engagement',
      'action': 'Click',
      'label': 'Save express'
    });
  },

  /**
   * Prepares a detail object for the `save-request-data` event.
   *
   * @param {Object} opts Map of saving request options returned from save
   *                      panel / dialog
   * @param {Object} request The request object to update.
   * @return {Object} Event's detail object.
   */
  _prepareSaveRequestEvent: function(opts, request) {
    var data = Object.assign({}, request);
    if (opts.name) {
      data.name = opts.name;
    }
    if (opts.description) {
      data.description = opts.description;
    } else if (data.description) {
      delete data.description;
    }
    if (opts.override === false || opts.type === 'history') {
      delete data._id;
      delete data._rev;
    }
    var detail = {
      request: data,
      opts: opts
    };
    detail.opts.drive = opts.isDrive ? true : false;
    delete opts.isDrive;
    return detail;
  },

  /**
   * Dispatches the event to save request data in the data store.
   * @param {CustomEvent} e The `save-request` event dispatched from the editor.
   */
  _saveRequestEdit: function(e) {
    this.$.requestEditorContainer.opened = false;
    this.$.requestEditor.request = undefined;
    this._dispatchSaveRequest(e.detail, e.detail.request);
  },

  _dispatchSaveRequest: function(opts, data) {
    var detail = this._prepareSaveRequestEvent(opts, data);

    var event = this.fire('save-request-data', detail, {
      cancelable: true,
      composed: true
    });

    if (!event.defaultPrevented) {
      let message = 'Unable to save current request.\n';
      message += 'The "save-request-data" event is not handled.';
      console.error(message);
      this.fire('app-log', {
        'message': [message],
        'level': 'error'
      });
      this.$.errorToast.text = message;
      this.$.errorToast.opened = true;
      return Promise.reject(new Error('Save event not handled'));
    }

    // if (opts.isProject) {
    //   if (opts.projectIsNew) {
    //     detail.opts.projectName = opts.projectName;
    //   } else {
    //     detail.opts.projectId = opts.projectId;
    //   }
    // }

    return event.detail.result
    .then(request => {
      this.$.savedOk.opened = true;
      if (request.legacyProject && request.legacyProject !== this.projectId) {
        this.set('projectId', request.legacyProject);
      } else if (!request.legacyProject && this.projectId) {
        this.set('projectId', undefined);
      }
      this.proxyRequest = data;
      var id = request._id;
      try {
        id = encodeURIComponent(id);
      } catch (e) {}
      this.set('routeParams', {
        savedId: id,
        type: 'saved'
      });
    })
    .catch(cause => {
      console.error('Save request error', cause);
      this.fire('app-log', {
        'message': ['Unable to save the request.', cause],
        'level': 'error'
      });
      this.$.errorToast.text = 'Unable to save current request. ' + cause.message;
      this.$.errorToast.opened = true;
    });
  },
  /**
   * Inform other elements that the project ID changed.
   */
  _projectIdChanged: function(id) {
    this.fire('selected-project-changed', {
      value: id
    });
  },
  /**
   * Handles `report-response` custom event and displays cookie banner
   * if the response needs authorization.
   */
  _reportRequestHandler: function(e) {
    if (e.detail.auth) {
      this.cookieBanner = true;
    }
  },
  // Closes cookie banner upon user request.
  _closeCookieBanner: function() {
    this.cookieBanner = false;
  }
});
<commit_msg>Fix: Fixes #1096 - command + R to send request<commit_after>Polymer({
  is: 'arc-request-panel',

  properties: {
    /**
     * Current route params.
     */
    routeParams: Object,
    /**
     * Set by parent element to determine that this view is opened.
     */
    opened: Boolean,
    /**
     * Set by the `chrome-xhr-request` element. True if the proxy extension
     * is installed an connected to the application.
     */
    hasProxyInstalled: Boolean,
    /**
     * Current request object.
     */
    request: Object,
    /**
     * Keeps temp request data restored from the datastore / local store
     * to sync state between different stores and the UI.
     */
    proxyRequest: Object,
    /**
     * If set the panel will use the XHR proxy to send the request
     */
    useXhr: Boolean,
    // Currently selected project.
    projectId: String,
    // True to display cookie exchange instalkl banner.
    cookieBanner: Boolean
  },

  listeners: {
    'transport-request': '_onTransportRequested',
    'abort-request': '_abortHandler',
    'request-clear-state': '_clear'
  },

  observers: [
    '_routeChnaged(routeParams, opened)',
    '_openedChanged(opened)',
    '_proxyRequestChanged(proxyRequest.*)',
    '_requestChanged(request.*)',
    '_projectIdChanged(projectId)'
  ],

  attached: function() {
    this.listen(window, 'report-response', '_reportRequestHandler');
  },

  detached: function() {
    this.unlisten(window, 'report-response', '_reportRequestHandler');
  },

  _clear: function() {
    this.cookieBanner = false;
  },

  _routeChnaged: function(route, opened) {
    if (!opened || !route || !route.type) {
      return;
    }
    switch (route.type) {
      case 'saved':
      case 'history':
        let id = decodeURIComponent(this.routeParams.savedId || this.routeParams.historyId);
        this._restoreRequestData(id, route.type);
        break;
      case 'current':
      case 'drive':
        return;
      default:
        this.restoreLatest();
        break;
    }
  },

  _openedChanged: function(opened) {
    if (opened) {
      this._requestFeatures();
    } else {
      this._releaseFeatures();
    }
  },

  _requestFeatures: function() {
    this.fire('request-toolbar-features', {
      features: ['clearAll', 'save', 'xhrtoggle']
    }, {
      cancelable: true
    });
  },

  _releaseFeatures: function() {
    this.fire('release-toolbar-features', {}, {
      cancelable: true
    });
  },

  _onTransportRequested: function(e) {
    if (this.cookieBanner) {
      this.cookieBanner = false;
    }
    this.fire('url-history-store', {
      value: this.request.url
    }, {
      cancelable: true,
      composed: true
    });
    var panel;
    if (this.useXhr) {
      panel = this.$$('chrome-xhr-request');
    } else {
      panel = this.$$('chrome-socket-request');
    }
    panel.send(e.detail)
    .catch(cause => {
      console.error(cause);
    });
  },
  /**
   * Aborts the request.
   */
  _abortHandler: function() {
    var panel;
    if (this.useXhr) {
      panel = this.$$('chrome-xhr-request');
    } else {
      panel = this.$$('chrome-socket-request');
    }
    panel.abort();
    this.fire('url-history-store', {
      value: this.request.url
    }, {
      cancelable: true,
      composed: true
    });
  },
  /**
   * Handler for the XHR change event
   */
  _xhrChanged: function(e) {
    var requested = e.detail.value;
    e.preventDefault();
    e.stopPropagation();

    if (!this.hasProxyInstalled && requested) {
      this.$$('install-proxy-dialog').opened = true;
      return;
    }
    this.useXhr = requested;
    this.fire('send-analytics', {
      type: 'event',
      category: 'Request',
      action: 'Use XHR',
      label: requested + '',
    });
  },
  /**
   * Clears the request state
   */
  clearRequest: function(e) {
    this.set('request', {
      method: 'GET'
    });
    this.projectId = undefined;
    if (e && e.preventDefault) {
      e.preventDefault();
      e.stopPropagation();
    }
  },
  /**
   * Sends the request from the shortcut manager.
   * TODO: It uses private APIs and it shouldn't.
   */
  sendRequest: function() {
    var panel = this.$$('request-panel');
    var editor = panel.$$('request-editor');
    editor._sendRequest();
  },
  /**
   * Restores saved in the datastore request data.
   * @param {String} id ID of the record
   * @param {String} type Type of the stored data. Can be `saved`, `history` or
   * `drive`
   */
  _restoreRequestData: function(id, type) {
    type = type || 'saved';
    var dbName;
    switch (type) {
      case 'saved':
        dbName = 'saved-requests';
        break;
      case 'history':
        dbName = 'history-requests';
        break;
      case 'drive':
        dbName = 'saved-requests';
        break;
      default:
        this.fire('app-log', {
          'message': `${type} is not a type of a request.`,
          'level': 'error'
        });
        console.error('Can\'t restore request data. Type is unknown.', type);
        this.fire('send-analytics', {
          type: 'exception',
          description: 'Can\'t restore request of a type: ' + type + ' (ArcRequestPanel)',
          fatal: true
        });
        this.$.typeMissingToast.opened = true;
        return;
    }

    var db = new PouchDB(dbName);
    return db.get(id)
    .then((r) => {
      r.type = type;
      this.set('proxyRequest', r);
    })
    .catch((e) => {
      this.fire('app-log', {
        'message': e,
        'level': 'error'
      });
      console.error('Can\'t restore request data', e);
      this.$.missingRequestToast.opened = true;
    });
  },
  /**
   * Sets the `request` object when a proxy change.
   */
  _proxyRequestChanged: function(record) {
    if (!record || !record.base) {
      return;
    }
    var data = record.base;
    var base = {
      _id: data._id,
      type: data.type,
      headers: data.headers,
      legacyProject: data.legacyProject,
      method: data.method,
      name: data.name,
      payload: data.payload,
      url: data.url,
      description: data.description
    };
    if (data.legacyProject !== this.projectId) {
      this.set('projectId', data.legacyProject);
    }
    this.set('request', base);
  },
  // Restores latest request from local storage.
  restoreLatest: function() {
    this.$.latest.read();
  },

  // Handler for latest rectore call.
  _latestLoaded: function(e) {
    var obj = e.detail.value;
    if (!obj) {
      obj = {
        method: 'GET'
      };
    }
    this.set('request', obj);
  },

  _requestChanged: function(record) {
    if (!record || !record.base) {
      return;
    }
    var request = record.base;
    if (Object.keys(request).length === 1 && request.method && request.method === 'GET') {
      // Default value.
      return;
    }
    this.debounce('request-store', function() {
      this.$.latest.store();
    }, 100);
  },
  /**
   * Handler for the save event from the request editor.
   */
  _saveHandler: function(e) {
    this.onSave({});
    e.preventDefault();
    e.stopPropagation();
  },

  onSave: function(opts) {
    if (!this.request.url || !this.request.url.trim()) {
      return;
    }
    var type = this.request.type;
    var isDrive;
    var isSaved;
    if (type) {
      isDrive = type === 'google-drive';
      isSaved = type === 'saved';
    } else {
      isDrive = !!this.routeParams.externalId;
      isSaved = !!this.routeParams.savedId;
    }
    if ((isDrive || isSaved) && opts.source === 'shortcut' && !opts.shift) {
      return this._saveCurrent();
    }

    this.$.requestEditor.request = this.request;
    this.$.requestEditorContainer.opened = true;
    this.fire('send-analytics', {
      'type': 'event',
      'category': 'Engagement',
      'action': 'Click',
      'label': 'Save action initialization'
    });
  },

  _resizeEditorSheetContent: function() {
    this.$.requestEditor.notifyResize();
  },

  _cancelRequestEdit: function() {
    this.$.requestEditorContainer.opened = false;
    this.$.requestEditor.request = undefined;
  },

  _saveCurrent: function() {
    var data = Object.assign({}, this.proxyRequest, this.request);
    var opts = {
      isDrive: this.request.type === 'google-drive',
      projectId: this.projectId,
      name: data.name,
      description: data.description
    };

    this._dispatchSaveRequest(opts, data);
    this.fire('send-analytics', {
      'type': 'event',
      'category': 'Engagement',
      'action': 'Click',
      'label': 'Save express'
    });
  },

  /**
   * Prepares a detail object for the `save-request-data` event.
   *
   * @param {Object} opts Map of saving request options returned from save
   *                      panel / dialog
   * @param {Object} request The request object to update.
   * @return {Object} Event's detail object.
   */
  _prepareSaveRequestEvent: function(opts, request) {
    var data = Object.assign({}, request);
    if (opts.name) {
      data.name = opts.name;
    }
    if (opts.description) {
      data.description = opts.description;
    } else if (data.description) {
      delete data.description;
    }
    if (opts.override === false || opts.type === 'history') {
      delete data._id;
      delete data._rev;
    }
    var detail = {
      request: data,
      opts: opts
    };
    detail.opts.drive = opts.isDrive ? true : false;
    delete opts.isDrive;
    return detail;
  },

  /**
   * Dispatches the event to save request data in the data store.
   * @param {CustomEvent} e The `save-request` event dispatched from the editor.
   */
  _saveRequestEdit: function(e) {
    this.$.requestEditorContainer.opened = false;
    this.$.requestEditor.request = undefined;
    this._dispatchSaveRequest(e.detail, e.detail.request);
  },

  _dispatchSaveRequest: function(opts, data) {
    var detail = this._prepareSaveRequestEvent(opts, data);

    var event = this.fire('save-request-data', detail, {
      cancelable: true,
      composed: true
    });

    if (!event.defaultPrevented) {
      let message = 'Unable to save current request.\n';
      message += 'The "save-request-data" event is not handled.';
      console.error(message);
      this.fire('app-log', {
        'message': [message],
        'level': 'error'
      });
      this.$.errorToast.text = message;
      this.$.errorToast.opened = true;
      return Promise.reject(new Error('Save event not handled'));
    }

    // if (opts.isProject) {
    //   if (opts.projectIsNew) {
    //     detail.opts.projectName = opts.projectName;
    //   } else {
    //     detail.opts.projectId = opts.projectId;
    //   }
    // }

    return event.detail.result
    .then(request => {
      this.$.savedOk.opened = true;
      if (request.legacyProject && request.legacyProject !== this.projectId) {
        this.set('projectId', request.legacyProject);
      } else if (!request.legacyProject && this.projectId) {
        this.set('projectId', undefined);
      }
      this.proxyRequest = data;
      var id = request._id;
      try {
        id = encodeURIComponent(id);
      } catch (e) {}
      this.set('routeParams', {
        savedId: id,
        type: 'saved'
      });
    })
    .catch(cause => {
      console.error('Save request error', cause);
      this.fire('app-log', {
        'message': ['Unable to save the request.', cause],
        'level': 'error'
      });
      this.$.errorToast.text = 'Unable to save current request. ' + cause.message;
      this.$.errorToast.opened = true;
    });
  },
  /**
   * Inform other elements that the project ID changed.
   */
  _projectIdChanged: function(id) {
    this.fire('selected-project-changed', {
      value: id
    });
  },
  /**
   * Handles `report-response` custom event and displays cookie banner
   * if the response needs authorization.
   */
  _reportRequestHandler: function(e) {
    if (e.detail.auth) {
      this.cookieBanner = true;
    }
  },
  // Closes cookie banner upon user request.
  _closeCookieBanner: function() {
    this.cookieBanner = false;
  }
});
<|endoftext|>


<commit_before>var ResponsesNewWindow = require('ui/handheld/android/ResponsesNewWindow');
var Survey = require('models/survey');
var Palette = require('ui/common/components/Palette');
var SeparatorView = require('ui/common/components/SeparatorView');
var ButtonView = require('ui/common/components/ButtonView');
var Measurements = require('ui/common/components/Measurements');

function SurveysDetailsView(survey) {
  var self = Ti.UI.createView({
    height : '140dip',
    width : '100%'
  });

  var labelsView = Ti.UI.createView ({
    layout : 'vertical',
    width : '80%',
    height : '100%',
    left : Measurements.PADDING_X_SMALL,
    backgroundFocusedColor : Palette.SECONDARY_COLOR,
    backgroundSelectedColor : Palette.SECONDARY_COLOR
  });

  var surveyNameLabel = Ti.UI.createLabel({
    text : survey.name,
    color : Palette.PRIMARY_COLOR,
    left : Measurements.PADDING_SMALL,
    top : Measurements.PADDING_SMALL,
    font : { fontSize :Measurements.FONT_BIG  }
  });

  var surveyDescriptionLabel = Ti.UI.createLabel({
    text : survey.description,
    color : Palette.PRIMARY_COLOR_LIGHT,
    left : Measurements.PADDING_SMALL,
    top : Measurements.PADDING_SMALL,
    font : { fontSize :Measurements.FONT_SMALL  }
  });

  var surveyInfoView = Ti.UI.createView({
    width : '100%'
  });

  var responseCountLabel = Ti.UI.createLabel({
    text : survey.incompleteResponseCount() + ' | ' +  survey.completeResponseCount(),
    color : Palette.PRIMARY_COLOR_LIGHT,
    right : Measurements.PADDING_SMALL,
    font : {
      fontSize : Measurements.FONT_MEDIUM }
  });
  var date = ((new Date(survey.expiry_date)).toDateString()).substring(4);

  var expiryDateLabel = Ti.UI.createLabel({
    text : 'Expires on: ' + date,
    color : Palette.PRIMARY_COLOR_LIGHT,
    left : Measurements.PADDING_SMALL,
    font : {
      fontSize : Measurements.FONT_MEDIUM }
  });

  var buttons = Ti.UI.createView({
    layout : 'vertical',
    height : '95%',
    width : '15%',
    right : Measurements.PADDING_X_SMALL
  });

  var addResponseButton = new ButtonView('+', {
    font : {
      fontSize : Measurements.FONT_BIG
    },
    width : '100%',
    height : '45%'
  });

  var syncResponseButton = new ButtonView('↻', {
    font : {
      fontSize : Measurements.FONT_BIG
    },
    width : '100%',
    height : '45%'
  });

  buttons.add(addResponseButton);
  buttons.add(new SeparatorView(Palette.SECONDARY_COLOR_LIGHT, Measurements.PADDING_SMALL));
  buttons.add(syncResponseButton);
  syncResponseButton.enabled = survey.responseCount() > 0;

  var activityIndicator = Ti.UI.Android.createProgressIndicator({
    message : 'Loading...',
    location : Ti.UI.Android.PROGRESS_INDICATOR_DIALOG,
    type : Ti.UI.Android.PROGRESS_INDICATOR_INDETERMINANT
  });
  self.add(activityIndicator);

  addResponseButton.addEventListener('click', function() {
    activityIndicator.show();
    ResponsesNewWindow(survey.id).open();
    activityIndicator.hide();
  });

  syncResponseButton.addEventListener('click', function() {
    self.fireEvent('SurveyDetailsView.sync_responses');
  });

  self.refresh = function() {
    responseCountLabel.setText(survey.incompleteResponseCount() + ' | ' +  survey.completeResponseCount());
    syncResponseButton.enabled = survey.responseCount() > 0;
  };

  labelsView.add(surveyNameLabel);
  labelsView.add(surveyDescriptionLabel);

  surveyInfoView.add(expiryDateLabel);
  surveyInfoView.add(responseCountLabel);

  labelsView.add(surveyInfoView);
  self.add(labelsView);
  self.add(buttons);
  return (self);
}

module.exports = SurveysDetailsView;
<commit_msg>Disable responseSync button if user is not logged in<commit_after>var ResponsesNewWindow = require('ui/handheld/android/ResponsesNewWindow');
var Survey = require('models/survey');
var Palette = require('ui/common/components/Palette');
var SeparatorView = require('ui/common/components/SeparatorView');
var ButtonView = require('ui/common/components/ButtonView');
var Measurements = require('ui/common/components/Measurements');
var loggedIn = require('helpers/LoginHelper').loggedIn;

function SurveysDetailsView(survey) {
  var self = Ti.UI.createView({
    height : '140dip',
    width : '100%'
  });

  var labelsView = Ti.UI.createView ({
    layout : 'vertical',
    width : '80%',
    height : '100%',
    left : Measurements.PADDING_X_SMALL,
    backgroundFocusedColor : Palette.SECONDARY_COLOR,
    backgroundSelectedColor : Palette.SECONDARY_COLOR
  });

  var surveyNameLabel = Ti.UI.createLabel({
    text : survey.name,
    color : Palette.PRIMARY_COLOR,
    left : Measurements.PADDING_SMALL,
    top : Measurements.PADDING_SMALL,
    font : { fontSize :Measurements.FONT_BIG  }
  });

  var surveyDescriptionLabel = Ti.UI.createLabel({
    text : survey.description,
    color : Palette.PRIMARY_COLOR_LIGHT,
    left : Measurements.PADDING_SMALL,
    top : Measurements.PADDING_SMALL,
    font : { fontSize :Measurements.FONT_SMALL  }
  });

  var surveyInfoView = Ti.UI.createView({
    width : '100%'
  });

  var responseCountLabel = Ti.UI.createLabel({
    text : survey.incompleteResponseCount() + ' | ' +  survey.completeResponseCount(),
    color : Palette.PRIMARY_COLOR_LIGHT,
    right : Measurements.PADDING_SMALL,
    font : {
      fontSize : Measurements.FONT_MEDIUM }
  });
  var date = ((new Date(survey.expiry_date)).toDateString()).substring(4);

  var expiryDateLabel = Ti.UI.createLabel({
    text : 'Expires on: ' + date,
    color : Palette.PRIMARY_COLOR_LIGHT,
    left : Measurements.PADDING_SMALL,
    font : {
      fontSize : Measurements.FONT_MEDIUM }
  });

  var buttons = Ti.UI.createView({
    layout : 'vertical',
    height : '95%',
    width : '15%',
    right : Measurements.PADDING_X_SMALL
  });

  var addResponseButton = new ButtonView('+', {
    font : {
      fontSize : Measurements.FONT_BIG
    },
    width : '100%',
    height : '45%'
  });

  var syncResponseButton = new ButtonView('↻', {
    font : {
      fontSize : Measurements.FONT_BIG
    },
    width : '100%',
    height : '45%'
  });

  var canSync = function() {
    Ti.API.info("Login Info" + loggedIn());
    return (survey.responseCount() > 0) && loggedIn();
  };

  buttons.add(addResponseButton);
  buttons.add(new SeparatorView(Palette.SECONDARY_COLOR_LIGHT, Measurements.PADDING_SMALL));
  buttons.add(syncResponseButton);
  syncResponseButton.enabled = canSync();

  var activityIndicator = Ti.UI.Android.createProgressIndicator({
    message : 'Loading...',
    location : Ti.UI.Android.PROGRESS_INDICATOR_DIALOG,
    type : Ti.UI.Android.PROGRESS_INDICATOR_INDETERMINANT
  });
  self.add(activityIndicator);

  addResponseButton.addEventListener('click', function() {
    activityIndicator.show();
    ResponsesNewWindow(survey.id).open();
    activityIndicator.hide();
  });

  syncResponseButton.addEventListener('click', function() {
    self.fireEvent('SurveyDetailsView.sync_responses');
  });

  self.refresh = function() {
    responseCountLabel.setText(survey.incompleteResponseCount() + ' | ' +  survey.completeResponseCount());
    syncResponseButton.enabled = canSync();
  };

  labelsView.add(surveyNameLabel);
  labelsView.add(surveyDescriptionLabel);

  surveyInfoView.add(expiryDateLabel);
  surveyInfoView.add(responseCountLabel);

  labelsView.add(surveyInfoView);
  self.add(labelsView);
  self.add(buttons);
  return (self);
}

module.exports = SurveysDetailsView;
<|endoftext|>


<commit_before>/*global pako*/
(function() {
    'use strict';

    window.embedInSandcastleTemplate = function(code, addExtraLine) {
        return 'function startup(Cesium) {\n' +
           '    \'use strict\';\n' +
           '//Sandcastle_Begin\n' +
           (addExtraLine ? '\n' : '') +
           code +
           '//Sandcastle_End\n' +
           '    Sandcastle.finishedLoading();\n' +
           '}\n' +
           'if (typeof Cesium !== \'undefined\') {\n' +
           '    startup(Cesium);\n' +
           '} else if (typeof require === \'function\') {\n' +
           '    require([\'Cesium\'], startup);\n' +
           '}\n';
    };
    window.decodeBase64Data = function(base64String) {
        // data stored in the hash as:
        // Base64 encoded, raw DEFLATE compressed JSON array where index 0 is code, index 1 is html
        // restore padding
        while (base64String.length % 4 !== 0) {
            base64String += '=';
        }
        var jsonString = pako.inflate(atob(base64String), { raw: true, to: 'string' });
        // we save a few bytes by omitting the leading [" and trailing "] since they are always the same
        jsonString = '["' + jsonString + '"]';
        var json = JSON.parse(jsonString);
        // index 0 is code, index 1 is html
        var code = json[0];
        var html = json[1];
        var baseHref = json[2];

        return {
            code : code,
            html : html,
            baseHref : baseHref
        };
    };
 }());
<commit_msg>Use requirejs in Sandcastle-helpers<commit_after>require({
  baseUrl: '../../Source',
  packages: [{
      name: 'ThirdParty',
      location: '../Apps/Sandcastle/ThirdParty'
    }]
  }, [
      'ThirdParty/pako.min'
    ], function(
        pako) {
    'use strict';

     window.embedInSandcastleTemplate = function(code, addExtraLine) {
        return 'function startup(Cesium) {\n' +
           '    \'use strict\';\n' +
           '//Sandcastle_Begin\n' +
           (addExtraLine ? '\n' : '') +
           code +
           '//Sandcastle_End\n' +
           '    Sandcastle.finishedLoading();\n' +
           '}\n' +
           'if (typeof Cesium !== \'undefined\') {\n' +
           '    startup(Cesium);\n' +
           '} else if (typeof require === \'function\') {\n' +
           '    require([\'Cesium\'], startup);\n' +
           '}\n';
    };
    window.decodeBase64Data = function(base64String) {
        // data stored in the hash as:
        // Base64 encoded, raw DEFLATE compressed JSON array where index 0 is code, index 1 is html
        // restore padding
        while (base64String.length % 4 !== 0) {
            base64String += '=';
        }
        var jsonString = pako.inflate(atob(base64String), { raw: true, to: 'string' });
        // we save a few bytes by omitting the leading [" and trailing "] since they are always the same
        jsonString = '["' + jsonString + '"]';
        var json = JSON.parse(jsonString);
        // index 0 is code, index 1 is html
        var code = json[0];
        var html = json[1];
        var baseHref = json[2];
         return {
            code : code,
            html : html,
            baseHref : baseHref
        };
    };
 });
<|endoftext|>