<commit_before>/* eslint-disable
    camelcase,
*/
const logger = require('logger-sharelatex')
const metrics = require('metrics-sharelatex')
const { EventEmitter } = require('events')
const OError = require('@overleaf/o-error')

const IdMap = new Map() // keep track of whether ids are from projects or docs
const RoomEvents = new EventEmitter() // emits {project,doc}-active and {project,doc}-empty events

// Manage socket.io rooms for individual projects and docs
//
// The first time someone joins a project or doc we emit a 'project-active' or
// 'doc-active' event.
//
// When the last person leaves a project or doc, we emit 'project-empty' or
// 'doc-empty' event.
//
// The pubsub side is handled by ChannelManager

module.exports = {
  joinProject(client, project_id, callback) {
    this.joinEntity(client, 'project', project_id, callback)
  },

  joinDoc(client, doc_id, callback) {
    this.joinEntity(client, 'doc', doc_id, callback)
  },

  leaveDoc(client, doc_id) {
    this.leaveEntity(client, 'doc', doc_id)
  },

  leaveProjectAndDocs(client) {
    // what rooms is this client in? we need to leave them all. socket.io
    // will cause us to leave the rooms, so we only need to manage our
    // channel subscriptions... but it will be safer if we leave them
    // explicitly, and then socket.io will just regard this as a client that
    // has not joined any rooms and do a final disconnection.
    const roomsToLeave = this._roomsClientIsIn(client)
    logger.log({ client: client.id, roomsToLeave }, 'client leaving project')
    for (const id of roomsToLeave) {
      const entity = IdMap.get(id)
      this.leaveEntity(client, entity, id)
    }
  },

  emitOnCompletion(promiseList, eventName) {
    Promise.all(promiseList)
      .then(() => RoomEvents.emit(eventName))
      .catch((err) => RoomEvents.emit(eventName, err))
  },

  eventSource() {
    return RoomEvents
  },

  joinEntity(client, entity, id, callback) {
    const beforeCount = this._clientsInRoom(client, id)
    // client joins room immediately but joinDoc request does not complete
    // until room is subscribed
    client.join(id)
    // is this a new room? if so, subscribe
    if (beforeCount === 0) {
      logger.log({ entity, id }, 'room is now active')
      RoomEvents.once(`${entity}-subscribed-${id}`, function (err) {
        // only allow the client to join when all the relevant channels have subscribed
        if (err) {
          OError.tag(err, 'error joining', { entity, id })
          return callback(err)
        }
        logger.log(
          { client: client.id, entity, id, beforeCount },
          'client joined new room and subscribed to channel'
        )
        callback(err)
      })
      RoomEvents.emit(`${entity}-active`, id)
      IdMap.set(id, entity)
      // keep track of the number of listeners
      metrics.gauge('room-listeners', RoomEvents.eventNames().length)
    } else {
      logger.log(
        { client: client.id, entity, id, beforeCount },
        'client joined existing room'
      )
      client.join(id)
      callback()
    }
  },

  leaveEntity(client, entity, id) {
    // Ignore any requests to leave when the client is not actually in the
    // room. This can happen if the client sends spurious leaveDoc requests
    // for old docs after a reconnection.
    // This can now happen all the time, as we skip the join for clients that
    //  disconnect before joinProject/joinDoc completed.
    if (!this._clientAlreadyInRoom(client, id)) {
      logger.log(
        { client: client.id, entity, id },
        'ignoring request from client to leave room it is not in'
      )
      return
    }
    client.leave(id)
    const afterCount = this._clientsInRoom(client, id)
    logger.log(
      { client: client.id, entity, id, afterCount },
      'client left room'
    )
    // is the room now empty? if so, unsubscribe
    if (!entity) {
      logger.error({ entity: id }, 'unknown entity when leaving with id')
      return
    }
    if (afterCount === 0) {
      logger.log({ entity, id }, 'room is now empty')
      RoomEvents.emit(`${entity}-empty`, id)
      IdMap.delete(id)
      metrics.gauge('room-listeners', RoomEvents.eventNames().length)
    }
  },

  // internal functions below, these access socket.io rooms data directly and
  // will need updating for socket.io v2

  // The below code makes some assumptions that are always true for v0
  // - we are using the base namespace '', so room names are '/<ENTITY>'
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/manager.js#L62
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/manager.js#L1018
  // - client.namespace is a Namespace
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/namespace.js#L204
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/socket.js#L40
  // - client.manager is a Manager
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/namespace.js#L204
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/socket.js#L41
  // - a Manager has
  //   - `.rooms={'NAMESPACE/ENTITY': []}` and
  //   - `.roomClients={'CLIENT_ID': {'...': true}}`
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/manager.js#L287-L288
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/manager.js#L444-L455

  _clientsInRoom(client, room) {
    const clients = client.manager.rooms['/' + room] || []
    return clients.length
  },

  _roomsClientIsIn(client) {
    const rooms = client.manager.roomClients[client.id] || {}
    return (
      Object.keys(rooms)
        // drop the namespace
        .filter((room) => room !== '')
        // room names are composed as '<NAMESPACE>/<ROOM>' and the default
        //  namespace is empty (see comments above), just drop the '/'
        .map((fullRoomPath) => fullRoomPath.slice(1))
    )
  },

  _clientAlreadyInRoom(client, room) {
    const rooms = client.manager.roomClients[client.id] || {}
    return !!rooms['/' + room]
  }
}
<commit_msg>[RoomManager] drop duplicate joining of entities<commit_after>/* eslint-disable
    camelcase,
*/
const logger = require('logger-sharelatex')
const metrics = require('metrics-sharelatex')
const { EventEmitter } = require('events')
const OError = require('@overleaf/o-error')

const IdMap = new Map() // keep track of whether ids are from projects or docs
const RoomEvents = new EventEmitter() // emits {project,doc}-active and {project,doc}-empty events

// Manage socket.io rooms for individual projects and docs
//
// The first time someone joins a project or doc we emit a 'project-active' or
// 'doc-active' event.
//
// When the last person leaves a project or doc, we emit 'project-empty' or
// 'doc-empty' event.
//
// The pubsub side is handled by ChannelManager

module.exports = {
  joinProject(client, project_id, callback) {
    this.joinEntity(client, 'project', project_id, callback)
  },

  joinDoc(client, doc_id, callback) {
    this.joinEntity(client, 'doc', doc_id, callback)
  },

  leaveDoc(client, doc_id) {
    this.leaveEntity(client, 'doc', doc_id)
  },

  leaveProjectAndDocs(client) {
    // what rooms is this client in? we need to leave them all. socket.io
    // will cause us to leave the rooms, so we only need to manage our
    // channel subscriptions... but it will be safer if we leave them
    // explicitly, and then socket.io will just regard this as a client that
    // has not joined any rooms and do a final disconnection.
    const roomsToLeave = this._roomsClientIsIn(client)
    logger.log({ client: client.id, roomsToLeave }, 'client leaving project')
    for (const id of roomsToLeave) {
      const entity = IdMap.get(id)
      this.leaveEntity(client, entity, id)
    }
  },

  emitOnCompletion(promiseList, eventName) {
    Promise.all(promiseList)
      .then(() => RoomEvents.emit(eventName))
      .catch((err) => RoomEvents.emit(eventName, err))
  },

  eventSource() {
    return RoomEvents
  },

  joinEntity(client, entity, id, callback) {
    const beforeCount = this._clientsInRoom(client, id)
    // client joins room immediately but joinDoc request does not complete
    // until room is subscribed
    client.join(id)
    // is this a new room? if so, subscribe
    if (beforeCount === 0) {
      logger.log({ entity, id }, 'room is now active')
      RoomEvents.once(`${entity}-subscribed-${id}`, function (err) {
        // only allow the client to join when all the relevant channels have subscribed
        if (err) {
          OError.tag(err, 'error joining', { entity, id })
          return callback(err)
        }
        logger.log(
          { client: client.id, entity, id, beforeCount },
          'client joined new room and subscribed to channel'
        )
        callback(err)
      })
      RoomEvents.emit(`${entity}-active`, id)
      IdMap.set(id, entity)
      // keep track of the number of listeners
      metrics.gauge('room-listeners', RoomEvents.eventNames().length)
    } else {
      logger.log(
        { client: client.id, entity, id, beforeCount },
        'client joined existing room'
      )
      callback()
    }
  },

  leaveEntity(client, entity, id) {
    // Ignore any requests to leave when the client is not actually in the
    // room. This can happen if the client sends spurious leaveDoc requests
    // for old docs after a reconnection.
    // This can now happen all the time, as we skip the join for clients that
    //  disconnect before joinProject/joinDoc completed.
    if (!this._clientAlreadyInRoom(client, id)) {
      logger.log(
        { client: client.id, entity, id },
        'ignoring request from client to leave room it is not in'
      )
      return
    }
    client.leave(id)
    const afterCount = this._clientsInRoom(client, id)
    logger.log(
      { client: client.id, entity, id, afterCount },
      'client left room'
    )
    // is the room now empty? if so, unsubscribe
    if (!entity) {
      logger.error({ entity: id }, 'unknown entity when leaving with id')
      return
    }
    if (afterCount === 0) {
      logger.log({ entity, id }, 'room is now empty')
      RoomEvents.emit(`${entity}-empty`, id)
      IdMap.delete(id)
      metrics.gauge('room-listeners', RoomEvents.eventNames().length)
    }
  },

  // internal functions below, these access socket.io rooms data directly and
  // will need updating for socket.io v2

  // The below code makes some assumptions that are always true for v0
  // - we are using the base namespace '', so room names are '/<ENTITY>'
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/manager.js#L62
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/manager.js#L1018
  // - client.namespace is a Namespace
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/namespace.js#L204
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/socket.js#L40
  // - client.manager is a Manager
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/namespace.js#L204
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/socket.js#L41
  // - a Manager has
  //   - `.rooms={'NAMESPACE/ENTITY': []}` and
  //   - `.roomClients={'CLIENT_ID': {'...': true}}`
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/manager.js#L287-L288
  //   https://github.com/socketio/socket.io/blob/e4d61b1be65ac3313a85da111a46777aa8d4aae3/lib/manager.js#L444-L455

  _clientsInRoom(client, room) {
    const clients = client.manager.rooms['/' + room] || []
    return clients.length
  },

  _roomsClientIsIn(client) {
    const rooms = client.manager.roomClients[client.id] || {}
    return (
      Object.keys(rooms)
        // drop the namespace
        .filter((room) => room !== '')
        // room names are composed as '<NAMESPACE>/<ROOM>' and the default
        //  namespace is empty (see comments above), just drop the '/'
        .map((fullRoomPath) => fullRoomPath.slice(1))
    )
  },

  _clientAlreadyInRoom(client, room) {
    const rooms = client.manager.roomClients[client.id] || {}
    return !!rooms['/' + room]
  }
}
<|endoftext|>


<commit_before>'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Formio = undefined;

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _formiojs = require('formiojs');

var _formiojs2 = _interopRequireDefault(_formiojs);

var _formioUtils = require('formio-utils');

var _formioUtils2 = _interopRequireDefault(_formioUtils);

var _components = require('../components');

var _clone = require('lodash/clone');

var _clone2 = _interopRequireDefault(_clone);

require('../components/FormComponents');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

// TODO: We should have a better way of initializing form components.

var Formio = exports.Formio = _react2.default.createClass({
  displayName: 'Formio',
  getInitialState: function getInitialState() {
    this.unmounting = false;
    if (this.props.submission && this.props.submission.data) {
      this.data = (0, _clone2.default)(this.props.submission.data);
    }
    return {
      form: this.props.form || {},
      submission: this.props.submission || {},
      submissions: this.props.submissions || [],
      alerts: [],
      isLoading: this.props.form ? false : true,
      isSubmitting: false,
      isValid: true,
      isPristine: true
    };
  },
  getDefaultProps: function getDefaultProps() {
    return {
      readOnly: false,
      formAction: false,
      options: {}
    };
  },
  componentWillMount: function componentWillMount() {
    if (this.props.submission && this.props.submission.data) {
      this.data = (0, _clone2.default)(this.props.submission.data);
    } else {
      this.data = {};
    }
    this.inputs = {};
    if (this.props.src) {
      this.formio = new _formiojs2.default(this.props.src);
      this.formio.loadForm().then(function (form) {
        if (typeof this.props.onFormLoad === 'function') {
          this.props.onFormLoad(form);
        }
        this.setState({
          form: form,
          isLoading: false
        }, this.validate);
      }.bind(this));
      if (this.formio.submissionId) {
        this.formio.loadSubmission().then(function (submission) {
          if (typeof this.props.onSubmissionLoad === 'function') {
            this.props.onSubmissionLoad(submission);
          }
          this.data = (0, _clone2.default)(submission.data);
          this.setState({
            submission: submission
          }, this.validate);
        }.bind(this));
      }
    } else if (this.props.form) {
      this.validate();
    }
  },
  componentWillUnmount: function componentWillUnmount() {
    this.unmounting = true;
  },
  componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
    if (nextProps.form !== this.props.form) {
      this.setState({
        form: nextProps.form
      });
    }
    if (nextProps.submission !== this.props.submission) {
      if (nextProps.submission && nextProps.submission.data) {
        this.data = (0, _clone2.default)(nextProps.submission.data);
      }
      this.setState({
        submission: nextProps.submission
      });
    }
  },
  attachToForm: function attachToForm(component) {
    this.inputs[component.props.component.key] = component;
    this.validate();
  },
  detachFromForm: function detachFromForm(component) {
    var _this = this;

    var sendChange = false;
    // Don't detach when the whole form is unmounting.
    if (this.unmounting) {
      return;
    }
    delete this.inputs[component.props.component.key];
    if (!component.props.component.hasOwnProperty('clearOnHide') || component.props.component.clearOnHide !== false) {
      if (this.data && this.data.hasOwnProperty(component.props.component.key)) {
        delete this.data[component.props.component.key];
        sendChange = true;
      }
    }
    this.validate(function () {
      if (sendChange) {
        _this.externalChange(component);
      }
    });
  },
  onEvent: function onEvent(event) {
    if (typeof this.props.onEvent === 'function') {
      this.props.onEvent.apply(null, [event, this.data].concat(_toConsumableArray(Array.prototype.slice.call(arguments, 1, arguments.length))));
    }
  },
  externalChange: function externalChange(component, context) {
    if (typeof this.props.onChange === 'function' && !this.props.readOnly) {
      this.props.onChange({ data: this.data }, component, context);
    }
  },
  onChange: function onChange(component) {
    var _this2 = this;

    var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    // Datagrids and containers are different.
    if (context.hasOwnProperty('datagrid')) {
      this.data[context.datagrid.props.component.key] = context.datagrid.state.value;
    } else if (context.hasOwnProperty('container')) {
      this.data[context.container.props.component.key] = context.container.state.value;
    } else {
      if (component.state.value === null) {
        delete this.data[component.props.component.key];
      } else {
        this.data[component.props.component.key] = component.state.value;
      }
    }
    this.validate(function () {
      _this2.externalChange(component, context);
    });
    // If a field is no longer pristine, the form is no longer pristine.
    if (!component.state.isPristine && this.state.isPristine) {
      this.setState({
        isPristine: false
      });
    }
  },
  validate: function validate(next) {
    var allIsValid = true;

    var inputs = this.inputs;
    Object.keys(inputs).forEach(function (name) {
      if (!inputs[name].state.isValid) {
        allIsValid = false;
      }
    });

    this.setState(function (previousState) {
      return previousState.isValid = allIsValid;
    }, next);

    return allIsValid;
  },
  clearHiddenData: function clearHiddenData(component) {
    var _this3 = this;

    if (!component.hasOwnProperty('clearOnHide') || component.clearOnHide !== false) {
      if (this.data.hasOwnProperty(component.key)) {
        delete this.data[component.key];
        this.externalChange({ props: { component: component }, state: { isPristine: true, value: null } });
      }
    }
    if (component.hasOwnProperty('components')) {
      component.components.forEach(function (component) {
        _this3.clearHiddenData(component);
      });
    }
    if (component.hasOwnProperty('columns')) {
      component.columns.forEach(function (column) {
        column.components.forEach(function (component) {
          _this3.clearHiddenData(component);
        });
      });
    }
    if (component.hasOwnProperty('rows') && Array.isArray(component.rows)) {
      component.rows.forEach(function (column) {
        column.forEach(function (component) {
          _this3.clearHiddenData(component);
        });
      });
    }
  },
  checkConditional: function checkConditional(component) {
    var row = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    var show = _formioUtils2.default.checkCondition(component, row, this.data);

    // If element is hidden, remove any values already on the form (this can happen when data is loaded into the form
    // and the field is initially hidden.
    if (!show) {
      // Recursively delete data for all components under this component.
      this.clearHiddenData(component);
    }

    return show;
  },
  isDisabled: function isDisabled(component, data) {
    return this.props.readOnly || Array.isArray(this.props.disableComponents) && this.props.disableComponents.indexOf(component.key) !== -1 || component.disabled;
  },
  showAlert: function showAlert(type, message, clear) {
    this.setState(function (previousState) {
      if (clear) {
        previousState.alerts = [];
      }
      previousState.alerts = previousState.alerts.concat({ type: type, message: message });
      return previousState;
    });
  },
  setPristine: function setPristine(isPristine) {
    // Mark all inputs as dirty so errors show.
    Object.keys(this.inputs).forEach(function (name) {
      this.inputs[name].setState({
        isPristine: isPristine
      });
      if (typeof this.inputs[name].setPristine === 'function') {
        this.inputs[name].setPristine(isPristine);
      }
    }.bind(this));
    this.setState({
      isPristine: isPristine
    });
  },
  onSubmit: function onSubmit(event) {
    event.preventDefault();

    this.setPristine(false);

    if (!this.state.isValid) {
      this.showAlert('danger', 'Please fix the following errors before submitting.', true);
      return;
    }

    this.setState({
      alerts: [],
      isSubmitting: true
    });
    var sub = this.state.submission;
    sub.data = (0, _clone2.default)(this.data);

    var request;
    var method;
    // Do the submit here.
    if (this.state.form.action) {
      method = this.state.submission._id ? 'put' : 'post';
      request = _formiojs2.default.request(this.state.form.action, method, sub);
    } else if (this.formio) {
      request = this.formio.saveSubmission(sub);
    }
    if (request) {
      request.then(function (submission) {
        if (typeof this.props.onFormSubmit === 'function') {
          this.props.onFormSubmit(submission);
        }
        this.setState({
          isSubmitting: false,
          alerts: [{
            type: 'success',
            message: 'Submission was ' + (method === 'put' ? 'updated' : 'created')
          }]
        });
      }.bind(this)).catch(function (response) {
        if (typeof this.props.onFormError === 'function') {
          this.props.onFormError(response);
        }
        this.setState({
          isSubmitting: false
        });
        if (response.hasOwnProperty('name') && response.name === 'ValidationError') {
          response.details.forEach(function (detail) {
            if (this.inputs[detail.path]) {
              this.inputs[detail.path].setState({
                isValid: false,
                isPristine: false,
                errorMessage: detail.message
              });
            }
          }.bind(this));
        } else {
          this.showAlert('danger', response);
        }
      }.bind(this));
    } else {
      if (typeof this.props.onFormSubmit === 'function') {
        this.props.onFormSubmit(sub);
      }
      this.setState({
        alerts: [],
        isSubmitting: false
      });
    }
  },
  resetForm: function resetForm() {
    this.setState(function (previousState) {
      for (var key in previousState.submission.data) {
        delete previousState.submission.data[key];
      }
      return previousState;
    });
  },
  render: function render() {
    var components = this.state.form.components || [];
    var loading = this.state.isLoading ? _react2.default.createElement('i', { id: 'formio-loading', className: 'glyphicon glyphicon-refresh glyphicon-spin' }) : '';
    var alerts = this.state.alerts.map(function (alert, index) {
      var className = 'alert alert-' + alert.type;
      return _react2.default.createElement(
        'div',
        { className: className, role: 'alert', key: index },
        alert.message
      );
    });

    return _react2.default.createElement(
      'form',
      { role: 'form', name: 'formioForm', onSubmit: this.onSubmit },
      loading,
      alerts,
      _react2.default.createElement(_components.FormioComponentsList, {
        components: components,
        values: this.data,
        options: this.props.options,
        attachToForm: this.attachToForm,
        detachFromForm: this.detachFromForm,
        isSubmitting: this.state.isSubmitting,
        isFormValid: this.state.isValid,
        onElementRender: this.props.onElementRender,
        resetForm: this.resetForm,
        formio: this.formio,
        data: this.data,
        onChange: this.onChange,
        onEvent: this.onEvent,
        isDisabled: this.isDisabled,
        checkConditional: this.checkConditional,
        showAlert: this.showAlert,
        formPristine: this.state.isPristine
      })
    );
  }
});<commit_msg>Rebuild.<commit_after>'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Formio = undefined;

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _full = require('formiojs/full');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Formio = exports.Formio = function (_Component) {
  _inherits(Formio, _Component);

  function Formio() {
    var _ref;

    var _temp, _this, _ret;

    _classCallCheck(this, Formio);

    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }

    return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Formio.__proto__ || Object.getPrototypeOf(Formio)).call.apply(_ref, [this].concat(args))), _this), _initialiseProps.call(_this), _temp), _possibleConstructorReturn(_this, _ret);
  }

  return Formio;
}(_react.Component);

Formio.defaultProps = {
  options: {}
};
Formio.propTypes = {
  src: _propTypes2.default.string,
  form: _propTypes2.default.object,
  submission: _propTypes2.default.object,
  options: _propTypes2.default.shape({
    readOnly: _propTypes2.default.boolean,
    noAlerts: _propTypes2.default.boolean,
    i18n: _propTypes2.default.string,
    template: _propTypes2.default.string
  }),
  onPrevPage: _propTypes2.default.func,
  onNextPage: _propTypes2.default.func,
  onChange: _propTypes2.default.func,
  onCustomEvent: _propTypes2.default.func,
  onSubmit: _propTypes2.default.func,
  onSubmitDone: _propTypes2.default.func,
  onError: _propTypes2.default.func,
  onRender: _propTypes2.default.func
};

var _initialiseProps = function _initialiseProps() {
  var _this2 = this;

  this.componentDidMount = function () {
    var _props = _this2.props,
        options = _props.options,
        src = _props.src,
        form = _props.form;

    if (src) {
      _this2.createPromise = _full.Formio.createForm(_this2.element, src, options).then(function (formio) {
        _this2.formio = formio;
        _this2.formio.src = src;
      });
    }
    if (form) {
      _this2.createPromise = _full.Formio.createForm(_this2.element, form, options).then(function (formio) {
        _this2.formio = formio;
        _this2.formio.form = form;
      });
    }

    _this2.initializeFormio();
  };

  this.componentWillUnmount = function () {
    if (_this2.formio !== undefined) {
      _this2.formio.destroy(true);
    }
  };

  this.initializeFormio = function () {
    var submission = _this2.props.submission;

    if (_this2.createPromise) {
      _this2.createPromise.then(function () {
        if (submission) {
          _this2.formio.submission = submission;
        }
        //this.formio.hideComponents([]); (From Components.js)
        _this2.formio.on('prevPage', _this2.emit('onPrevPage'));
        _this2.formio.on('nextPage', _this2.emit('onNextPage'));
        _this2.formio.on('change', _this2.emit('onChange'));
        _this2.formio.on('customEvent', _this2.emit('onCustomEvent'));
        _this2.formio.on('submit', _this2.emit('onSubmit'));
        _this2.formio.on('submitDone', _this2.emit('onSubmitDone'));
        _this2.formio.on('error', _this2.emit('onError'));
        _this2.formio.on('render', _this2.emit('onRender'));
      });
    }
  };

  this.componentWillReceiveProps = function (nextProps) {
    var _props2 = _this2.props,
        options = _props2.options,
        src = _props2.src,
        form = _props2.form,
        submission = _props2.submission;

    if (src !== nextProps.src) {
      _this2.createPromise = _full.Formio.createForm(_this2.element, nextProps.src, options).then(function (formio) {
        _this2.formio = formio;
        _this2.formio.src = nextProps.src;
      });
      _this2.initializeFormio();
    }
    if (form !== nextProps.form) {
      _this2.createPromise = _full.Formio.createForm(_this2.element, nextProps.form, options).then(function (formio) {
        _this2.formio = formio;
        _this2.formio.form = form;
      });
      _this2.initializeFormio();
    }

    if (submission !== nextProps.submission) {
      _this2.formio.submission = nextProps.submission;
    }
  };

  this.render = function () {
    return _react2.default.createElement('div', { ref: function ref(element) {
        return _this2.element = element;
      } });
  };

  this.emit = function (funcName) {
    return function () {
      if (_this2.props.hasOwnProperty(funcName) && typeof _this2.props[funcName] === 'function') {
        var _props3;

        (_props3 = _this2.props)[funcName].apply(_props3, arguments);
      }
    };
  };
};<|endoftext|>


<commit_before>const mongoose = require('mongoose');
const Producer = mongoose.model('Producer');
const Record = mongoose.model('ConsolidatedRecord');

exports.list = function (req, res, next) {
    Producer
        .find()
        .lean()
        .exec(function (err, producers) {
            if (err) return next(err);
            res.send(producers);
        });
};

exports.fetch = function (req, res, next, id) {
    Producer.findById(id, function (err, producer) {
        if (err) return next(err);
        if (!producer) return res.sendStatus(404);
        req.producer = producer;
        next();
    });
};

exports.associate = function (req, res, next) {
    Producer.create({ _id: req.body._id, associatedTo: req.organization._id }, function (err, producer) {
        if (err) return next(err);
        res.send(producer);
    });
};

exports.dissociate = function (req, res, next) {
    if (!req.producer.associatedTo.equals(req.organization._id)) return res.sendStatus(404);
    Producer.findByIdAndRemove(req.producer._id, function (err) {
        if (err) return next(err);
        res.sendStatus(200);
    });
};

const facetEligibilityCondition = { $all: [
    { $elemMatch: { name: 'availability', value: 'yes' } },
    { $elemMatch: { name: 'opendata', value: 'yes' } }
] };

exports.listByOrganization = function (req, res, next) {
  Record
    .distinct('organizations', {
      facets: facetEligibilityCondition,
      catalogs: { $in: req.organization.sourceCatalogs }
    })
    .exec()
    .then(eligibleProducersNames => {
      return Producer.find({ _id: { $in: eligibleProducersNames } }).lean().exec()
        .then(associatedProducers => {
          const associatedProducersNames = associatedProducers.map(ap => ap._id);
          const producers = associatedProducers;
          eligibleProducersNames.forEach(eligibleProducerName => {
            if (!associatedProducersNames.includes(eligibleProducerName));
            producers.push({ _id: eligibleProducerName });
          });
          return producers;
        });
    })
    .then(producers => res.send(producers))
    .catch(next);
};
<commit_msg>Ensure producer dissociation return 204<commit_after>const mongoose = require('mongoose');
const Producer = mongoose.model('Producer');
const Record = mongoose.model('ConsolidatedRecord');

exports.list = function (req, res, next) {
    Producer
        .find()
        .lean()
        .exec(function (err, producers) {
            if (err) return next(err);
            res.send(producers);
        });
};

exports.fetch = function (req, res, next, id) {
    Producer.findById(id, function (err, producer) {
        if (err) return next(err);
        if (!producer) return res.sendStatus(404);
        req.producer = producer;
        next();
    });
};

exports.associate = function (req, res, next) {
    Producer.create({ _id: req.body._id, associatedTo: req.organization._id }, function (err, producer) {
        if (err) return next(err);
        res.send(producer);
    });
};

exports.dissociate = function (req, res, next) {
    if (!req.producer.associatedTo.equals(req.organization._id)) return res.sendStatus(404);
    Producer.findByIdAndRemove(req.producer._id, function (err) {
        if (err) return next(err);
        res.status(204).end();
    });
};

const facetEligibilityCondition = { $all: [
    { $elemMatch: { name: 'availability', value: 'yes' } },
    { $elemMatch: { name: 'opendata', value: 'yes' } }
] };

exports.listByOrganization = function (req, res, next) {
  Record
    .distinct('organizations', {
      facets: facetEligibilityCondition,
      catalogs: { $in: req.organization.sourceCatalogs }
    })
    .exec()
    .then(eligibleProducersNames => {
      return Producer.find({ _id: { $in: eligibleProducersNames } }).lean().exec()
        .then(associatedProducers => {
          const associatedProducersNames = associatedProducers.map(ap => ap._id);
          const producers = associatedProducers;
          eligibleProducersNames.forEach(eligibleProducerName => {
            if (!associatedProducersNames.includes(eligibleProducerName));
            producers.push({ _id: eligibleProducerName });
          });
          return producers;
        });
    })
    .then(producers => res.send(producers))
    .catch(next);
};
<|endoftext|>


<commit_before>
import tables from '../../database/tables'

export const tableNames = tables

export const tableKeys = {
  users: {
    hash: 'id',
    range: null
  },
  userLevels: {
    hash: 'id',
    range: null
  },
  charities: {
    hash: 'id',
    range: null
  },
  vcDonationLog: {
    hash: 'id',
    range: null
  },
  backgroundImages: {
    hash: 'id',
    range: null
  },
  widgets: {
    hash: 'id',
    range: null
  },
  userWidgets: {
    hash: 'userId',
    range: 'widgetId'
  },
  referralDataLog: {
    hash: 'id',
    range: null
  }
}

export const tableFixtureFileNames = {
  users: 'Users.json',
  userLevels: '',
  charities: '',
  vcDonationLog: '',
  backgroundImages: '',
  widgets: 'Widgets.json',
  userWidgets: 'UserWidgets.json',
  referralDataLog: ''
}
<commit_msg>Add more fixture file info.<commit_after>
import tables from '../../database/tables'

export const tableNames = tables

export const tableKeys = {
  users: {
    hash: 'id',
    range: null
  },
  userLevels: {
    hash: 'id',
    range: null
  },
  charities: {
    hash: 'id',
    range: null
  },
  vcDonationLog: {
    hash: 'id',
    range: null
  },
  backgroundImages: {
    hash: 'id',
    range: null
  },
  widgets: {
    hash: 'id',
    range: null
  },
  userWidgets: {
    hash: 'userId',
    range: 'widgetId'
  },
  referralDataLog: {
    hash: 'id',
    range: null
  }
}

export const tableFixtureFileNames = {
  users: 'Users.json',
  userLevels: 'UserLevels.json',
  charities: 'CharityData.json',
  vcDonationLog: 'VcDonationLog.json',
  backgroundImages: 'BackgroundImages.json',
  widgets: 'Widgets.json',
  userWidgets: 'UserWidgets.json',
  referralDataLog: ''
}
<|endoftext|>


<commit_before>var grunt = require('grunt');

module.exports = {
  production: {
    options: {
      baseUrl: 'tmp',
      // mainConfigFile: 'tmp/main.build.js', // wont work :/ see TODO: remove build duplication
      name: '../bower_components/almond/almond',
      include: ['main'],
      exclude: ['coffee-script'],
      stubModules: ['cs'],
      out: 'dist/main.js',
      removeCombined: true,
      findNestedDependencies: true,
      optimize: 'uglify2',
      paths: {<% if (!useZepto) { %>
        'jquery': '../bower_components/jquery/jquery',<% } %><% if (useZepto) { %>
        'zepto': '../bower_components/zepto/zepto',<% } %>
        'underscore': '../bower_components/underscore/underscore',
        'handlebars': '../bower_components/handlebars/handlebars',
        'backbone': '../bower_components/backbone/backbone',
        'thorax': '../bower_components/thorax/thorax',
        'coffee-script': '../bower_components/coffee-script/index',
        'cs': '../bower_components/require-cs/cs',
        'text': '../bower_components/text/text',
        'hbs': '../bower_components/requirejs-hbs/hbs'
      },
      shim: {
        'handlebars': {
          exports: 'Handlebars'
        },
        'backbone': {
          exports: 'Backbone',<% if (useZepto) { %>
          deps: ['zepto', 'underscore']<% } else { %>
          deps: ['jquery', 'underscore']<% } %>
        },
        'underscore': {
          exports: '_'
        },
        'thorax': {
          exports: 'Thorax',
          deps: ['handlebars', 'backbone']
        }<% if (useZepto) { %>,
        'zepto': {
          exports: '$'
        }<% } %>
      }
    }
  }
};<commit_msg>added to requirejs.js as requested<commit_after>var grunt = require('grunt');

module.exports = {
  production: {
    options: {
      baseUrl: 'tmp',
      // mainConfigFile: 'tmp/main.build.js', // wont work :/ see TODO: remove build duplication
      name: '../bower_components/almond/almond',
      include: ['main'],
      exclude: ['coffee-script'],
      stubModules: ['cs'],
      out: 'dist/main.js',
      removeCombined: true,
      findNestedDependencies: true,
      optimize: 'uglify2',
      paths: {<% if (!useZepto) { %>
        'jquery': '../bower_components/jquery/jquery',<% } %><% if (useZepto) { %>
        'zepto': '../bower_components/zepto/zepto',<% } %>
        'underscore': '../bower_components/underscore/underscore',
        'handlebars': '../bower_components/handlebars/handlebars',
        'backbone': '../bower_components/backbone/backbone',
        'thorax': '../bower_components/thorax/thorax',
        'coffee-script': '../bower_components/coffee-script/index',
        'cs': '../bower_components/require-cs/cs',
        'text': '../bower_components/text/text',
        'hbs': '../bower_components/requirejs-hbs/hbs',
        'localstorage': '../bower_components/backbone.localStorage/backbone.localstorage'
      },
      shim: {
        'handlebars': {
          exports: 'Handlebars'
        },
        'backbone': {
          exports: 'Backbone',<% if (useZepto) { %>
          deps: ['zepto', 'underscore']<% } else { %>
          deps: ['jquery', 'underscore']<% } %>
        },
        'underscore': {
          exports: '_'
        },
        'thorax': {
          exports: 'Thorax',
          deps: ['handlebars', 'backbone']
        }<% if (useZepto) { %>,
        'zepto': {
          exports: '$'
        }<% } %>,
        'localstorage': {
          deps: ['backbone']
        }
      }
    }
  }
};
<|endoftext|>


<commit_before>import * as React from 'react';
import { addDecorator, configure } from '@storybook/react';
import { withKnobs, boolean, optionsKnob } from '@storybook/addon-knobs';
import classnames from 'classnames';
import * as styles from './styles.scss';
import messages from '../_locales/en/messages.json';
import { I18n } from '../sticker-creator/util/i18n';
import { ClassyProvider } from '../ts/components/PopperRootContext';

const optionsConfig = {
  display: 'inline-radio',
};

const makeThemeKnob = pane =>
  optionsKnob(
    `${pane} Pane Theme`,
    { Light: '', Dark: classnames('dark-theme', styles.darkTheme) },
    '',
    optionsConfig,
    `${pane} Pane`
  );

const makeDeviceThemeKnob = pane =>
  optionsKnob(
    `${pane} Pane Device Theme`,
    { Android: '', iOS: 'ios-theme' },
    '',
    optionsConfig,
    `${pane} Pane`
  );

const makeModeKnob = pane =>
  optionsKnob(
    `${pane} Pane Mode`,
    { Mouse: 'mouse-mode', Keyboard: 'keyboard-mode' },
    'mouse-mode',
    optionsConfig,
    `${pane} Pane`
  );

addDecorator(withKnobs);

addDecorator((storyFn /* , context */) => {
  const contents = storyFn();
  const firstPaneTheme = makeThemeKnob('First');
  const firstPaneDeviceTheme = makeDeviceThemeKnob('First');
  const firstPaneMode = makeModeKnob('First');

  const secondPane = boolean('Second Pane Active', false, 'Second Pane');

  const secondPaneTheme = makeThemeKnob('Second');
  const secondPaneDeviceTheme = makeDeviceThemeKnob('Second');
  const secondPaneMode = makeModeKnob('Second');

  // Adding it to the body as well so that we can cover modals and other
  // components that are rendered outside of this decorator container
  if (firstPaneTheme === '') {
    document.body.classList.remove('dark-theme');
  } else {
    document.body.classList.add('dark-theme');
  }

  if (firstPaneDeviceTheme === '') {
    document.body.classList.remove('ios-theme');
  } else {
    document.body.classList.add('ios-theme');
  }

  if (firstPaneMode === 'mouse-mode') {
    document.body.classList.remove('keyboard-mode');
    document.body.classList.add('mouse-mode');
  } else {
    document.body.classList.remove('mouse-mode');
    document.body.classList.add('keyboard-mode');
  }

  return (

      <ClassyProvider themes={['dark']}>

          {contents}

      </ClassyProvider>
      {secondPane ? (

          {contents}

      ) : null}

  );
});

// Hack to enable hooks in stories: https://github.com/storybookjs/storybook/issues/5721#issuecomment-473869398
addDecorator(Story => <Story />);

addDecorator(story => <I18n messages={messages}>{story()}</I18n>);

configure(() => {
  // Load sticker creator stories
  const stickerCreatorContext = require.context(
    '../sticker-creator',
    true,
    /\.stories\.tsx?$/
  );
  stickerCreatorContext.keys().forEach(f => stickerCreatorContext(f));
  // Load main app stories
  const tsComponentsContext = require.context(
    '../ts/components',
    true,
    /\.stories.tsx?$/
  );
  tsComponentsContext.keys().forEach(f => tsComponentsContext(f));
}, module);
<commit_msg>Storybook: persist pane knob values in localstorage<commit_after>import * as React from 'react';
import { addDecorator, configure } from '@storybook/react';
import { withKnobs, boolean, optionsKnob } from '@storybook/addon-knobs';
import classnames from 'classnames';
import * as styles from './styles.scss';
import messages from '../_locales/en/messages.json';
import { I18n } from '../sticker-creator/util/i18n';
import { ClassyProvider } from '../ts/components/PopperRootContext';

const optionsConfig = {
  display: 'inline-radio',
};

const persistKnob = id => knob => {
  const value = knob(localStorage.getItem(id));
  localStorage.setItem(id, value);
  return value;
};

const makeThemeKnob = pane =>
  persistKnob(`${pane}-pane-theme`)(localValue =>
    optionsKnob(
      `${pane} Pane Theme`,
      { Light: '', Dark: classnames('dark-theme', styles.darkTheme) },
      localValue || '',
      optionsConfig,
      `${pane} Pane`
    )
  );

const makeDeviceThemeKnob = pane =>
  persistKnob(`${pane}-pane-device-theme`)(localValue =>
    optionsKnob(
      `${pane} Pane Device Theme`,
      { Android: '', iOS: 'ios-theme' },
      localValue || '',
      optionsConfig,
      `${pane} Pane`
    )
  );

const makeModeKnob = pane =>
  persistKnob(`${pane}-pane-mode`)(localValue =>
    optionsKnob(
      `${pane} Pane Mode`,
      { Mouse: 'mouse-mode', Keyboard: 'keyboard-mode' },
      localValue || 'mouse-mode',
      optionsConfig,
      `${pane} Pane`
    )
  );

addDecorator(withKnobs);

addDecorator((storyFn /* , context */) => {
  const contents = storyFn();
  const firstPaneTheme = makeThemeKnob('First');
  const firstPaneDeviceTheme = makeDeviceThemeKnob('First');
  const firstPaneMode = makeModeKnob('First');

  const secondPane = persistKnob('second-pane-active')(localValue =>
    boolean('Second Pane Active', localValue !== 'false', 'Second Pane')
  );

  const secondPaneTheme = makeThemeKnob('Second');
  const secondPaneDeviceTheme = makeDeviceThemeKnob('Second');
  const secondPaneMode = makeModeKnob('Second');

  // Adding it to the body as well so that we can cover modals and other
  // components that are rendered outside of this decorator container
  if (firstPaneTheme === '') {
    document.body.classList.remove('dark-theme');
  } else {
    document.body.classList.add('dark-theme');
  }

  if (firstPaneDeviceTheme === '') {
    document.body.classList.remove('ios-theme');
  } else {
    document.body.classList.add('ios-theme');
  }

  if (firstPaneMode === 'mouse-mode') {
    document.body.classList.remove('keyboard-mode');
    document.body.classList.add('mouse-mode');
  } else {
    document.body.classList.remove('mouse-mode');
    document.body.classList.add('keyboard-mode');
  }

  return (

      <ClassyProvider themes={['dark']}>

          {contents}

      </ClassyProvider>
      {secondPane ? (

          {contents}

      ) : null}

  );
});

// Hack to enable hooks in stories: https://github.com/storybookjs/storybook/issues/5721#issuecomment-473869398
addDecorator(Story => <Story />);

addDecorator(story => <I18n messages={messages}>{story()}</I18n>);

configure(() => {
  // Load sticker creator stories
  const stickerCreatorContext = require.context(
    '../sticker-creator',
    true,
    /\.stories\.tsx?$/
  );
  stickerCreatorContext.keys().forEach(f => stickerCreatorContext(f));
  // Load main app stories
  const tsComponentsContext = require.context(
    '../ts/components',
    true,
    /\.stories.tsx?$/
  );
  tsComponentsContext.keys().forEach(f => tsComponentsContext(f));
}, module);
<|endoftext|>


<commit_before>'use strict';

const expect        = require('../../helpers/expect');
const fs            = require('fs');
const SerializeIcon = require('../../../src/utils/serialize-icon');

const SaveCdvXML    = require('../../../src/utils/save-cordova-xml');

describe('SaveCordovaXML', function() {
  const fixturePath = 'node-tests/fixtures/config.xml';
  const tmpFixturePath = 'tmp/config.xml';

  const projectPath = 'tmp';

  before(() => {
    if (!fs.existsSync(projectPath)) {
      fs.mkdirSync(projectPath);
    }
  });

  afterEach(() => {
    fs.unlinkSync(tmpFixturePath);
  });

  context('when projectPath, desiredNodes, keyName, and serializeFn', () => {
    const projectPath = 'tmp/';
    const desiredNodes = {
      ios: {
        itemKey: 'width',
        items: [
          { size: 60,  name: 'icon-60', src: 'tmp/ios/icon-60.png' }
        ]
      }
    };
    const keyName = 'icon';
    const serializeFn = SerializeIcon;
    const args = {
      projectPath: projectPath,
      desiredNodes: desiredNodes,
      keyName: keyName,
      serializeFn: serializeFn
    };

    context('when config.xml has no platform nodes', () => {
      before(() => {
        fs.createReadStream(`${fixturePath}/no-platform-nodes.xml`)
        .pipe(fs.createWriteStream(tmpFixturePath));
      });

      it('it adds the platform node with icon nodes', (done) => {
        SaveCdvXML(args).then(() => {
          const configXML = fs.readFileSync(tmpFixturePath, 'utf8');
          const expectedConfigXML = fs.readFileSync(
            `${fixturePath}/no-and-ios-platform-node-expected.xml`, 'utf8'
          );

          try {
            expect(configXML).to.equal(expectedConfigXML);
            done();
          } catch(e) {
            done(e);
          }
        })
        .catch((e) => {
          done(e);
        });
      });
    });

    context('when config.xml has desiredNodes platform', () => {
      before(() => {
        fs.createReadStream(`${fixturePath}/ios-platform-node.xml`)
        .pipe(fs.createWriteStream(tmpFixturePath));
      });

      it('it replaces the icon nodes', (done) => {
        SaveCdvXML(args).then(() => {
          const configXML = fs.readFileSync(tmpFixturePath, 'utf8');
          const expectedConfigXML = fs.readFileSync(
            `${fixturePath}/no-and-ios-platform-node-expected.xml`, 'utf8'
          );

          try {
            expect(configXML).to.equal(expectedConfigXML);
            done();
          } catch(e) {
            done(e);
          }
        })
        .catch((e) => {
          done(e);
        });
      });
    });

    context('when config.xml does not have desiredNodes platform', () => {
      before(() => {
        fs.createReadStream(`${fixturePath}/android-platform-node.xml`)
        .pipe(fs.createWriteStream(tmpFixturePath));
      });

      it('it adds the platform node with icon nodes', (done) => {
        SaveCdvXML(args).then(() => {
          const configXML = fs.readFileSync(tmpFixturePath, 'utf8');
          const expectedConfigXML = fs.readFileSync(
            `${fixturePath}/android-platform-node-expected.xml`, 'utf8'
          );

          try {
            expect(configXML).to.equal(expectedConfigXML);
            done();
          } catch(e) {
            done(e);
          }
        })
        .catch((e) => {
          done(e);
        });
      });
    });
  });
});
<commit_msg>fix(save-cordova-xml): Update test to fix wait for the before hook to complete before executing test<commit_after>'use strict';

const expect        = require('../../helpers/expect');
const fs            = require('fs');
const SerializeIcon = require('../../../src/utils/serialize-icon');

const SaveCdvXML    = require('../../../src/utils/save-cordova-xml');

describe('SaveCordovaXML', function() {
  const fixturePath = 'node-tests/fixtures/config.xml';
  const tmpFixturePath = 'tmp/config.xml';

  const projectPath = 'tmp';

  before(() => {
    if (!fs.existsSync(projectPath)) {
      fs.mkdirSync(projectPath);
    }
  });

  afterEach(() => {
    fs.unlinkSync(tmpFixturePath);
  });

  context('when projectPath, desiredNodes, keyName, and serializeFn', () => {
    const projectPath = 'tmp/';
    const desiredNodes = {
      ios: {
        itemKey: 'width',
        items: [
          { size: 60,  name: 'icon-60', src: 'tmp/ios/icon-60.png' }
        ]
      }
    };
    const keyName = 'icon';
    const serializeFn = SerializeIcon;
    const args = {
      projectPath: projectPath,
      desiredNodes: desiredNodes,
      keyName: keyName,
      serializeFn: serializeFn
    };

    context('when config.xml has no platform nodes', () => {
      before((done) => {
        const fixtureStream = fs.createReadStream(`${fixturePath}/no-platform-nodes.xml`)
        const tmpFixtureStream = fs.createWriteStream(tmpFixturePath)
        fixtureStream.pipe(tmpFixtureStream);

        tmpFixtureStream.on('finish', () => {
          done();
        });
      });

      it('it adds the platform node with icon nodes', (done) => {
        SaveCdvXML(args).then(() => {
          const configXML = fs.readFileSync(tmpFixturePath, 'utf8');
          const expectedConfigXML = fs.readFileSync(
            `${fixturePath}/no-and-ios-platform-node-expected.xml`, 'utf8'
          );

          try {
            expect(configXML).to.equal(expectedConfigXML);
            done();
          } catch(e) {
            done(e);
          }
        })
        .catch((e) => {
          done(e);
        });
      });
    });

    context('when config.xml has desiredNodes platform', () => {
      before((done) => {
        const fixtureStream = fs.createReadStream(`${fixturePath}/ios-platform-node.xml`)
        const tmpFixtureStream = fs.createWriteStream(tmpFixturePath)
        fixtureStream.pipe(tmpFixtureStream);

        tmpFixtureStream.on('finish', () => {
          done();
        });
      });

      it('it replaces the icon nodes', (done) => {
        SaveCdvXML(args).then(() => {
          const configXML = fs.readFileSync(tmpFixturePath, 'utf8');
          const expectedConfigXML = fs.readFileSync(
            `${fixturePath}/no-and-ios-platform-node-expected.xml`, 'utf8'
          );

          try {
            expect(configXML).to.equal(expectedConfigXML);
            done();
          } catch(e) {
            done(e);
          }
        })
        .catch((e) => {
          done(e);
        });
      });
    });

    context('when config.xml does not have desiredNodes platform', () => {
      before((done) => {
        const fixtureStream = fs.createReadStream(`${fixturePath}/android-platform-node.xml`)
        const tmpFixtureStream = fs.createWriteStream(tmpFixturePath)
        fixtureStream.pipe(tmpFixtureStream);

        tmpFixtureStream.on('finish', () => {
          done();
        });
      });

      it('it adds the platform node with icon nodes', (done) => {
        SaveCdvXML(args).then(() => {
          const configXML = fs.readFileSync(tmpFixturePath, 'utf8');
          const expectedConfigXML = fs.readFileSync(
            `${fixturePath}/android-platform-node-expected.xml`, 'utf8'
          );

          try {
            expect(configXML).to.equal(expectedConfigXML);
            done();
          } catch(e) {
            done(e);
          }
        })
        .catch((e) => {
          done(e);
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>import Ember from 'ember';

import lookup from 'furnace-forms/utils/lookup-class';
import getName from 'furnace-forms/utils/get-name';

export default Ember.Component.extend({

	tagName: '',

	_control: null,

	_lookup: lookup,

	control : Ember.computed.alias('_control').readOnly(),

	attrList : null,

	form: Ember.computed('_named,for',{
		get() {
			if(this.get('_named')) {
				return this.get('_named');
			} else {
				return getName(this.get('for'));
			}
		}
	}).readOnly(),

	_formObserver: Ember.observer('form',function() {
		let Clazz=this._lookup(this.get('form'));
		let control=Clazz.create(Ember.getOwner(this).ownerInjection(),{
			'for': this.get('for'),
			target: this,
			_rootControl:true
		});
		this.set('_control',control);
	}).on('init'),

	decorator: Ember.computed.alias('_control._decorator'),

	'for' : null,

	send: function() {
		this.sendAction.apply(this,arguments);
	},

	sendAction(action) {
		let actionName=action || 'action';
		if(this.get('attrs.'+actionName)) {
			this._super(...arguments);
		} else {
			var targetObject=this.get('_targetObject') || this.get('targetObject');
			if(targetObject) {
				targetObject.send.apply(targetObject,arguments);
			}
		}
	},

	receiveParentAttributes : Ember.on('didReceiveAttrs',function(attrs) {
		if(!this.attrList) {
			var attrList=Ember.A();
			for(let name in attrs.newAttrs) {
				if(name!=='for' && name!=='_named') {
					attrList.push(name);
				}
			}
			this.set('attrList',attrList);
		}
	}),

}).reopenClass({
	positionalParams: ['_named'],
});<commit_msg>Fixed deprecation with default form detection<commit_after>import Ember from 'ember';

import lookup from 'furnace-forms/utils/lookup-class';
import getName from 'furnace-forms/utils/get-name';

export default Ember.Component.extend({

	tagName: '',

	_control: null,

	_lookup: lookup,

	control : Ember.computed.alias('_control').readOnly(),

	attrList : null,

	form: Ember.computed('_named,for',{
		get() {
			if(this.get('_named')) {
				return this.get('_named');
			} else {
				return getName(this.get('_targetObject'));
			}
		}
	}).readOnly(),

	_formObserver: Ember.observer('form',function() {
		let Clazz=this._lookup(this.get('form'));
		let control=Clazz.create(Ember.getOwner(this).ownerInjection(),{
			'for': this.get('for'),
			target: this,
			_rootControl:true
		});
		this.set('_control',control);
	}).on('init'),

	decorator: Ember.computed.alias('_control._decorator'),

	'for' : null,

	send: function() {
		this.sendAction.apply(this,arguments);
	},

	sendAction(action) {
		let actionName=action || 'action';
		if(this.get('attrs.'+actionName)) {
			this._super(...arguments);
		} else {
			var targetObject=this.get('_targetObject') || this.get('targetObject');
			if(targetObject) {
				targetObject.send.apply(targetObject,arguments);
			}
		}
	},

	receiveParentAttributes : Ember.on('didReceiveAttrs',function(attrs) {
		if(!this.attrList) {
			var attrList=Ember.A();
			for(let name in attrs.newAttrs) {
				if(name!=='for' && name!=='_named') {
					attrList.push(name);
				}
			}
			this.set('attrList',attrList);
		}
	}),

}).reopenClass({
	positionalParams: ['_named'],
});<|endoftext|>


<commit_before>/*
 * Copyright 2019 ThoughtWorks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* global __dirname */

const path                = require('path');
const process             = require('process');
const jasmineSeedReporter = require('karma-jasmine-seed-reporter');
const childProcess        = require('child_process');

let browsers;

if (process.platform === 'darwin') {
  browsers = ['Firefox', 'Chrome', 'Safari'];
} else if (process.platform === 'win32') {

  // make sure to kill Edge browser before doing anything.
  childProcess.spawnSync('taskkill', ['/F', '/IM', 'MicrosoftEdge.exe', '/T']);

  // Clear Edge history so that it doesn't re-open tabs after getting killed
  childProcess.spawnSync('powershell', ['-Command', "Remove-Item $env:USERPROFILE/AppData/Local/Packages/Microsoft.MicrosoftEdge_8wekyb3d8bbwe/AC/* -Force -Recurse"]);

  browsers = ['Edge'];
} else {
  // linux, bsd, et.al.
  browsers = ['Firefox'];
}

module.exports = function (config) {
  config.set({
    basePath:      path.join(__dirname, 'public', 'assets', 'webpack'),
    frameworks:    ['jasmine'],
    client:        {
      captureConsole: true,
      jasmine:        {
        random: true,
        seed:   process.env['JASMINE_SEED']
      }
    },
    plugins:        [jasmineSeedReporter, "karma-*"],
    preprocessors:  {
      '**/*.js': ['sourcemap']
    },
    files:          [
      {
        pattern:  'vendor-and-helpers.chunk.js',
        watched:  true,
        included: true,
        served:   true
      },
      {
        pattern:  'specRoot.js',
        watched:  true,
        included: true,
        served:   true
      },
    ],
    reporters:      ['progress', 'junit', 'kjhtml', 'html', 'jasmine-seed'],
    htmlReporter:   {
      outputDir:               path.join(__dirname, '..', '..', '..', '..', '..', 'target', 'karma_reports'),
      templatePath:            null,
      focusOnFailures:         true,
      namedFiles:              false,
      pageTitle:               null,
      urlFriendlyName:         false,
      preserveDescribeNesting: false,
      foldAll:                 false,
    },
    junitReporter:  {
      outputDir:          path.join(__dirname, '..', '..', '..', '..', '..', 'target', 'karma_reports'),
      outputFile:         undefined,
      suite:              '',
      useBrowserName:     true,
      nameFormatter:      undefined,
      classNameFormatter: undefined,
      properties:         {}
    },
    port:          9876,
    colors:        true,
    logLevel:      process.env['KARMA_LOG_LEVEL'] ? config[`LOG_${process.env['KARMA_LOG_LEVEL'].toUpperCase()}`] : config.LOG_INFO,
    autoWatch:     true,
    browsers,
    singleRun:     false,
    concurrency:   Infinity
  });
};
<commit_msg>Fixup karma to load relevant files from the manifest.json<commit_after>/*
 * Copyright 2019 ThoughtWorks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* global __dirname */

const path                = require('path');
const process             = require('process');
const jasmineSeedReporter = require('karma-jasmine-seed-reporter');
const childProcess        = require('child_process');

let browsers;

if (process.platform === 'darwin') {
  browsers = ['Firefox', 'Chrome', 'Safari'];
} else if (process.platform === 'win32') {

  // make sure to kill Edge browser before doing anything.
  childProcess.spawnSync('taskkill', ['/F', '/IM', 'MicrosoftEdge.exe', '/T']);

  // Clear Edge history so that it doesn't re-open tabs after getting killed
  childProcess.spawnSync('powershell', ['-Command', "Remove-Item $env:USERPROFILE/AppData/Local/Packages/Microsoft.MicrosoftEdge_8wekyb3d8bbwe/AC/* -Force -Recurse"]);

  browsers = ['Edge'];
} else {
  // linux, bsd, et.al.
  browsers = ['Firefox'];
}

module.exports = function (config) {
  const basePath = path.join(__dirname, 'public', 'assets', 'webpack');
  const manifest = require(path.join(basePath, 'manifest.json'));

  config.set({
    basePath,
    frameworks:    ['jasmine'],
    client:        {
      captureConsole: true,
      jasmine:        {
        random: true,
        seed:   process.env['JASMINE_SEED']
      }
    },
    plugins:       [jasmineSeedReporter, "karma-*"],
    preprocessors: {
      '**/*.js': ['sourcemap']
    },
    files:         manifest.entrypoints.specRoot.assets.map((eachAsset) => {
      return {
        pattern:  eachAsset,
        watched:  true,
        included: true,
        served:   true
      };
    }),
    reporters:     ['progress', 'junit', 'kjhtml', 'html', 'jasmine-seed'],
    htmlReporter:  {
      outputDir:               path.join(__dirname, '..', '..', '..', '..', '..', 'target', 'karma_reports'),
      templatePath:            null,
      focusOnFailures:         true,
      namedFiles:              false,
      pageTitle:               null,
      urlFriendlyName:         false,
      preserveDescribeNesting: false,
      foldAll:                 false,
    },
    junitReporter: {
      outputDir:          path.join(__dirname, '..', '..', '..', '..', '..', 'target', 'karma_reports'),
      outputFile:         undefined,
      suite:              '',
      useBrowserName:     true,
      nameFormatter:      undefined,
      classNameFormatter: undefined,
      properties:         {}
    },
    port:          9876,
    colors:        true,
    logLevel:      process.env['KARMA_LOG_LEVEL'] ? config[`LOG_${process.env['KARMA_LOG_LEVEL'].toUpperCase()}`] : config.LOG_INFO,
    autoWatch:     true,
    browsers,
    singleRun:     false,
    concurrency:   Infinity
  });
};
<|endoftext|>


<commit_before>/*    Copyright 2013 10gen Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/* jshint camelcase: false */
/* global mongo, console */
mongo.Coll = function (db, name) {
  if (name.length > 80){
		throw new mongo.CollectionNameError('Collection name must be 80 characters or less');
	}

	if (name.match(/(\$|\0)/)){
		throw new mongo.CollectionNameError('Collection name may not contain $ or \\0');
	}

	if (name.match(/^system\./)){
		throw new mongo.CollectionNameError('Collection name may not begin with system.*');
	}

	if (name === ''){
		throw new mongo.CollectionNameError('Collection name may not be empty');
	}

  this.name = name;
  this.db = db;
  this.shell = db.shell;
  this.urlBase = mongo.util.getDBCollectionResURL(db.shell.mwsResourceID, name);
};

mongo.Coll.prototype.toString = function () {
  return this.db.toString() + '.' + this.name;
};

// Todo: rewrite documentation in this file to reflect it's new location

/**
 * Makes a Cursor that is the result of a find request on the mongod backing
 * server.
 */
mongo.Coll.prototype.find = function (query, projection) {
  mongo.events.functionTrigger(this.shell, 'db.collection.find', arguments,
                               {collection: this.name});
  return new mongo.Cursor(this, query, projection);
};

mongo.Coll.prototype.findOne = function (query, projection) {
  mongo.events.functionTrigger(this.shell, 'db.collection.findOne', arguments,
                               {collection: this.name});
  var cursor = this.find(query, projection).limit(1);
  var context = this.shell.evaluator.pause();
  cursor.hasNext(function (hasNext) {
    if (hasNext) {
      cursor.next(function (next) {
        this.shell.evaluator.resume(context, next);
      }.bind(this));
    } else {
      this.shell.evaluator.resume(context, null);
    }
  }.bind(this));
};

mongo.Coll.prototype.insert = function (doc) {
  var url = this.urlBase + 'insert';
  var params = {document: doc};
  mongo.events.functionTrigger(this.shell, 'db.collection.insert', arguments,
                               {collection: this.name});
  mongo.request.makeRequest(url, params, 'POST', 'dbCollectionInsert', this.shell);
};

mongo.Coll.prototype.save = function (doc) {
  var url = this.urlBase + 'save';
  var params = {document: doc};
  mongo.events.functionTrigger(this.shell, 'db.collection.save', arguments,
    {collection: this.name});
  mongo.request.makeRequest(url, params, 'POST', 'dbCollectionSave', this.shell);
};

/**
 * Makes a remove request to the mongod instance on the backing server. On
 * success, the item(s) are removed from the collection, otherwise a failure
 * message is printed and an error is thrown.
 */
mongo.Coll.prototype.remove = function (constraint, justOne) {
  var url = this.urlBase + 'remove';
  var params = {constraint: constraint, just_one: justOne};
  mongo.events.functionTrigger(this.shell, 'db.collection.remove', arguments,
                               {collection: this.name});
  mongo.request.makeRequest(url, params, 'DELETE', 'dbCollectionRemove', this.shell);
};

/**
 * Makes an update request to the mongod instance on the backing server. On
 * success, the item(s) are updated in the collection, otherwise a failure
 * message is printed and an error is thrown.
 *
 * Optionally, an object which specifies whether to perform an upsert and/or
 * a multiple update may be used instead of the individual upsert and multi
 * parameters.
 */
mongo.Coll.prototype.update = function (query, update, upsert, multi) {
  var url = this.urlBase + 'update';
  mongo.events.functionTrigger(this.shell, 'db.collection.update', arguments,
                               {collection: this.name});

  // handle options document for 2.2+
  if (typeof upsert === 'object'){
    if (multi !== undefined){
      var msg = 'Fourth argument must be empty when specifying upsert and multi with an object';
      this.shell.insertResponseLine('ERROR: ' + msg);
      console.error('dbCollectionUpdate fail: ' + msg);
      throw {message: 'dbCollectionUpdate: Syntax error'};
    }
    multi = upsert.multi;
    upsert = upsert.upsert;
  }

  var params = {query: query, update: update, upsert: !!upsert, multi: !!multi};
  mongo.request.makeRequest(url, params, 'PUT', 'dbCollectionUpdate', this.shell);
};

/**
 * Makes a drop request to the mongod instance on the backing server. On
 * success, the collection is dropped from the database, otherwise a failure
 * message is printed and an error is thrown.
 */
mongo.Coll.prototype.drop = function () {
  var url = this.urlBase + 'drop';
  mongo.events.functionTrigger(this.shell, 'db.collection.drop', arguments,
                               {collection: this.name});
  mongo.request.makeRequest(url, null, 'DELETE', 'dbCollectionDrop', this.shell);
};

/**
 * Makes an aggregation request to the mongod instance on the backing server.
 * On success, the result of the aggregation is returned, otherwise a failure
 * message is printed and an error is thrown.
 */
mongo.Coll.prototype.aggregate = function(query){
  query = query || [];
  var url = this.urlBase + 'aggregate';
  var context = this.shell.evaluator.pause();
  var onSuccess = function(data){
    this.shell.evaluator.resume(context, data);
  }.bind(this);
  mongo.events.functionTrigger(this.shell, 'db.collection.aggregate', arguments,
                               {collection: this.name});
  mongo.request.makeRequest(url, query, 'GET', 'dbCollectionAggregate', this.shell, onSuccess);
};

mongo.Coll.prototype.__methodMissing = function (field) {
  var unimplemented = {
    'createIndex': 0,
    'copyTo': 0,
    'distinct': 0,
    'dropIndex': 0,
    'dropIndexes': 0,
    'ensureIndex': 0,
    'findAndModify': 0,
    'getIndexes': 0,
    'getShardDistribution': 0,
    'getShardVersion': 0,
    'group': 0,
    'isCapped': 0,
    'mapReduce': 0,
    'reIndex': 0,
    'renameCollection': 0,
    'stats': 0,
    'storageSize': 0,
    'totalSize': 0,
    'totalIndexSize': 0,
    'validate': 0
  };
  var msg;

  if (unimplemented.hasOwnProperty(field)) {
    msg = ' is not implemented.'
  } else {
    msg = ' is not a function on collections.';
  }
  this.shell.insertError(field + msg);
  var noop = function(){};
  noop.toString = function(){ return ''; };
  return noop;
};
<commit_msg>Add missing semi-colon.<commit_after>/*    Copyright 2013 10gen Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/* jshint camelcase: false */
/* global mongo, console */
mongo.Coll = function (db, name) {
  if (name.length > 80){
		throw new mongo.CollectionNameError('Collection name must be 80 characters or less');
	}

	if (name.match(/(\$|\0)/)){
		throw new mongo.CollectionNameError('Collection name may not contain $ or \\0');
	}

	if (name.match(/^system\./)){
		throw new mongo.CollectionNameError('Collection name may not begin with system.*');
	}

	if (name === ''){
		throw new mongo.CollectionNameError('Collection name may not be empty');
	}

  this.name = name;
  this.db = db;
  this.shell = db.shell;
  this.urlBase = mongo.util.getDBCollectionResURL(db.shell.mwsResourceID, name);
};

mongo.Coll.prototype.toString = function () {
  return this.db.toString() + '.' + this.name;
};

// Todo: rewrite documentation in this file to reflect it's new location

/**
 * Makes a Cursor that is the result of a find request on the mongod backing
 * server.
 */
mongo.Coll.prototype.find = function (query, projection) {
  mongo.events.functionTrigger(this.shell, 'db.collection.find', arguments,
                               {collection: this.name});
  return new mongo.Cursor(this, query, projection);
};

mongo.Coll.prototype.findOne = function (query, projection) {
  mongo.events.functionTrigger(this.shell, 'db.collection.findOne', arguments,
                               {collection: this.name});
  var cursor = this.find(query, projection).limit(1);
  var context = this.shell.evaluator.pause();
  cursor.hasNext(function (hasNext) {
    if (hasNext) {
      cursor.next(function (next) {
        this.shell.evaluator.resume(context, next);
      }.bind(this));
    } else {
      this.shell.evaluator.resume(context, null);
    }
  }.bind(this));
};

mongo.Coll.prototype.insert = function (doc) {
  var url = this.urlBase + 'insert';
  var params = {document: doc};
  mongo.events.functionTrigger(this.shell, 'db.collection.insert', arguments,
                               {collection: this.name});
  mongo.request.makeRequest(url, params, 'POST', 'dbCollectionInsert', this.shell);
};

mongo.Coll.prototype.save = function (doc) {
  var url = this.urlBase + 'save';
  var params = {document: doc};
  mongo.events.functionTrigger(this.shell, 'db.collection.save', arguments,
    {collection: this.name});
  mongo.request.makeRequest(url, params, 'POST', 'dbCollectionSave', this.shell);
};

/**
 * Makes a remove request to the mongod instance on the backing server. On
 * success, the item(s) are removed from the collection, otherwise a failure
 * message is printed and an error is thrown.
 */
mongo.Coll.prototype.remove = function (constraint, justOne) {
  var url = this.urlBase + 'remove';
  var params = {constraint: constraint, just_one: justOne};
  mongo.events.functionTrigger(this.shell, 'db.collection.remove', arguments,
                               {collection: this.name});
  mongo.request.makeRequest(url, params, 'DELETE', 'dbCollectionRemove', this.shell);
};

/**
 * Makes an update request to the mongod instance on the backing server. On
 * success, the item(s) are updated in the collection, otherwise a failure
 * message is printed and an error is thrown.
 *
 * Optionally, an object which specifies whether to perform an upsert and/or
 * a multiple update may be used instead of the individual upsert and multi
 * parameters.
 */
mongo.Coll.prototype.update = function (query, update, upsert, multi) {
  var url = this.urlBase + 'update';
  mongo.events.functionTrigger(this.shell, 'db.collection.update', arguments,
                               {collection: this.name});

  // handle options document for 2.2+
  if (typeof upsert === 'object'){
    if (multi !== undefined){
      var msg = 'Fourth argument must be empty when specifying upsert and multi with an object';
      this.shell.insertResponseLine('ERROR: ' + msg);
      console.error('dbCollectionUpdate fail: ' + msg);
      throw {message: 'dbCollectionUpdate: Syntax error'};
    }
    multi = upsert.multi;
    upsert = upsert.upsert;
  }

  var params = {query: query, update: update, upsert: !!upsert, multi: !!multi};
  mongo.request.makeRequest(url, params, 'PUT', 'dbCollectionUpdate', this.shell);
};

/**
 * Makes a drop request to the mongod instance on the backing server. On
 * success, the collection is dropped from the database, otherwise a failure
 * message is printed and an error is thrown.
 */
mongo.Coll.prototype.drop = function () {
  var url = this.urlBase + 'drop';
  mongo.events.functionTrigger(this.shell, 'db.collection.drop', arguments,
                               {collection: this.name});
  mongo.request.makeRequest(url, null, 'DELETE', 'dbCollectionDrop', this.shell);
};

/**
 * Makes an aggregation request to the mongod instance on the backing server.
 * On success, the result of the aggregation is returned, otherwise a failure
 * message is printed and an error is thrown.
 */
mongo.Coll.prototype.aggregate = function(query){
  query = query || [];
  var url = this.urlBase + 'aggregate';
  var context = this.shell.evaluator.pause();
  var onSuccess = function(data){
    this.shell.evaluator.resume(context, data);
  }.bind(this);
  mongo.events.functionTrigger(this.shell, 'db.collection.aggregate', arguments,
                               {collection: this.name});
  mongo.request.makeRequest(url, query, 'GET', 'dbCollectionAggregate', this.shell, onSuccess);
};

mongo.Coll.prototype.__methodMissing = function (field) {
  var unimplemented = {
    'createIndex': 0,
    'copyTo': 0,
    'distinct': 0,
    'dropIndex': 0,
    'dropIndexes': 0,
    'ensureIndex': 0,
    'findAndModify': 0,
    'getIndexes': 0,
    'getShardDistribution': 0,
    'getShardVersion': 0,
    'group': 0,
    'isCapped': 0,
    'mapReduce': 0,
    'reIndex': 0,
    'renameCollection': 0,
    'stats': 0,
    'storageSize': 0,
    'totalSize': 0,
    'totalIndexSize': 0,
    'validate': 0
  };
  var msg;

  if (unimplemented.hasOwnProperty(field)) {
    msg = ' is not implemented.';
  } else {
    msg = ' is not a function on collections.';
  }
  this.shell.insertError(field + msg);
  var noop = function(){};
  noop.toString = function(){ return ''; };
  return noop;
};
<|endoftext|>


<commit_before>import { Report, Position, Task, Location } from "models"
import faker from "faker"
import _isEmpty from "lodash/isEmpty"
import _isEqual from "lodash/isEqual"
import _uniqWith from "lodash/uniqWith"
import { runGQL, populate } from "../simutils"

async function getRandomPerson(user, variables) {
  const positionsQuery = Object.assign({}, variables, {
    pageNum: 0,
    pageSize: 1
  })
  const totalCount = (await runGQL(user, {
    query: `
        query ($positionsQuery: PositionSearchQueryInput) {
          positionList(query: $positionsQuery) {
            totalCount
          }
        }
      `,
    variables: {
      positionsQuery
    }
  })).data.positionList.totalCount
  let positions = null
  if (totalCount > 0) {
    positionsQuery.pageNum = faker.random.number({ max: totalCount - 1 })
    positions = (await runGQL(user, {
      query: `
          query ($positionsQuery: PositionSearchQueryInput) {
            positionList(query: $positionsQuery) {
              list {
                uuid
                type
                person {
                  uuid
                  name
                  role
                }
              }
            }
          }
        `,
      variables: {
        positionsQuery
      }
    })).data.positionList.list
  }
  return _isEmpty(positions) ? null : positions[0].person
}

export const randomAdvisor = async function(user) {
  return getRandomPerson(user, {
    status: Position.STATUS.ACTIVE,
    isFilled: true,
    type: [Position.TYPE.ADVISOR]
  })
}

export const randomPrincipal = async function(user) {
  return getRandomPerson(user, {
    status: Position.STATUS.ACTIVE,
    isFilled: true,
    type: [Position.TYPE.PRINCIPAL]
  })
}

async function populateReport(report, user, args) {
  const emptyArray = () => {
    return []
  }

  /* eslint-disable no-unused-vars */
  const emptyObject = () => {
    return {}
  }
  /* eslint-enable no-unused-vars */

  async function activeLocation() {
    const totalCount = (await runGQL(user, {
      query: `
        query ($locationQuery: LocationSearchQueryInput) {
          locationList(query: $locationQuery) {
            totalCount
          }
        }
      `,
      variables: {
        locationQuery: {
          pageNum: 0,
          pageSize: 1,
          status: Location.STATUS.ACTIVE
        }
      }
    })).data.locationList.totalCount
    let activeLocations = null
    if (totalCount > 0) {
      const random = faker.random.number({ max: totalCount - 1 })
      activeLocations = (await runGQL(user, {
        query: `
          query ($locationQuery: LocationSearchQueryInput) {
            locationList(query: $locationQuery) {
              list {
                uuid
              }
            }
          }
        `,
        variables: {
          locationQuery: {
            pageNum: random,
            pageSize: 1,
            status: Location.STATUS.ACTIVE
          }
        }
      })).data.locationList.list
    }
    return _isEmpty(activeLocations) ? null : activeLocations[0]
  }

  async function activeTask() {
    const totalCount = (await runGQL(user, {
      query: `
        query ($taskQuery: TaskSearchQueryInput) {
          taskList(query: $taskQuery) {
            totalCount
          }
        }
      `,
      variables: {
        taskQuery: {
          pageNum: 0,
          pageSize: 1,
          status: Task.STATUS.ACTIVE
        }
      }
    })).data.taskList.totalCount
    let activeTasks = null
    if (totalCount > 0) {
      const random = faker.random.number({ max: totalCount - 1 })
      activeTasks = (await runGQL(user, {
        query: `
          query ($taskQuery: TaskSearchQueryInput) {
            taskList(query: $taskQuery) {
              list {
                uuid
              }
            }
          }
        `,
        variables: {
          taskQuery: {
            pageNum: random,
            pageSize: 1,
            status: Task.STATUS.ACTIVE
          }
        }
      })).data.taskList.list
    }
    return _isEmpty(activeTasks) ? null : activeTasks[0]
  }

  const location = await activeLocation()
  async function getAttendees() {
    const attendees = []
    const nbOfAdvisors = faker.random.number({ min: 1, max: 5 })
    let primary = true
    for (let i = 0; i < nbOfAdvisors; i++) {
      const advisor = await randomAdvisor(user)
      if (advisor) {
        advisor.primary = primary
        primary = false
        attendees.push(advisor)
      }
    }

    const nbOfPrincipals = faker.random.number({ min: 1, max: 5 })
    primary = true
    for (let i = 0; i < nbOfPrincipals; i++) {
      const principal = await randomPrincipal(user)
      if (principal) {
        principal.primary = primary
        primary = false
        attendees.push(principal)
      }
    }

    return [..._uniqWith(attendees, _isEqual)]
  }
  const attendees = await getAttendees()
  async function getTasks() {
    const reportTasks = []
    const nbOfTasks = faker.random.number({ min: 1, max: 3 })

    for (let i = 0; i < nbOfTasks; i++) {
      reportTasks.push(await activeTask())
    }

    return [..._uniqWith(reportTasks, _isEqual)]
  }
  const tasks = await getTasks()
  const template = {
    intent: () => faker.lorem.paragraph(),
    engagementDate: () => faker.date.recent(365).toISOString(),
    duration: () => faker.random.number({ min: 1, max: 480 }),
    cancelledReason: () =>
      faker.random.arrayElement([
        "CANCELLED_BY_ADVISOR",
        "CANCELLED_BY_PRINCIPAL",
        "CANCELLED_DUE_TO_TRANSPORTATION",
        "CANCELLED_DUE_TO_FORCE_PROTECTION",
        "CANCELLED_DUE_TO_ROUTES",
        "CANCELLED_DUE_TO_THREAT"
      ]),
    atmosphere: () =>
      faker.random.arrayElement(["POSITIVE", "NEUTRAL", "NEGATIVE"]),
    atmosphereDetails: () => faker.lorem.sentence(),
    location,
    attendees,
    tasks,
    reportText: () => faker.lorem.paragraphs(),
    nextSteps: () => faker.lorem.sentence(),
    keyOutcomes: () => faker.lorem.sentence(),
    tags: emptyArray,
    reportSensitiveInformation: () => null,
    authorizationGroups: emptyArray,
    state: (args && args.state) || Report.STATE.DRAFT
  }

  populate(report, template)
    .intent.always()
    .engagementDate.always()
    .duration.often()
    .cancelledReason.often()
    .atmosphere.always()
    .atmosphereDetails.always()
    .location.always()
    .attendees.always()
    .tasks.always()
    .reportText.always()
    .nextSteps.always()
    .keyOutcomes.always()
    .tags.rarely()
    .reportSensitiveInformation.and()
    .authorizationGroups.rarely()
    .state.always()

  return report
}

const createReport = async function(user, grow, args) {
  const report = new Report()
  if (await populateReport(report, user, args)) {
    console.debug(`Creating report ${report.intent.green}`)
    const { reportTags, cancelled, ...reportStripped } = report // TODO: we need to do this more generically

    return (await runGQL(user, {
      query:
        "mutation($report: ReportInput!) { createReport(report: $report) { uuid } }",
      variables: { report: reportStripped }
    })).data.createReport
  }
}

const updateDraftReport = async function(user) {
  const totalCount = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: 0,
          pageSize: 1,
          state: ${Report.STATE.DRAFT},
          authorUuid: "${user.person.uuid}"
        }) {
          totalCount
        }
      }
    `,
    variables: {}
  })).data.reportList.totalCount
  if (totalCount === 0) {
    return null
  }
  const random = faker.random.number({ max: totalCount - 1 })
  const reports = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: ${random},
          pageSize: 1,
          state: ${Report.STATE.DRAFT},
          authorUuid: "${user.person.uuid}"
        }) {
          list {
            uuid
            intent
            engagementDate
            duration
            keyOutcomes
            nextSteps
            cancelledReason
            atmosphere
            atmosphereDetails
            attendees {
              uuid
              primary
            }
          }
        }
      }
    `,
    variables: {}
  })).data.reportList.list
  const report = !_isEmpty(reports) && reports[0]
  if (!report) {
    return null
  }

  if (await populateReport(report, user)) {
    return (await runGQL(user, {
      query:
        "mutation($report: ReportInput!) { updateReport(report: $report) { uuid } }",
      variables: { report: report }
    })).data.updateReport
  }
}

const submitDraftReport = async function(user) {
  const totalCount = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: 0,
          pageSize: 1,
          state: ${Report.STATE.DRAFT},
          authorUuid: "${user.person.uuid}"
        }) {
          totalCount
        }
      }
    `,
    variables: {}
  })).data.reportList.totalCount
  if (totalCount === 0) {
    return null
  }
  const random = faker.random.number({ max: totalCount - 1 })
  const reports = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: ${random},
          pageSize: 1,
          state: ${Report.STATE.DRAFT},
          authorUuid: "${user.person.uuid}"
        }) {
          list {
            uuid
          }
        }
      }
    `,
    variables: {}
  })).data.reportList.list
  const report = _isEmpty(reports) && reports[0]
  if (!report) {
    return null
  }

  return (await runGQL(user, {
    query: "mutation($uuid: String!) { submitReport(uuid: $uuid) { uuid } }",
    variables: { uuid: report.uuid }
  })).data.submitReport
}

const approveReport = async function(user) {
  const totalCount = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: 0,
          pageSize: 1,
          pendingApprovalOf: "${user.person.uuid}"
        }) {
          totalCount
        }
      }
    `,
    variables: {}
  })).data.reportList.totalCount
  if (totalCount === 0) {
    return null
  }
  const random = faker.random.number({ max: totalCount - 1 })
  const reports = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: ${random},
          pageSize: 1,
          pendingApprovalOf: "${user.person.uuid}"
        }) {
          list {
            uuid
          }
        }
      }
    `,
    variables: {}
  })).data.reportList.list
  const report = _isEmpty(reports) && reports[0]
  if (!report) {
    return null
  }

  return (await runGQL(user, {
    query: "mutation ($uuid: String!) { approveReport(uuid: $uuid) { uuid } }",
    variables: { uuid: report.uuid }
  })).data.approveReport
}

export { createReport, updateDraftReport, submitDraftReport, approveReport }
<commit_msg>NCI-Agency/anet#379: Add releasedAt field to generated reports<commit_after>import { Report, Position, Task, Location } from "models"
import faker from "faker"
import _isEmpty from "lodash/isEmpty"
import _isEqual from "lodash/isEqual"
import _uniqWith from "lodash/uniqWith"
import { runGQL, populate } from "../simutils"

async function getRandomPerson(user, variables) {
  const positionsQuery = Object.assign({}, variables, {
    pageNum: 0,
    pageSize: 1
  })
  const totalCount = (await runGQL(user, {
    query: `
        query ($positionsQuery: PositionSearchQueryInput) {
          positionList(query: $positionsQuery) {
            totalCount
          }
        }
      `,
    variables: {
      positionsQuery
    }
  })).data.positionList.totalCount
  let positions = null
  if (totalCount > 0) {
    positionsQuery.pageNum = faker.random.number({ max: totalCount - 1 })
    positions = (await runGQL(user, {
      query: `
          query ($positionsQuery: PositionSearchQueryInput) {
            positionList(query: $positionsQuery) {
              list {
                uuid
                type
                person {
                  uuid
                  name
                  role
                }
              }
            }
          }
        `,
      variables: {
        positionsQuery
      }
    })).data.positionList.list
  }
  return _isEmpty(positions) ? null : positions[0].person
}

export const randomAdvisor = async function(user) {
  return getRandomPerson(user, {
    status: Position.STATUS.ACTIVE,
    isFilled: true,
    type: [Position.TYPE.ADVISOR]
  })
}

export const randomPrincipal = async function(user) {
  return getRandomPerson(user, {
    status: Position.STATUS.ACTIVE,
    isFilled: true,
    type: [Position.TYPE.PRINCIPAL]
  })
}

async function populateReport(report, user, args) {
  const emptyArray = () => {
    return []
  }

  /* eslint-disable no-unused-vars */
  const emptyObject = () => {
    return {}
  }
  /* eslint-enable no-unused-vars */

  async function activeLocation() {
    const totalCount = (await runGQL(user, {
      query: `
        query ($locationQuery: LocationSearchQueryInput) {
          locationList(query: $locationQuery) {
            totalCount
          }
        }
      `,
      variables: {
        locationQuery: {
          pageNum: 0,
          pageSize: 1,
          status: Location.STATUS.ACTIVE
        }
      }
    })).data.locationList.totalCount
    let activeLocations = null
    if (totalCount > 0) {
      const random = faker.random.number({ max: totalCount - 1 })
      activeLocations = (await runGQL(user, {
        query: `
          query ($locationQuery: LocationSearchQueryInput) {
            locationList(query: $locationQuery) {
              list {
                uuid
              }
            }
          }
        `,
        variables: {
          locationQuery: {
            pageNum: random,
            pageSize: 1,
            status: Location.STATUS.ACTIVE
          }
        }
      })).data.locationList.list
    }
    return _isEmpty(activeLocations) ? null : activeLocations[0]
  }

  async function activeTask() {
    const totalCount = (await runGQL(user, {
      query: `
        query ($taskQuery: TaskSearchQueryInput) {
          taskList(query: $taskQuery) {
            totalCount
          }
        }
      `,
      variables: {
        taskQuery: {
          pageNum: 0,
          pageSize: 1,
          status: Task.STATUS.ACTIVE
        }
      }
    })).data.taskList.totalCount
    let activeTasks = null
    if (totalCount > 0) {
      const random = faker.random.number({ max: totalCount - 1 })
      activeTasks = (await runGQL(user, {
        query: `
          query ($taskQuery: TaskSearchQueryInput) {
            taskList(query: $taskQuery) {
              list {
                uuid
              }
            }
          }
        `,
        variables: {
          taskQuery: {
            pageNum: random,
            pageSize: 1,
            status: Task.STATUS.ACTIVE
          }
        }
      })).data.taskList.list
    }
    return _isEmpty(activeTasks) ? null : activeTasks[0]
  }

  const location = await activeLocation()
  async function getAttendees() {
    const attendees = []
    const nbOfAdvisors = faker.random.number({ min: 1, max: 5 })
    let primary = true
    for (let i = 0; i < nbOfAdvisors; i++) {
      const advisor = await randomAdvisor(user)
      if (advisor) {
        advisor.primary = primary
        primary = false
        attendees.push(advisor)
      }
    }

    const nbOfPrincipals = faker.random.number({ min: 1, max: 5 })
    primary = true
    for (let i = 0; i < nbOfPrincipals; i++) {
      const principal = await randomPrincipal(user)
      if (principal) {
        principal.primary = primary
        primary = false
        attendees.push(principal)
      }
    }

    return [..._uniqWith(attendees, _isEqual)]
  }
  const attendees = await getAttendees()
  async function getTasks() {
    const reportTasks = []
    const nbOfTasks = faker.random.number({ min: 1, max: 3 })

    for (let i = 0; i < nbOfTasks; i++) {
      reportTasks.push(await activeTask())
    }

    return [..._uniqWith(reportTasks, _isEqual)]
  }
  const tasks = await getTasks()
  const engagementDate = faker.date.recent(365)

  const template = {
    intent: () => faker.lorem.paragraph(),
    engagementDate: engagementDate.toISOString(),
    duration: () => faker.random.number({ min: 1, max: 480 }),
    cancelledReason: () =>
      faker.random.arrayElement([
        "CANCELLED_BY_ADVISOR",
        "CANCELLED_BY_PRINCIPAL",
        "CANCELLED_DUE_TO_TRANSPORTATION",
        "CANCELLED_DUE_TO_FORCE_PROTECTION",
        "CANCELLED_DUE_TO_ROUTES",
        "CANCELLED_DUE_TO_THREAT"
      ]),
    atmosphere: () =>
      faker.random.arrayElement(["POSITIVE", "NEUTRAL", "NEGATIVE"]),
    atmosphereDetails: () => faker.lorem.sentence(),
    location,
    attendees,
    tasks,
    reportText: () => faker.lorem.paragraphs(),
    nextSteps: () => faker.lorem.sentence(),
    keyOutcomes: () => faker.lorem.sentence(),
    tags: emptyArray,
    reportSensitiveInformation: () => null,
    authorizationGroups: emptyArray,
    state: (args && args.state) || Report.STATE.DRAFT,
    releasedAt: () => {
      // Set the releasedAt value on a random date between 1 and 7 days after the engagement
      let result = new Date(engagementDate)
      result.setSeconds(
        result.getSeconds() +
          (Math.floor(Math.random() * (60 * 60 * 24 * 7)) + 1)
      )
      return result
    }
  }

  populate(report, template)
    .intent.always()
    .engagementDate.always()
    .duration.often()
    .cancelledReason.often()
    .atmosphere.always()
    .atmosphereDetails.always()
    .location.always()
    .attendees.always()
    .tasks.always()
    .reportText.always()
    .nextSteps.always()
    .keyOutcomes.always()
    .tags.rarely()
    .reportSensitiveInformation.and()
    .authorizationGroups.rarely()
    .state.always()
    .releasedAt.always()

  return report
}

const createReport = async function(user, grow, args) {
  const report = new Report()
  if (await populateReport(report, user, args)) {
    console.debug(`Creating report ${report.intent.green}`)
    const { reportTags, cancelled, ...reportStripped } = report // TODO: we need to do this more generically

    return (await runGQL(user, {
      query:
        "mutation($report: ReportInput!) { createReport(report: $report) { uuid } }",
      variables: { report: reportStripped }
    })).data.createReport
  }
}

const updateDraftReport = async function(user) {
  const totalCount = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: 0,
          pageSize: 1,
          state: ${Report.STATE.DRAFT},
          authorUuid: "${user.person.uuid}"
        }) {
          totalCount
        }
      }
    `,
    variables: {}
  })).data.reportList.totalCount
  if (totalCount === 0) {
    return null
  }
  const random = faker.random.number({ max: totalCount - 1 })
  const reports = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: ${random},
          pageSize: 1,
          state: ${Report.STATE.DRAFT},
          authorUuid: "${user.person.uuid}"
        }) {
          list {
            uuid
            intent
            engagementDate
            duration
            keyOutcomes
            nextSteps
            cancelledReason
            atmosphere
            atmosphereDetails
            attendees {
              uuid
              primary
            }
          }
        }
      }
    `,
    variables: {}
  })).data.reportList.list
  const report = !_isEmpty(reports) && reports[0]
  if (!report) {
    return null
  }

  if (await populateReport(report, user)) {
    return (await runGQL(user, {
      query:
        "mutation($report: ReportInput!) { updateReport(report: $report) { uuid } }",
      variables: { report: report }
    })).data.updateReport
  }
}

const submitDraftReport = async function(user) {
  const totalCount = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: 0,
          pageSize: 1,
          state: ${Report.STATE.DRAFT},
          authorUuid: "${user.person.uuid}"
        }) {
          totalCount
        }
      }
    `,
    variables: {}
  })).data.reportList.totalCount
  if (totalCount === 0) {
    return null
  }
  const random = faker.random.number({ max: totalCount - 1 })
  const reports = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: ${random},
          pageSize: 1,
          state: ${Report.STATE.DRAFT},
          authorUuid: "${user.person.uuid}"
        }) {
          list {
            uuid
          }
        }
      }
    `,
    variables: {}
  })).data.reportList.list
  const report = _isEmpty(reports) && reports[0]
  if (!report) {
    return null
  }

  return (await runGQL(user, {
    query: "mutation($uuid: String!) { submitReport(uuid: $uuid) { uuid } }",
    variables: { uuid: report.uuid }
  })).data.submitReport
}

const approveReport = async function(user) {
  const totalCount = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: 0,
          pageSize: 1,
          pendingApprovalOf: "${user.person.uuid}"
        }) {
          totalCount
        }
      }
    `,
    variables: {}
  })).data.reportList.totalCount
  if (totalCount === 0) {
    return null
  }
  const random = faker.random.number({ max: totalCount - 1 })
  const reports = (await runGQL(user, {
    query: `
      query {
        reportList(query: {
          pageNum: ${random},
          pageSize: 1,
          pendingApprovalOf: "${user.person.uuid}"
        }) {
          list {
            uuid
          }
        }
      }
    `,
    variables: {}
  })).data.reportList.list
  const report = _isEmpty(reports) && reports[0]
  if (!report) {
    return null
  }

  return (await runGQL(user, {
    query: "mutation ($uuid: String!) { approveReport(uuid: $uuid) { uuid } }",
    variables: { uuid: report.uuid }
  })).data.approveReport
}

export { createReport, updateDraftReport, submitDraftReport, approveReport }
<|endoftext|>