<commit_before>/*
 * Handles barrier processing and display
 *
 * It process `Contract.barriers` and display them if its applicable
 * for current `Contract.form()
 */

var Barriers = (function () {
    'use strict';

    var isBarrierUpdated = false;

    var display = function (barrierCategory) {
        var barriers = Contract.barriers()[Defaults.get('underlying')],
            formName = Contract.form();

        if (barriers && formName && Defaults.get('formname')!=='risefall') {
            var barrier = barriers[formName];
            if(barrier) {
                var unit = document.getElementById('duration_units'),
                    end_time = document.getElementById('expiry_date'),
                    currentTick = Tick.quote(),
                    indicativeBarrierTooltip = document.getElementById('indicative_barrier_tooltip'),
                    indicativeHighBarrierTooltip = document.getElementById('indicative_high_barrier_tooltip'),
                    indicativeLowBarrierTooltip = document.getElementById('indicative_low_barrier_tooltip'),
                    decimalPlaces = countDecimalPlaces(currentTick);

                if (barrier.count === 1) {
                    document.getElementById('high_barrier_row').style.display = 'none';
                    document.getElementById('low_barrier_row').style.display = 'none';
                    document.getElementById('barrier_row').setAttribute('style', '');

                    var defaults_barrier = Defaults.get('barrier');
                    var barrier_def = defaults_barrier && !isNaN(defaults_barrier) ? defaults_barrier : barrier['barrier'];
                    var elm = document.getElementById('barrier'),
                        tooltip = document.getElementById('barrier_tooltip'),
                        span = document.getElementById('barrier_span');
                    if ((unit && isVisible(unit) && unit.value === 'd') || (end_time && isVisible(end_time) && moment(end_time.value).isAfter(moment(),'day'))) {
                        if (currentTick && !isNaN(currentTick) && String(barrier_def).match(/^[+-]/)) {
                            elm.value = (parseFloat(currentTick) + parseFloat(barrier_def)).toFixed(decimalPlaces);
                            elm.textContent = (parseFloat(currentTick) + parseFloat(barrier_def)).toFixed(decimalPlaces);
                        } else {
                            elm.value = parseFloat(barrier_def);
                            elm.textContent = parseFloat(barrier_def);
                        }
                        tooltip.style.display = 'none';
                        span.style.display = 'inherit';
                        // no need to display indicative barrier in case of absolute barrier
                        indicativeBarrierTooltip.textContent = '';
                    } else {
                        if(!String(barrier_def).match(/^[+-]/)) barrier_def = barrier['barrier']; // override Defaults value, because it's changing from absolute to relative barrier
                        elm.value = barrier_def;
                        elm.textContent = barrier_def;
                        span.style.display = 'none';
                        tooltip.style.display = 'inherit';
                        if (currentTick && !isNaN(currentTick)) {
                            indicativeBarrierTooltip.textContent = (parseFloat(currentTick) + parseFloat(barrier_def)).toFixed(decimalPlaces);
                        } else {
                            indicativeBarrierTooltip.textContent = '';
                        }
                    }
                    Defaults.set('barrier', elm.value);
                    Defaults.remove('barrier_high', 'barrier_low');
                    return;
                } else if (barrier.count === 2) {
                    document.getElementById('barrier_row').style.display = 'none';
                    document.getElementById('high_barrier_row').setAttribute('style', '');
                    document.getElementById('low_barrier_row').setAttribute('style', '');

                    var high_elm = document.getElementById('barrier_high'),
                        low_elm = document.getElementById('barrier_low'),
                        high_tooltip = document.getElementById('barrier_high_tooltip'),
                        high_span = document.getElementById('barrier_high_span'),
                        low_tooltip = document.getElementById('barrier_low_tooltip'),
                        low_span = document.getElementById('barrier_low_span');

                    var defaults_barrier_high = Defaults.get('barrier_high'), defaults_barrier_low = Defaults.get('barrier_low');
                    var barrier_high = defaults_barrier_high && !isNaN(defaults_barrier_high) ? defaults_barrier_high : barrier['barrier'],
                        barrier_low  = defaults_barrier_low  && !isNaN(defaults_barrier_low)  ? defaults_barrier_low  : barrier['barrier1'];
                    if (unit && unit.value === 'd') {
                        if (currentTick && !isNaN(currentTick) && String(barrier_high).match(/^[+-]/)) {
                            high_elm.value = (parseFloat(currentTick) + parseFloat(barrier_high)).toFixed(decimalPlaces);
                            high_elm.textContent = (parseFloat(currentTick) + parseFloat(barrier_high)).toFixed(decimalPlaces);

                            low_elm.value = (parseFloat(currentTick) + parseFloat(barrier_low)).toFixed(decimalPlaces);
                            low_elm.textContent = (parseFloat(currentTick) + parseFloat(barrier_low)).toFixed(decimalPlaces);
                        } else {
                            high_elm.value = parseFloat(barrier_high);
                            high_elm.textContent = parseFloat(barrier_high);

                            low_elm.value = parseFloat(barrier_low);
                            low_elm.textContent = parseFloat(barrier_low);
                        }

                        high_tooltip.style.display = 'none';
                        high_span.style.display = 'inherit';
                        low_tooltip.style.display = 'none';
                        low_span.style.display = 'inherit';

                        indicativeHighBarrierTooltip.textContent = '';
                        indicativeLowBarrierTooltip.textContent = '';
                    } else {
                        high_elm.value = barrier_high;
                        high_elm.textContent = barrier_high;

                        low_elm.value = barrier_low;
                        low_elm.textContent = barrier_low;

                        high_span.style.display = 'none';
                        high_tooltip.style.display = 'inherit';
                        low_span.style.display = 'none';
                        low_tooltip.style.display = 'inherit';

                        if (currentTick && !isNaN(currentTick)) {
                            indicativeHighBarrierTooltip.textContent = (parseFloat(currentTick) + parseFloat(barrier_high)).toFixed(decimalPlaces);
                            indicativeLowBarrierTooltip.textContent = (parseFloat(currentTick) + parseFloat(barrier_low)).toFixed(decimalPlaces);
                        } else {
                            indicativeHighBarrierTooltip.textContent = '';
                            indicativeLowBarrierTooltip.textContent = '';
                        }
                    }
                    Defaults.set('barrier_high', high_elm.value);
                    Defaults.set('barrier_low', low_elm.value);
                    Defaults.remove('barrier');
                    return;
                }
            }
        }

        var elements = document.getElementsByClassName('barrier_class');
        for (var i = 0; i < elements.length; i++){
            elements[i].style.display = 'none';
        }
        Defaults.remove('barrier', 'barrier_high', 'barrier_low');
    };

    return {
        display: display,
        isBarrierUpdated: function () { return isBarrierUpdated; },
        setBarrierUpdate: function (flag) {
            isBarrierUpdated = flag;
        }
    };
})();
<commit_msg>Fix for high/low barrier<commit_after>/*
 * Handles barrier processing and display
 *
 * It process `Contract.barriers` and display them if its applicable
 * for current `Contract.form()
 */

var Barriers = (function () {
    'use strict';

    var isBarrierUpdated = false;

    var display = function (barrierCategory) {
        var barriers = Contract.barriers()[Defaults.get('underlying')],
            formName = Contract.form();

        if (barriers && formName && Defaults.get('formname')!=='risefall') {
            var barrier = barriers[formName];
            if(barrier) {
                var unit = document.getElementById('duration_units'),
                    end_time = document.getElementById('expiry_date'),
                    currentTick = Tick.quote(),
                    indicativeBarrierTooltip = document.getElementById('indicative_barrier_tooltip'),
                    indicativeHighBarrierTooltip = document.getElementById('indicative_high_barrier_tooltip'),
                    indicativeLowBarrierTooltip = document.getElementById('indicative_low_barrier_tooltip'),
                    decimalPlaces = countDecimalPlaces(currentTick);

                if (barrier.count === 1) {
                    document.getElementById('high_barrier_row').style.display = 'none';
                    document.getElementById('low_barrier_row').style.display = 'none';
                    document.getElementById('barrier_row').setAttribute('style', '');

                    var defaults_barrier = Defaults.get('barrier');
                    var barrier_def = defaults_barrier && !isNaN(defaults_barrier) ? defaults_barrier : barrier['barrier'];
                    var elm = document.getElementById('barrier'),
                        tooltip = document.getElementById('barrier_tooltip'),
                        span = document.getElementById('barrier_span');
                    if ((unit && isVisible(unit) && unit.value === 'd') || (end_time && isVisible(end_time) && moment(end_time.value).isAfter(moment(),'day'))) {
                        if (currentTick && !isNaN(currentTick) && String(barrier_def).match(/^[+-]/)) {
                            elm.value = (parseFloat(currentTick) + parseFloat(barrier_def)).toFixed(decimalPlaces);
                            elm.textContent = (parseFloat(currentTick) + parseFloat(barrier_def)).toFixed(decimalPlaces);
                        } else {
                            elm.value = parseFloat(barrier_def);
                            elm.textContent = parseFloat(barrier_def);
                        }
                        tooltip.style.display = 'none';
                        span.style.display = 'inherit';
                        // no need to display indicative barrier in case of absolute barrier
                        indicativeBarrierTooltip.textContent = '';
                    } else {
                        if(!String(barrier_def).match(/^[+-]/)) barrier_def = barrier['barrier']; // override Defaults value, because it's changing from absolute to relative barrier
                        elm.value = barrier_def;
                        elm.textContent = barrier_def;
                        span.style.display = 'none';
                        tooltip.style.display = 'inherit';
                        if (currentTick && !isNaN(currentTick)) {
                            indicativeBarrierTooltip.textContent = (parseFloat(currentTick) + parseFloat(barrier_def)).toFixed(decimalPlaces);
                        } else {
                            indicativeBarrierTooltip.textContent = '';
                        }
                    }
                    Defaults.set('barrier', elm.value);
                    Defaults.remove('barrier_high', 'barrier_low');
                    return;
                } else if (barrier.count === 2) {
                    document.getElementById('barrier_row').style.display = 'none';
                    document.getElementById('high_barrier_row').setAttribute('style', '');
                    document.getElementById('low_barrier_row').setAttribute('style', '');

                    var high_elm = document.getElementById('barrier_high'),
                        low_elm = document.getElementById('barrier_low'),
                        high_tooltip = document.getElementById('barrier_high_tooltip'),
                        high_span = document.getElementById('barrier_high_span'),
                        low_tooltip = document.getElementById('barrier_low_tooltip'),
                        low_span = document.getElementById('barrier_low_span');

                    var defaults_barrier_high = Defaults.get('barrier_high'), defaults_barrier_low = Defaults.get('barrier_low');
                    var barrier_high = defaults_barrier_high && !isNaN(defaults_barrier_high) ? defaults_barrier_high : barrier['barrier'],
                        barrier_low  = defaults_barrier_low  && !isNaN(defaults_barrier_low)  ? defaults_barrier_low  : barrier['barrier1'];
                    if ((unit && isVisible(unit) && unit.value === 'd') ||
                        (end_time && isVisible(end_time) && moment(end_time.value).isAfter(moment(),'day')) ||
                        !String(barrier['barrier']).match(/^[+-]/)) {
                        if (currentTick && !isNaN(currentTick) && String(barrier_high).match(/^[+-]/)) {
                            high_elm.value = (parseFloat(currentTick) + parseFloat(barrier_high)).toFixed(decimalPlaces);
                            high_elm.textContent = (parseFloat(currentTick) + parseFloat(barrier_high)).toFixed(decimalPlaces);

                            low_elm.value = (parseFloat(currentTick) + parseFloat(barrier_low)).toFixed(decimalPlaces);
                            low_elm.textContent = (parseFloat(currentTick) + parseFloat(barrier_low)).toFixed(decimalPlaces);
                        } else {
                            high_elm.value = parseFloat(barrier_high);
                            high_elm.textContent = parseFloat(barrier_high);

                            low_elm.value = parseFloat(barrier_low);
                            low_elm.textContent = parseFloat(barrier_low);
                        }

                        high_tooltip.style.display = 'none';
                        high_span.style.display = 'inherit';
                        low_tooltip.style.display = 'none';
                        low_span.style.display = 'inherit';

                        indicativeHighBarrierTooltip.textContent = '';
                        indicativeLowBarrierTooltip.textContent = '';
                    } else {
                        // override Defaults value, if it's changing from absolute to relative barrier
                        if(!String(barrier_high).match(/^[+-]/) || !String(barrier_low).match(/^[+-]/)) {
                            barrier_high = barrier['barrier'];
                            barrier_low  = barrier['barrier1'];
                        }
                        high_elm.value = barrier_high;
                        high_elm.textContent = barrier_high;

                        low_elm.value = barrier_low;
                        low_elm.textContent = barrier_low;

                        high_span.style.display = 'none';
                        high_tooltip.style.display = 'inherit';
                        low_span.style.display = 'none';
                        low_tooltip.style.display = 'inherit';

                        if (currentTick && !isNaN(currentTick)) {
                            indicativeHighBarrierTooltip.textContent = (parseFloat(currentTick) + parseFloat(barrier_high)).toFixed(decimalPlaces);
                            indicativeLowBarrierTooltip.textContent = (parseFloat(currentTick) + parseFloat(barrier_low)).toFixed(decimalPlaces);
                        } else {
                            indicativeHighBarrierTooltip.textContent = '';
                            indicativeLowBarrierTooltip.textContent = '';
                        }
                    }
                    Defaults.set('barrier_high', high_elm.value);
                    Defaults.set('barrier_low', low_elm.value);
                    Defaults.remove('barrier');
                    return;
                }
            }
        }

        var elements = document.getElementsByClassName('barrier_class');
        for (var i = 0; i < elements.length; i++){
            elements[i].style.display = 'none';
        }
        Defaults.remove('barrier', 'barrier_high', 'barrier_low');
    };

    return {
        display: display,
        isBarrierUpdated: function () { return isBarrierUpdated; },
        setBarrierUpdate: function (flag) {
            isBarrierUpdated = flag;
        }
    };
})();
<|endoftext|>


<commit_before>/* global angular, Evaporate, evaporateOptions */
;(function (Evaporate, evaporateOptions) {
  'use strict';

  angular
    .module('evaporate', [])

    .factory('eva', [function () {
      return {
        _: new Evaporate(evaporateOptions),
        urlBase: 'http://' + evaporateOptions.bucket + '.s3.amazonaws.com/'
      };
    }])

    .directive('evaporate', ['eva', function (eva) {

      function link (scope, element) {

        function foo () {}

        function indexOf (arr, obj) {
          var imax = arr.length;
          for (var i = 0; i < imax; i++) if (angular.equals(arr[i], obj)) return i;
          return -1;
        }

        // allocate eva's data
        if (!scope.data) scope.data = {};

        // apply defaults for input parameters
        var data = scope.data,
            dir = data.dir ? (data.dir + '/') : '',
            timestampSeparator = data.timestampSeparator || '$',
            headersCommon = data.headersCommon || {},
            headersSigned = data.headersSigned || {},
            onFileProgress = (typeof data.onFileProgress === 'function' ? data.onFileProgress : foo),
            onFileComplete = (typeof data.onFileComplete === 'function' ? data.onFileComplete : foo),
            onFileError = (typeof data.onFileError === 'function' ? data.onFileError : foo);

        // expose some info for parent scope
        data.ready = false;
        data.files = [];

        // ready..
        if (eva._.supported) {

          // ..steady..
          element.bind('change', function (event) {

            // process added files
            angular.forEach(event.target.files, function (file) {

              // process file attrs
              file.started = Date.now();
              file.path_ = dir + file.started + timestampSeparator + file.name;
              file.url = eva.urlBase + file.path_;

              // queue file for upload
              eva._.add({

                // filename, relative to bucket
                name: file.path_,

                // content
                file: file,

                // headers
                contentType: file.type || 'binary/octet-stream',
                notSignedHeadersAtInitiate: headersCommon,
                xAmzHeadersAtInitiate:      headersSigned,

                // event callbacks
                complete: function () {

                  // check file as completed
                  file.completed = true;

                  // execute user's callback
                  onFileComplete(file);

                  // update ui
                  scope.$apply();
                },
                progress: function (progress) {

                  // update progress
                  file.progress = Math.round(progress * 10000) / 100;
                  file.timeLeft = Math.round(
                    (100 - file.progress) / file.progress *
                    (Date.now() - file.started) / 1000
                  );

                  // execute user's callback
                  onFileProgress(file);

                  // update ui
                  scope.$apply();
                },
                error: function (message) {

                  // remove file from the queue
                  var index = indexOf(data.files, file);
                  if (index !== -1) data.files.splice(index, 1);

                  // execute user's callback
                  onFileError(file, message);

                  // update ui
                  scope.$apply();
                }
              });

              // expose file data to model
              data.files.push(file);
            });

            // update ui
            scope.$apply();
          });

          // ..go!
          data.ready = true;
        }
      }

      return {
        restrict: 'A',
        link: link,
        scope: {
          data: '=evaModel'
        }
      };
    }]);

})(Evaporate, evaporateOptions);
<commit_msg>Try to fix Chrome re-upload bug.<commit_after>/* global angular, Evaporate, evaporateOptions */
;(function (Evaporate, evaporateOptions) {
  'use strict';

  angular
    .module('evaporate', [])

    .factory('eva', [function () {
      return {
        _: new Evaporate(evaporateOptions),
        urlBase: 'http://' + evaporateOptions.bucket + '.s3.amazonaws.com/'
      };
    }])

    .directive('evaporate', ['eva', function (eva) {

      function link (scope, element) {

        function foo () {}

        function indexOf (arr, obj) {
          var imax = arr.length;
          for (var i = 0; i < imax; i++) if (angular.equals(arr[i], obj)) return i;
          return -1;
        }

        // allocate eva's data
        if (!scope.data) scope.data = {};

        // apply defaults for input parameters
        var data = scope.data,
            dir = data.dir ? (data.dir + '/') : '',
            timestampSeparator = data.timestampSeparator || '$',
            headersCommon = data.headersCommon || {},
            headersSigned = data.headersSigned || {},
            onFileProgress = (typeof data.onFileProgress === 'function' ? data.onFileProgress : foo),
            onFileComplete = (typeof data.onFileComplete === 'function' ? data.onFileComplete : foo),
            onFileError = (typeof data.onFileError === 'function' ? data.onFileError : foo);

        // expose some info for parent scope
        data.ready = false;
        data.files = [];

        // ready..
        if (eva._.supported) {

          // ..steady..
          element.bind('change', function (event) {

            // process added files
            angular.forEach(event.target.files, function (file) {

              // process file attrs
              file.started = Date.now();
              file.path_ = dir + file.started + timestampSeparator + file.name;
              file.url = eva.urlBase + file.path_;

              // queue file for upload
              eva._.add({

                // filename, relative to bucket
                name: file.path_,

                // content
                file: file,

                // headers
                contentType: file.type || 'binary/octet-stream',
                notSignedHeadersAtInitiate: headersCommon,
                xAmzHeadersAtInitiate:      headersSigned,

                // event callbacks
                complete: function () {

                  // check file as completed
                  file.completed = true;

                  // execute user's callback
                  onFileComplete(file);

                  // update ui
                  scope.$apply();
                },
                progress: function (progress) {

                  // update progress
                  file.progress = Math.round(progress * 10000) / 100;
                  file.timeLeft = Math.round(
                    (100 - file.progress) / file.progress *
                    (Date.now() - file.started) / 1000
                  );

                  // execute user's callback
                  onFileProgress(file);

                  // update ui
                  scope.$apply();
                },
                error: function (message) {

                  // remove file from the queue
                  var index = indexOf(data.files, file);
                  if (index !== -1) data.files.splice(index, 1);

                  // execute user's callback
                  onFileError(file, message);

                  // update ui
                  scope.$apply();
                }
              });

              // expose file data to model
              data.files.push(file);
            });

            element.val(null);

            // update ui
            scope.$apply();
          });

          // ..go!
          data.ready = true;
        }
      }

      return {
        restrict: 'A',
        link: link,
        scope: {
          data: '=evaModel'
        }
      };
    }]);

})(Evaporate, evaporateOptions);
<|endoftext|>


<commit_before>import classNames from 'classnames';
import {Form, Tooltip} from 'reactjs-components';
import GeminiScrollbar from 'react-gemini-scrollbar';
import React from 'react';

import GeminiUtil from '../utils/GeminiUtil';
import SideTabs from './SideTabs';
import SchemaFormUtil from '../utils/SchemaFormUtil';
import SchemaUtil from '../utils/SchemaUtil';

const METHODS_TO_BIND = [
  'getTriggerSubmit', 'validateForm', 'handleFormChange', 'handleTabClick',
  'handleExternalSubmit'
];

class SchemaForm extends React.Component {
  constructor() {
    super();

    this.state = {currentTab: ''};

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });

    this.triggerSubmit = function () {};
    this.isValidated = true;
  }

  componentWillMount() {
    if (this.props.definition) {
      this.multipleDefinition = this.props.definition;
    } else {
      this.multipleDefinition = this.getNewDefinition();
    }

    if (this.props.model) {
      this.model = this.props.model;
      SchemaFormUtil.mergeModelIntoDefinition(this.model, this.multipleDefinition);
    } else {
      this.model = {};
    }

    this.submitMap = {};
    this.setState({
      currentTab: Object.keys(this.multipleDefinition)[0]
    });

    this.props.getTriggerSubmit(this.handleExternalSubmit);
  }

  componentDidUpdate() {
    // Timeout necessary due to modal content height updates on did mount
    setTimeout(() => {
      GeminiUtil.updateWithRef(this.refs.geminiForms);
    });
  }

  handleTabClick(currentTab) {
    this.setState({currentTab});
  }

  handleFormChange(formData, eventObj) {
    let isBlur = eventObj.eventType === 'blur';
    let isChange = eventObj.eventType === 'change';

    if (!isBlur && !isChange) {
      return;
    }

    if (isBlur) {
      this.validateForm();
      this.props.onChange(this.getDataTriple());
      return;
    }

    setTimeout(() => {
      this.validateForm();
      this.props.onChange(this.getDataTriple());
    });
  }

  handleFormSubmit(formKey, formModel) {
    this.model[formKey] = formModel;
  }

  handleExternalSubmit() {
    this.validateForm();
    return this.getDataTriple();
  }

  getDataTriple() {
    return {
      isValidated: this.isValidated,
      model: SchemaFormUtil.processFormModel(this.model, this.multipleDefinition),
      definition: this.multipleDefinition
    };
  }

  getNewDefinition() {
    let {model, schema} = this.props;
    let definition = SchemaUtil.schemaToMultipleDefinition(
      schema, this.getSubHeader, this.getLabel
    );

    if (model) {
      SchemaFormUtil.mergeModelIntoDefinition(model, definition);
    }

    return definition;
  }

  buildModel() {
    Object.keys(this.multipleDefinition).forEach((formKey) => {
      this.submitMap[formKey]();
    });
  }

  validateForm() {
    let schema = this.props.schema;
    let isValidated = true;

    this.buildModel();
    // Reset the definition in order to reset all errors.
    this.multipleDefinition = this.getNewDefinition();
    let model = SchemaFormUtil.processFormModel(
      this.model, this.multipleDefinition
    );

    SchemaFormUtil.validateModelWithSchema(model, schema).forEach((error) => {
      let path = error.path;
      let obj = SchemaFormUtil.getDefinitionFromPath(
        this.multipleDefinition, path
      );

      isValidated = false;
      obj.showError = error.message;
      obj.validationErrorText = error.message;
    });

    this.forceUpdate();
    this.isValidated = isValidated;
    return isValidated;
  }

  getTriggerSubmit(formKey, triggerSubmit) {
    this.submitMap[formKey] = triggerSubmit;
  }

  getSubHeader(name) {
    return (

          {name}

    );
  }

  getLabel(description, label) {
    return (

              {label}

            <Tooltip content={description} wrapperClassName="tooltip-wrapper
              media-object-item" wrapText={true} maxWidth={300}
              scrollContainer=".gm-scroll-view">

            </Tooltip>

    );
  }

  getServiceHeader() {
    let {packageIcon, packageName, packageVersion} = this.props;

    return (

                {packageName}

                {packageVersion}

    );
  }

  getHeader(title, description) {
    return (

{title}

{description}

    );
  }

  getSideContent(multipleDefinition) {
    let {currentTab} = this.state;

    return (

        <SideTabs
          onTabClick={this.handleTabClick}
          selectedTab={currentTab}
          tabs={Object.values(multipleDefinition)} />

    );
  }

  getFormPanels() {
    let currentTab = this.state.currentTab;
    let multipleDefinition = this.multipleDefinition;

    let panels = Object.keys(multipleDefinition).map((formKey, i) => {
      let panelClassSet = classNames('form', {
        'hidden': currentTab !== formKey
      });

      let {definition, description, title} = multipleDefinition[formKey];
      let formDefinition = [{
        render: this.getHeader.bind(this, title, description)
      }].concat(definition);

      return (

          <Form
            className={panelClassSet}
            formGroupClass="form-group flush"
            definition={formDefinition}
            triggerSubmit={this.getTriggerSubmit.bind(this, formKey)}
            onChange={this.handleFormChange}
            onSubmit={this.handleFormSubmit.bind(this, formKey)} />

      );
    });

    return (
      <GeminiScrollbar
        autoshow={true}
        className="multiple-form-right-column column-mini-12 column-small-8"
        ref="geminiForms">
        {panels}
      </GeminiScrollbar>
    );
  }

  render() {
    return (

        {this.getServiceHeader()}

          {this.getSideContent(this.multipleDefinition)}
          {this.getFormPanels()}

    );
  }
}

SchemaForm.defaultProps = {
  className: 'multiple-form row',
  getTriggerSubmit: function () {},
  schema: {}
};

SchemaForm.propTypes = {
  getTriggerSubmit: React.PropTypes.func,
  schema: React.PropTypes.object,
  packageIcon: React.PropTypes.string,
  packageName: React.PropTypes.string,
  packageVersion: React.PropTypes.string
};

module.exports = SchemaForm;
<commit_msg>Adding missing class to media-object to remove margin<commit_after>import classNames from 'classnames';
import {Form, Tooltip} from 'reactjs-components';
import GeminiScrollbar from 'react-gemini-scrollbar';
import React from 'react';

import GeminiUtil from '../utils/GeminiUtil';
import SideTabs from './SideTabs';
import SchemaFormUtil from '../utils/SchemaFormUtil';
import SchemaUtil from '../utils/SchemaUtil';

const METHODS_TO_BIND = [
  'getTriggerSubmit', 'validateForm', 'handleFormChange', 'handleTabClick',
  'handleExternalSubmit'
];

class SchemaForm extends React.Component {
  constructor() {
    super();

    this.state = {currentTab: ''};

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });

    this.triggerSubmit = function () {};
    this.isValidated = true;
  }

  componentWillMount() {
    if (this.props.definition) {
      this.multipleDefinition = this.props.definition;
    } else {
      this.multipleDefinition = this.getNewDefinition();
    }

    if (this.props.model) {
      this.model = this.props.model;
      SchemaFormUtil.mergeModelIntoDefinition(this.model, this.multipleDefinition);
    } else {
      this.model = {};
    }

    this.submitMap = {};
    this.setState({
      currentTab: Object.keys(this.multipleDefinition)[0]
    });

    this.props.getTriggerSubmit(this.handleExternalSubmit);
  }

  componentDidUpdate() {
    // Timeout necessary due to modal content height updates on did mount
    setTimeout(() => {
      GeminiUtil.updateWithRef(this.refs.geminiForms);
    });
  }

  handleTabClick(currentTab) {
    this.setState({currentTab});
  }

  handleFormChange(formData, eventObj) {
    let isBlur = eventObj.eventType === 'blur';
    let isChange = eventObj.eventType === 'change';

    if (!isBlur && !isChange) {
      return;
    }

    if (isBlur) {
      this.validateForm();
      this.props.onChange(this.getDataTriple());
      return;
    }

    setTimeout(() => {
      this.validateForm();
      this.props.onChange(this.getDataTriple());
    });
  }

  handleFormSubmit(formKey, formModel) {
    this.model[formKey] = formModel;
  }

  handleExternalSubmit() {
    this.validateForm();
    return this.getDataTriple();
  }

  getDataTriple() {
    return {
      isValidated: this.isValidated,
      model: SchemaFormUtil.processFormModel(this.model, this.multipleDefinition),
      definition: this.multipleDefinition
    };
  }

  getNewDefinition() {
    let {model, schema} = this.props;
    let definition = SchemaUtil.schemaToMultipleDefinition(
      schema, this.getSubHeader, this.getLabel
    );

    if (model) {
      SchemaFormUtil.mergeModelIntoDefinition(model, definition);
    }

    return definition;
  }

  buildModel() {
    Object.keys(this.multipleDefinition).forEach((formKey) => {
      this.submitMap[formKey]();
    });
  }

  validateForm() {
    let schema = this.props.schema;
    let isValidated = true;

    this.buildModel();
    // Reset the definition in order to reset all errors.
    this.multipleDefinition = this.getNewDefinition();
    let model = SchemaFormUtil.processFormModel(
      this.model, this.multipleDefinition
    );

    SchemaFormUtil.validateModelWithSchema(model, schema).forEach((error) => {
      let path = error.path;
      let obj = SchemaFormUtil.getDefinitionFromPath(
        this.multipleDefinition, path
      );

      isValidated = false;
      obj.showError = error.message;
      obj.validationErrorText = error.message;
    });

    this.forceUpdate();
    this.isValidated = isValidated;
    return isValidated;
  }

  getTriggerSubmit(formKey, triggerSubmit) {
    this.submitMap[formKey] = triggerSubmit;
  }

  getSubHeader(name) {
    return (

          {name}

    );
  }

  getLabel(description, label) {
    return (

              {label}

            <Tooltip content={description} wrapperClassName="tooltip-wrapper
              media-object-item" wrapText={true} maxWidth={300}
              scrollContainer=".gm-scroll-view">

            </Tooltip>

    );
  }

  getServiceHeader() {
    let {packageIcon, packageName, packageVersion} = this.props;

    return (

                {packageName}

                {packageVersion}

    );
  }

  getHeader(title, description) {
    return (

{title}

{description}

    );
  }

  getSideContent(multipleDefinition) {
    let {currentTab} = this.state;

    return (

        <SideTabs
          onTabClick={this.handleTabClick}
          selectedTab={currentTab}
          tabs={Object.values(multipleDefinition)} />

    );
  }

  getFormPanels() {
    let currentTab = this.state.currentTab;
    let multipleDefinition = this.multipleDefinition;

    let panels = Object.keys(multipleDefinition).map((formKey, i) => {
      let panelClassSet = classNames('form', {
        'hidden': currentTab !== formKey
      });

      let {definition, description, title} = multipleDefinition[formKey];
      let formDefinition = [{
        render: this.getHeader.bind(this, title, description)
      }].concat(definition);

      return (

          <Form
            className={panelClassSet}
            formGroupClass="form-group flush"
            definition={formDefinition}
            triggerSubmit={this.getTriggerSubmit.bind(this, formKey)}
            onChange={this.handleFormChange}
            onSubmit={this.handleFormSubmit.bind(this, formKey)} />

      );
    });

    return (
      <GeminiScrollbar
        autoshow={true}
        className="multiple-form-right-column column-mini-12 column-small-8"
        ref="geminiForms">
        {panels}
      </GeminiScrollbar>
    );
  }

  render() {
    return (

        {this.getServiceHeader()}

          {this.getSideContent(this.multipleDefinition)}
          {this.getFormPanels()}

    );
  }
}

SchemaForm.defaultProps = {
  className: 'multiple-form row',
  getTriggerSubmit: function () {},
  schema: {}
};

SchemaForm.propTypes = {
  getTriggerSubmit: React.PropTypes.func,
  schema: React.PropTypes.object,
  packageIcon: React.PropTypes.string,
  packageName: React.PropTypes.string,
  packageVersion: React.PropTypes.string
};

module.exports = SchemaForm;
<|endoftext|>


<commit_before>import classNames from 'classnames';
import mixin from 'reactjs-mixin';
/* eslint-disable no-unused-vars */
import React from 'react';
/* eslint-enable no-unused-vars */
import {StoreMixin} from 'mesosphere-shared-reactjs';

import CompositeState from '../structs/CompositeState';
import DescriptionList from './DescriptionList';
import MarathonStore from '../stores/MarathonStore';
import MesosStateStore from '../stores/MesosStateStore';
import MesosSummaryStore from '../stores/MesosSummaryStore';
import ResourceTypes from '../constants/ResourceTypes';
import RequestErrorMsg from './RequestErrorMsg';
import ServicesBreadcrumb from './ServicesBreadcrumb';
import TaskDebugView from './TaskDebugView';
import TaskDirectoryView from './TaskDirectoryView';
import TaskDirectoryStore from '../stores/TaskDirectoryStore';
import TaskStates from '../constants/TaskStates';
import TaskUtil from '../utils/TaskUtil';
import Units from '../utils/Units';

import InternalStorageMixin from '../mixins/InternalStorageMixin';
import TabsMixin from '../mixins/TabsMixin';

const TABS = {
  files: 'Files',
  details: 'Details',
  debug: 'Log Viewer'
};

const METHODS_TO_BIND = [
  'onTaskDirectoryStoreError',
  'onTaskDirectoryStoreSuccess'
];

class TaskDetail extends mixin(InternalStorageMixin, TabsMixin, StoreMixin) {
  constructor() {
    super(...arguments);

    this.tabs_tabs = Object.assign({}, TABS);

    this.state = {
      currentTab: 'details',
      directory: null,
      expandClass: 'large',
      showExpandButton: false,
      selectedLogFile: null,
      taskDirectoryErrorCount: 0
    };

    this.store_listeners = [
      {name: 'state', events: ['success'], listenAlways: false},
      {name: 'summary', events: ['success'], listenAlways: false},
      {name: 'taskDirectory', events: ['error', 'success']}
    ];

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentDidMount() {
    super.componentDidMount(...arguments);
    this.store_removeEventListenerForStoreID('summary', 'success');
  }

  onStateStoreSuccess() {
    let task = MesosStateStore.getTaskFromTaskID(this.props.params.taskID);
    TaskDirectoryStore.getDirectory(task);
  }

  onTaskDirectoryStoreError() {
    this.setState({
      taskDirectoryErrorCount: this.state.taskDirectoryErrorCount + 1
    });
  }

  onTaskDirectoryStoreSuccess() {
    this.setState({
      directory: TaskDirectoryStore.get('directory'),
      taskDirectoryErrorCount: 0
    });
  }

  hasLoadingError() {
    return this.state.taskDirectoryErrorCount >= 3;
  }

  getErrorScreen() {
    return (

        <RequestErrorMsg />

    );
  }

  getLoadingScreen() {
    return (

    );
  }

  handleOpenLogClick(selectedLogFile) {
    this.setState({selectedLogFile, currentTab: 'debug'});
  }

  getResources(task) {
    if (task.resources == null) {
      return null;
    }

    let resources = Object.keys(task.resources);

    return resources.map(function (resource) {
      if (resource === 'ports') {
        return null;
      }

      let colorIndex = ResourceTypes[resource].colorIndex;
      let resourceLabel = ResourceTypes[resource].label;
      let resourceIconClasses = `icon icon-sprite icon-sprite-medium
        icon-sprite-medium-color icon-resources-${resourceLabel.toLowerCase()}`;
      let resourceValue = Units.formatResource(
        resource, task.resources[resource]
      );
      return (

                  {resourceValue}

                  {resourceLabel.toUpperCase()}

      );
    });
  }

  getBasicInfo(task, node) {
    // Hide when no task or when we are viewing debug tab
    if (task == null || this.state.currentTab === 'debug') {
      return null;
    }

    let statusIcon = TaskUtil.getTaskStatusIcon(task);
    let statusClassName = `${TaskUtil.getTaskStatusClassName(task)} side-panel-subheader`;

    return (

            {task.id}

                {statusIcon}

                  {TaskStates[task.state].displayName}

                  {node.hostname}

          {this.getResources(task)}

    );
  }

  renderDetailsTabView() {
    let task = MesosStateStore.getTaskFromTaskID(this.props.params.taskID);

    if (task == null || !MesosSummaryStore.get('statesProcessed')) {
      return null;
    }

    let node = MesosStateStore.getNodeFromID(task.slave_id);
    let services = MesosSummaryStore.get('states')
      .lastSuccessful()
      .getServiceList();
    let service = services.filter({ids: [task.framework_id]}).last();

    let headerValueMapping = {
      ID: task.id,
      Service: `${service.name} (${service.id})`,
      Node: `${node.hostname} (${node.id})`
    };

    let sandBoxPath = TaskDirectoryStore.get('sandBoxPath');
    if (sandBoxPath) {
      headerValueMapping['Sandbox Path'] = sandBoxPath;
    }

    let labelMapping = {};

    if (task.labels) {
      task.labels.forEach(function (label) {
        labelMapping[label.key] = label.value;
      });
    }

    return (

        <DescriptionList
          className="container container-fluid flush container-pod container-pod-super-short flush-top"
          hash={headerValueMapping}
          headline="Configuration" />
        <DescriptionList
          className="container container-fluid flush container-pod container-pod-super-short flush-top"
          hash={labelMapping}
          headline="Labels" />

    );
  }

  renderFilesTabView() {
    let {state, props} = this;
    let task = MesosStateStore.getTaskFromTaskID(props.params.taskID);
    if (this.hasLoadingError()) {
      this.getErrorScreen();
    }
    if (!state.directory || !task) {
      return this.getLoadingScreen();
    }

    return (

        <TaskDirectoryView
          directory={state.directory}
          task={task}
          onOpenLogClick={this.handleOpenLogClick.bind(this)} />

    );
  }

  renderLogViewerTabView() {
    let {state, props} = this;
    let task = MesosStateStore.getTaskFromTaskID(props.params.taskID);
    if (this.hasLoadingError()) {
      this.getErrorScreen();
    }
    if (!state.directory || !task) {
      return this.getLoadingScreen();
    }

    return (

        <TaskDebugView
          selectedLogFile={state.selectedLogFile}
          showExpandButton={this.showExpandButton}
          directory={state.directory}
          task={task} />

    );
  }

  tabs_handleTabClick() {
    this.setState({selectedLogFile: null});

    // Only call super after we are done removing/adding listeners
    super.tabs_handleTabClick(...arguments);
  }

  getNotFound(itemType) {
    return (

          {`Error finding ${itemType}`}

          {`Did not find a ${itemType} by the id "${this.props.params.taskID}"`}

    );
  }

  getExpandButton() {
    if (!this.state.showExpandButton) {
      return null;
    }

    return (
      <button
        className="button button-stroke button-expand"
        onClick={this.handleExpand}>
      </button>
    );
  }

  render() {
    if (MesosStateStore.get('lastMesosState').slaves == null) {
      return null;
    }

    let task = MesosStateStore.getTaskFromTaskID(this.props.params.taskID);
    let service = MarathonStore.getServiceFromTaskID(this.props.params.taskID);

    if (task == null) {
      return this.getNotFound('task');
    }
    // // console.log(task.framework_id, services, service.getId());
    // // console.log(service.getId());
    // console.log(MarathonStore.get('groups'));

    let node = MesosStateStore.getNodeFromID(task.slave_id);
    let panelClasses = classNames({
      'container container-fluid container-pod container-pod-short container-pod-super-short-top flush': true,
      'container-pod-short': this.state.currentTab === 'debug'
    });

    return (

        <ServicesBreadcrumb serviceTreeItem={service} />
        {this.getExpandButton()}

          {this.getBasicInfo(task, node)}

            {this.tabs_getUnroutedTabs()}

        {this.tabs_getTabView()}

    );
  }
}

module.exports = TaskDetail;
<commit_msg>Align resource status horizontal<commit_after>import classNames from 'classnames';
import mixin from 'reactjs-mixin';
/* eslint-disable no-unused-vars */
import React from 'react';
/* eslint-enable no-unused-vars */
import {StoreMixin} from 'mesosphere-shared-reactjs';

import CompositeState from '../structs/CompositeState';
import DescriptionList from './DescriptionList';
import MarathonStore from '../stores/MarathonStore';
import MesosStateStore from '../stores/MesosStateStore';
import MesosSummaryStore from '../stores/MesosSummaryStore';
import ResourceTypes from '../constants/ResourceTypes';
import RequestErrorMsg from './RequestErrorMsg';
import ServicesBreadcrumb from './ServicesBreadcrumb';
import TaskDebugView from './TaskDebugView';
import TaskDirectoryView from './TaskDirectoryView';
import TaskDirectoryStore from '../stores/TaskDirectoryStore';
import TaskStates from '../constants/TaskStates';
import TaskUtil from '../utils/TaskUtil';
import Units from '../utils/Units';

import InternalStorageMixin from '../mixins/InternalStorageMixin';
import TabsMixin from '../mixins/TabsMixin';

const TABS = {
  files: 'Files',
  details: 'Details',
  debug: 'Log Viewer'
};

const METHODS_TO_BIND = [
  'onTaskDirectoryStoreError',
  'onTaskDirectoryStoreSuccess'
];

class TaskDetail extends mixin(InternalStorageMixin, TabsMixin, StoreMixin) {
  constructor() {
    super(...arguments);

    this.tabs_tabs = Object.assign({}, TABS);

    this.state = {
      currentTab: 'details',
      directory: null,
      expandClass: 'large',
      showExpandButton: false,
      selectedLogFile: null,
      taskDirectoryErrorCount: 0
    };

    this.store_listeners = [
      {name: 'state', events: ['success'], listenAlways: false},
      {name: 'summary', events: ['success'], listenAlways: false},
      {name: 'taskDirectory', events: ['error', 'success']}
    ];

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentDidMount() {
    super.componentDidMount(...arguments);
    this.store_removeEventListenerForStoreID('summary', 'success');
  }

  onStateStoreSuccess() {
    let task = MesosStateStore.getTaskFromTaskID(this.props.params.taskID);
    TaskDirectoryStore.getDirectory(task);
  }

  onTaskDirectoryStoreError() {
    this.setState({
      taskDirectoryErrorCount: this.state.taskDirectoryErrorCount + 1
    });
  }

  onTaskDirectoryStoreSuccess() {
    this.setState({
      directory: TaskDirectoryStore.get('directory'),
      taskDirectoryErrorCount: 0
    });
  }

  hasLoadingError() {
    return this.state.taskDirectoryErrorCount >= 3;
  }

  getErrorScreen() {
    return (

        <RequestErrorMsg />

    );
  }

  getLoadingScreen() {
    return (

    );
  }

  handleOpenLogClick(selectedLogFile) {
    this.setState({selectedLogFile, currentTab: 'debug'});
  }

  getResources(task) {
    if (task.resources == null) {
      return null;
    }

    let resources = Object.keys(task.resources);

    return resources.map(function (resource) {
      if (resource === 'ports') {
        return null;
      }

      let colorIndex = ResourceTypes[resource].colorIndex;
      let resourceLabel = ResourceTypes[resource].label;
      let resourceIconClasses = `icon icon-sprite icon-sprite-medium
        icon-sprite-medium-color icon-resources-${resourceLabel.toLowerCase()}`;
      let resourceValue = Units.formatResource(
        resource, task.resources[resource]
      );
      return (

                  {resourceValue}

                  {resourceLabel.toUpperCase()}

      );
    });
  }

  getBasicInfo(task, node) {
    // Hide when no task or when we are viewing debug tab
    if (task == null || this.state.currentTab === 'debug') {
      return null;
    }

    let statusIcon = TaskUtil.getTaskStatusIcon(task);
    let statusClassName = `${TaskUtil.getTaskStatusClassName(task)} side-panel-subheader`;

    return (

            {task.id}

                {statusIcon}

                  {TaskStates[task.state].displayName}

                  {node.hostname}

          {this.getResources(task)}

    );
  }

  renderDetailsTabView() {
    let task = MesosStateStore.getTaskFromTaskID(this.props.params.taskID);

    if (task == null || !MesosSummaryStore.get('statesProcessed')) {
      return null;
    }

    let node = MesosStateStore.getNodeFromID(task.slave_id);
    let services = MesosSummaryStore.get('states')
      .lastSuccessful()
      .getServiceList();
    let service = services.filter({ids: [task.framework_id]}).last();

    let headerValueMapping = {
      ID: task.id,
      Service: `${service.name} (${service.id})`,
      Node: `${node.hostname} (${node.id})`
    };

    let sandBoxPath = TaskDirectoryStore.get('sandBoxPath');
    if (sandBoxPath) {
      headerValueMapping['Sandbox Path'] = sandBoxPath;
    }

    let labelMapping = {};

    if (task.labels) {
      task.labels.forEach(function (label) {
        labelMapping[label.key] = label.value;
      });
    }

    return (

        <DescriptionList
          className="container container-fluid flush container-pod container-pod-super-short flush-top"
          hash={headerValueMapping}
          headline="Configuration" />
        <DescriptionList
          className="container container-fluid flush container-pod container-pod-super-short flush-top"
          hash={labelMapping}
          headline="Labels" />

    );
  }

  renderFilesTabView() {
    let {state, props} = this;
    let task = MesosStateStore.getTaskFromTaskID(props.params.taskID);
    if (this.hasLoadingError()) {
      this.getErrorScreen();
    }
    if (!state.directory || !task) {
      return this.getLoadingScreen();
    }

    return (

        <TaskDirectoryView
          directory={state.directory}
          task={task}
          onOpenLogClick={this.handleOpenLogClick.bind(this)} />

    );
  }

  renderLogViewerTabView() {
    let {state, props} = this;
    let task = MesosStateStore.getTaskFromTaskID(props.params.taskID);
    if (this.hasLoadingError()) {
      this.getErrorScreen();
    }
    if (!state.directory || !task) {
      return this.getLoadingScreen();
    }

    return (

        <TaskDebugView
          selectedLogFile={state.selectedLogFile}
          showExpandButton={this.showExpandButton}
          directory={state.directory}
          task={task} />

    );
  }

  tabs_handleTabClick() {
    this.setState({selectedLogFile: null});

    // Only call super after we are done removing/adding listeners
    super.tabs_handleTabClick(...arguments);
  }

  getNotFound(itemType) {
    return (

          {`Error finding ${itemType}`}

          {`Did not find a ${itemType} by the id "${this.props.params.taskID}"`}

    );
  }

  getExpandButton() {
    if (!this.state.showExpandButton) {
      return null;
    }

    return (
      <button
        className="button button-stroke button-expand"
        onClick={this.handleExpand}>
      </button>
    );
  }

  render() {
    if (MesosStateStore.get('lastMesosState').slaves == null) {
      return null;
    }

    let task = MesosStateStore.getTaskFromTaskID(this.props.params.taskID);
    let service = MarathonStore.getServiceFromTaskID(this.props.params.taskID);

    if (task == null) {
      return this.getNotFound('task');
    }
    // // console.log(task.framework_id, services, service.getId());
    // // console.log(service.getId());
    // console.log(MarathonStore.get('groups'));

    let node = MesosStateStore.getNodeFromID(task.slave_id);
    let panelClasses = classNames({
      'container container-fluid container-pod container-pod-short container-pod-super-short-top flush': true,
      'container-pod-short': this.state.currentTab === 'debug'
    });

    return (

        <ServicesBreadcrumb serviceTreeItem={service} />
        {this.getExpandButton()}

          {this.getBasicInfo(task, node)}

            {this.tabs_getUnroutedTabs()}

        {this.tabs_getTabView()}

    );
  }
}

module.exports = TaskDetail;
<|endoftext|>


<commit_before>import React from 'react';
import render from 'react-test-renderer';
import { shallow } from 'enzyme';
import Title from './Title';
import { singleLine } from '../../../test/test-helper';

it('renders', () => {
  const wrapper = shallow(<Title />);
  expect(wrapper.length).toBe(1);
});

it('matches snapshot', () => {
  const tree = render.create(<Title />).toJSON();
  expect(tree).toMatchSnapshot();
});

it('renders heading when has one child', () => {
  const wrapper = shallow(<Title>Hello</Title>);
  expect(wrapper.html()).toBe('
Hello
');
});

it('accepts className', () => {
  const wrapper = shallow(<Title className="test">Hello</Title>);
  expect(wrapper.html()).toBe('
Hello
');
});

it('renders <hgroup> when has multiple children', () => {
  const wrapper = shallow(
    <Title>

Hello

World

    </Title>,
  );
  const expected = singleLine`
    <hgroup class="title">

Hello

World

    </hgroup>
  `;
  expect(wrapper.html()).toBe(expected);
});
<commit_msg>Use snapshots in Title tests<commit_after>import React from 'react';
import render from 'react-test-renderer';
import Title from './Title';

it('renders heading', () => {
  const tree = render.create(<Title>Test</Title>);
  expect(tree.toJSON()).toMatchSnapshot();
});

it('renders group of headings', () => {
  const tree = render.create(
    <Title>

Hello

World

    </Title>,
  );
  expect(tree.toJSON()).toMatchSnapshot();
});

it('accepts class name', () => {
  const tree = render.create(<Title className="test">Test</Title>);
  expect(tree.toJSON()).toMatchSnapshot();
});
<|endoftext|>


<commit_before>'use strict';

var DialogCtrl = function($scope, dialog) {

    //
    // scope state
    //

    $scope.state.dialog = {
        open: false
    };

    //
    // Set dialog disply functions
    //

    dialog.displayInfo = function(options) {
        setOptions(options);
    };

    dialog.displayError = function(options) {
        if (!options) {
            return;
        }

        setOptions(options);
        $scope.title = options.title || 'Error';
        $scope.showBugReporter = (typeof options.showBugReporter !== 'undefined' ? options.showBugReporter : !options.title); // if title is set, presume it's not an error by default
    };

    dialog.displayConfirm = function(options) {
        setOptions(options);
    };

    function setOptions(options) {
        $scope.state.dialog.open = true;
        $scope.title = options.title;
        $scope.message = options.errMsg || options.message;
        $scope.faqLink = options.faqLink;
        $scope.positiveBtnStr = options.positiveBtnStr || 'Ok';
        $scope.negativeBtnStr = options.negativeBtnStr || 'Cancel';
        $scope.showNegativeBtn = options.showNegativeBtn || false;
        $scope.callback = options.callback;
    }

    //
    // Scope functions
    //

    $scope.confirm = function(ok) {
        $scope.state.dialog.open = false;

        if ($scope.callback) {
            $scope.callback(ok);
        }
        $scope.callback = undefined;
    };
};

module.exports = DialogCtrl;<commit_msg>Reset showBugReporter in dialog before each display<commit_after>'use strict';

var DialogCtrl = function($scope, dialog) {

    //
    // scope state
    //

    $scope.state.dialog = {
        open: false
    };

    //
    // Set dialog disply functions
    //

    dialog.displayInfo = function(options) {
        setOptions(options);
    };

    dialog.displayError = function(options) {
        if (!options) {
            return;
        }

        setOptions(options);
        $scope.title = options.title || 'Error';
        $scope.showBugReporter = (typeof options.showBugReporter !== 'undefined' ? options.showBugReporter : !options.title); // if title is set, presume it's not an error by default
    };

    dialog.displayConfirm = function(options) {
        setOptions(options);
    };

    function setOptions(options) {
        $scope.state.dialog.open = true;
        $scope.title = options.title;
        $scope.message = options.errMsg || options.message;
        $scope.faqLink = options.faqLink;
        $scope.positiveBtnStr = options.positiveBtnStr || 'Ok';
        $scope.negativeBtnStr = options.negativeBtnStr || 'Cancel';
        $scope.showNegativeBtn = options.showNegativeBtn || false;
        $scope.showBugReporter = false;
        $scope.callback = options.callback;
    }

    //
    // Scope functions
    //

    $scope.confirm = function(ok) {
        $scope.state.dialog.open = false;

        if ($scope.callback) {
            $scope.callback(ok);
        }
        $scope.callback = undefined;
    };
};

module.exports = DialogCtrl;<|endoftext|>


<commit_before>import React from 'react'
import io from 'socket.io-client'
import CampList from './CampList'
import Analytics from '../../analytics/Analytics'
import CommentParent from '../comments/CommentParent'
import { connect } from 'react-redux'
import { getComments, createCommentSuccess, contributedOnce } from '../comments/commentActions'
import { Button, Glyphicon, Panel, Col, Row, Grid } from 'react-bootstrap';
require('./camp.css')

class Camp extends React.Component{
  constructor(props){
    super(props)
    this.state = {
      showComments: false,
      hasFetched: false,
      ioNamespace: null,
      showChart: false,
      showModal: false
    }
  }

  fetchComments(campId) {
    this.disconnectFromPrev();
    var context = this;
    window.socket = io(`/${campId}`)
    window.socket.on('cgConnection', (data)=> {
      console.log('connected to commonground', data)
      this.setState({
        ioNamespace: data.namespace
      })
    });
    window.socket.on('comment', (data) => {
      this.props.createCommentSuccess(data)
      this.props.contributedOnce()
    })
    this.props.getComments(campId)
    this.setState({
      showComments: !this.state.showComments
    })
  }

  disconnectFromPrev() {
    if(window.socket) {
      window.socket.disconnect()
      console.log('disconnected from sockets!!!!!')
    }
  }

  render() {
    const campName = (

 this.fetchComments(this.props.campId)}>{this.props.inputStr}

    );

    return (
      <Col md={6}>
        <Panel header={campName} className='campBox'>
          {this.state.showComments && <Analytics campId={this.props.campId} />}
          {this.state.showComments && <CommentParent campId={this.props.campId} nsp={this.state.ioNamespace}/>}
        </Panel>
      </Col>
    )
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    getComments: (campId) => {
      dispatch(getComments(campId))
    },
    createCommentSuccess: (campId) => {
      dispatch(createCommentSuccess(campId))
    },
    contributedOnce: () => {
      dispatch(contributedOnce())
    }
  }
}

export default connect(null, mapDispatchToProps)(Camp)<commit_msg>update to camp component<commit_after>import React from 'react'
import io from 'socket.io-client'
import CampList from './CampList'
import Analytics from '../../analytics/Analytics'
import CommentParent from '../comments/CommentParent'
import { connect } from 'react-redux'
import { getComments, createCommentSuccess, contributedOnce } from '../comments/commentActions'
import { Button, Glyphicon, Panel, Col, Row, Grid } from 'react-bootstrap';
require('./camp.css')

class Camp extends React.Component{
  constructor(props){
    super(props)
    this.state = {
      showComments: false,
      hasFetched: false,
      ioNamespace: null,
      showChart: false,
      showModal: false
    }
  }

  fetchComments(campId) {
    this.disconnectFromPrev();
    var context = this;
    window.socket = io(`/${campId}`)
    window.socket.on('cgConnection', (data)=> {
      console.log('connected to commonground', data)
      this.setState({
        ioNamespace: data.namespace
      })
    });
    window.socket.on('comment', (data) => {
      this.props.createCommentSuccess(data)
      this.props.contributedOnce()
    })
    this.props.getComments(campId)
    this.setState({
      showComments: !this.state.showComments
    })
  }

  disconnectFromPrev() {
    if(window.socket) {
      window.socket.disconnect()
      console.log('disconnected from sockets!!!!!')
    }
  }

  render() {
    const campName = (

{this.props.inputStr}

    );

    return (
      <Col md={6}>
        <Panel header={campName} className='campBox' onClick={()=> this.fetchComments(this.props.campId)}>
          {this.state.showComments && <Analytics campId={this.props.campId} />}
          {this.state.showComments && <CommentParent campId={this.props.campId} nsp={this.state.ioNamespace}/>}
        </Panel>
      </Col>
    )
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    getComments: (campId) => {
      dispatch(getComments(campId))
    },
    createCommentSuccess: (campId) => {
      dispatch(createCommentSuccess(campId))
    },
    contributedOnce: () => {
      dispatch(contributedOnce())
    }
  }
}

export default connect(null, mapDispatchToProps)(Camp)<|endoftext|>


<commit_before>/**
 * Author: Jeff Whelpley
 * Date: 2/20/14
 *
 * This is where services are generated
 */
var Q =             require('q');
var _ =             require('lodash');
var fs =            require('fs');
var p =             require('path');
var utils =         require('../utensils');
var eventBus =      require('../server.event.bus');
var debugHandler =  require('../debug.handler');

/**
 * Simple function to clear the cache
 * @param injector
 * @constructor
 */
function ServiceFactory(injector) {
    this.cache = {};
    this.injector = injector || {};

    // if we are in debug mode, then add the debug handler
    var pattern = this.injector.debugPattern || '*.*.*.*.*';
    var handler = this.injector.debugHandler || debugHandler;
    if (this.injector.debug) {
        eventBus.on(pattern, handler);
    }
}

_.extend(ServiceFactory.prototype, {

    /**
     * Candidate if no slash and the modulePath ends in 'Service'
     * @param modulePath
     * @returns {boolean}
     */
    isCandidate: function isCandidate(modulePath) {
        modulePath = modulePath || '';
        var len = modulePath.length;
        return modulePath.indexOf('/') < 0 && len > 7 &&
            modulePath.substring(modulePath.length - 7) === 'Service';
    },

    /**
     * Simply empty the service cache
     */
    clearCache: function clearCache() {
        this.cache = {};
    },

    /**
     * Create a new service (or pull it from cache if it already exists)
     *
     * @param serviceName
     * @param moduleStack
     * @returns {{}}
     */
    create: function create(serviceName, moduleStack) {

        // if the service already exists in cache, then just return it right away
        if (this.cache[serviceName]) {
            return this.cache[serviceName];
        }

        // get all the parts of the service
        var serviceInfo = this.getServiceInfo(serviceName, this.injector.adapterMap);
        var resource = this.getResource(serviceInfo, moduleStack);
        var adapter = this.getAdapter(serviceInfo, resource, moduleStack);

        // check the cache again because the service name may change if it is a default
        if (this.cache[serviceInfo.serviceName]) {
            return this.cache[serviceInfo.serviceName];
        }

        // construct the service, save it to cache and return it
        var service = this.putItAllTogether(serviceInfo, resource, adapter);
        this.cache[serviceInfo.serviceName] = service;
        return service;
    },

    /**
     * Figure out information about the service based on the module path and the adapter map
     *
     * @param serviceName
     * @param adapterMap
     * @returns {{}}
     */
    getServiceInfo: function getServiceInfo(serviceName, adapterMap) {
        var serviceInfo = { serviceName: serviceName };
        var serviceParts = utils.splitCamelCase(serviceName);  // turn oneTwoThree into ['one', 'two', 'three']
        var nbrParts = serviceParts.length;

        // first check to see if the second to last part is an adapter
        serviceInfo.adapterName = serviceParts[nbrParts - 2];  // NOTE: last item in array is 'Service'
        if (adapterMap[serviceInfo.adapterName]) {
            serviceInfo.resourceName = serviceParts.slice(0, nbrParts - 2).join('.');
        }
        // if not, it means we are dealing with a straight service (ex. postService)
        else {
            serviceInfo.adapterName = 'service';
            serviceInfo.resourceName = serviceParts.slice(0, nbrParts - 1).join('.');
        }

        serviceInfo.adapterImpl = adapterMap[serviceInfo.adapterName];

        return serviceInfo;
    },

    /**
     * Get a resource based on the
     * @param serviceInfo
     * @param moduleStack
     * @returns {{}} A resource object
     */
    getResource: function getResource(serviceInfo, moduleStack) {
        var resourceName = serviceInfo.resourceName;
        var resourcePath = '/resources/' + resourceName + '/' + resourceName + '.resource';
        return this.loadIfExists(resourcePath, moduleStack, 'Could not find resource file');
    },

    /**
     * Get a adapter based on the service info and what exists on the file system
     *
     * @param serviceInfo
     * @param resource
     * @param moduleStack
     */
    getAdapter: function getAdapter(serviceInfo, resource, moduleStack) {
        var adapterName = serviceInfo.adapterName;

        // if adapter name is 'service' and there is a default, switch to the default
        if (adapterName === 'service' && resource.adapters[this.injector.container]) {
            adapterName = serviceInfo.adapterName = resource.adapters[this.injector.container];
            serviceInfo.adapterImpl = this.injector.adapterMap[adapterName];
            serviceInfo.serviceName = utils.getCamelCase(serviceInfo.resourceName + '.' +
                serviceInfo.adapterName + '.service');
        }

        // if that doesn't work, we will assume the adapter is in the current codebase, so go get it
        var overridePath = '/resources/' + serviceInfo.resourceName + '/' + serviceInfo.resourceName + '.' +
            (adapterName === 'service' ? adapterName : adapterName + '.service');
        var adapterPath = '/adapters/' + adapterName + '/' +
            serviceInfo.adapterImpl + '.' + adapterName + '.adapter';

        // if override exists, use that one, else use the lower level adapter
        var Adapter =
            this.loadIfExists(overridePath, moduleStack, null) ||
            this.injector.adapters[serviceInfo.adapterImpl] ||
            this.loadIfExists(adapterPath, moduleStack, null);

        // if still no adapter found, then there is an issue
        if (!Adapter) {
            throw new Error('ServiceFactory could not find adapter ' + adapterName +
            ' paths ' + overridePath + ' and ' + adapterPath);
        }

        return new Adapter(resource);
    },

    /**
     * Load a module if it exists
     * @param path
     * @param moduleStack
     * @param errMsg
     * @returns {*}
     */
    loadIfExists: function loadIfExists(path, moduleStack, errMsg) {
        var servicesDir = this.injector.servicesDir;
        var servicesFullPath = this.injector.rootDir + '/' + servicesDir;

        // if the file doesn't exist, either throw an error (if msg passed in), else just return null
        if (!fs.existsSync(p.join(servicesFullPath, path + '.js'))) {
            if (errMsg) {
                throw new Error(errMsg + ' ' + servicesFullPath + path + '.js');
            }
            else {
                return null;
            }
        }

        // else load the module
        return this.injector.loadModule(servicesDir + path, moduleStack);
    },

    /**
     * Take all the objects involved with a service and put them all together. The final service is really
     * just an instance of an adapter with each method enhanced to have various filters added
     *
     * @param serviceInfo
     * @param resource
     * @param adapter
     * @returns {{}}
     */
    putItAllTogether: function putItAllTogether(serviceInfo, resource, adapter) {
        var me = this;
        var debug = this.injector.debug;

        // loop through the methods
        _.each(resource.methods[serviceInfo.adapterName], function (method) {
            if (!adapter[method]) {
                return;
            }

            // we are going to monkey patch the target method on the adapter, so save the original method
            var origMethod = adapter[method].bind(adapter);
            var eventNameBase = {
                resource: serviceInfo.resourceName,
                adapter: serviceInfo.adapterName,
                method: method
            };

            // create the new service function
            adapter[method] = function (req) {
                req = req || {};

                // clean out request
                _.each(req, function (value, name) {
                    if (value && value === 'undefined') {
                        delete req[name];
                    }
                });

                // add event for data before anything happens (used only for debugging)
                if (debug) { me.emitEvent(req, eventNameBase, { type: 'service', timing: 'before' }); }

                // first validate the request
                return me.validateRequestParams(req, resource, method, serviceInfo.adapterName)
                    .then(function () {

                        // add event before calling the original method (used only for debugging)
                        if (debug) { me.emitEvent(req, eventNameBase, { type: 'service', timing: 'before' }); }

                        // call the original target method on the adapter
                        return origMethod(req);
                    })
                    .then(function (res) {

                        // emit event after origin method called; this is what most
                        // reactors key off of (can be disabled with noemit flag)
                        if (!req.noemit && !req.multi) {
                            var payload = {
                                caller: req.caller,
                                inputId: req._id,
                                targetId: req.targetId,
                                inputData: req.data,
                                data: res
                            };
                            me.emitEvent(payload, eventNameBase, null);
                        }

                        // return the response that will go back to the calling client
                        return res;
                    });
            };
        });

        // so essentially the service is the adapter with each method bulked up with some extra stuff
        return adapter;
    },

    /**
     * This is used to get an mock filter which will be sending out events
     * @param payload
     * @param eventNameBase
     * @param debugParams
     */
    emitEvent: function emitEvent(payload, eventNameBase, debugParams) {

        // create a copy of the payload so that nothing modifies the original object
        payload = JSON.parse(JSON.stringify(payload));

        // we don't want to emit the potentially huge resource file
        if (payload && payload.resource) {
            delete payload.resource;
        }

        // create the event data and emit the event
        var name = _.extend({}, eventNameBase, debugParams);
        var eventData = {
            name: name,
            payload: payload
        };
        var eventName = name.resource + '.' + name.adapter + '.' + name.method;
        eventName += debugParams ? '.' + name.type + '.' + name.timing : '';
        eventBus.emit(eventName, eventData);
    },

    /**
     * Used within a service to validate the input params
     * @param req
     * @param resource
     * @param method
     * @param adapter
     * @returns {*}
     */
    validateRequestParams: function validateRequestParams(req, resource, method, adapter) {
        req = req || {};

        var params = resource.params || {};
        var methodParams = _.extend({}, params[method], params[adapter + '.' + method] );
        var requiredParams = methodParams.required || [];
        var eitherorParams = methodParams.eitheror || [];
        var optional = methodParams.optional || [];
        var eitherorExists, param;
        var err, reqObj;

        // make sure all the required params are there
        for (var i = 0; i < requiredParams.length; i++) {
            param = requiredParams[i];

            if (req[param] === undefined || req[param] === null) {
                reqObj = _.extend({}, req);
                delete reqObj.resource;
                err = new Error('Invalid request');
                err.code = 'invalid_request_error';
                err.message = resource.name + ' ' + method + ' missing ' + param +
                    '. Required params: ' + JSON.stringify(requiredParams) +
                    ' req is: ' + JSON.stringify(reqObj);
                return Q.reject(err);
            }
        }

        // make sure at least one of the eitheror params are there
        if (eitherorParams.length) {
            eitherorExists = false;

            _.each(eitherorParams, function (eitherorParam) {
                if (req[eitherorParam]) { eitherorExists = true; }
            });

            if (!eitherorExists) {
                delete req.caller;
                delete req.resource;
                err = new Error('Invalid request');
                err.code = 'invalid_request_error';
                err.message = resource.name + ' ' + method +
                    ' must have one of the following params: ' + JSON.stringify(eitherorParams) +
                    ' request is ' + JSON.stringify(req);
                return Q.reject(err);
            }
        }

        // now loop through the values and error if invalid param in there; also do JSON parsing if an object
        var validParams = requiredParams.concat(eitherorParams, optional,
            ['lang', 'caller', 'resource', 'method', 'auth', 'noemit']);
        for (var key in req) {
            if (req.hasOwnProperty(key)) {
                if (validParams.indexOf(key) < 0) {
                    delete req.caller;
                    delete req.resource;
                    err = new Error('Invalid request');
                    err.code = 'invalid_request_error';
                    err.message = 'For ' + resource.name + ' ' + method + ' the key ' +
                        key + ' is not allowed. Valid params: ' + JSON.stringify(validParams) +
                        ' request is ' + JSON.stringify(req);
                    return Q.reject(err);
                }
            }
        }

        // no errors, so return resolved promise
        return new Q();
    }
});

// expose the class
module.exports = ServiceFactory;

<commit_msg>Minor changes to ensure search reindex works without error<commit_after>/**
 * Author: Jeff Whelpley
 * Date: 2/20/14
 *
 * This is where services are generated
 */
var Q =             require('q');
var _ =             require('lodash');
var fs =            require('fs');
var p =             require('path');
var utils =         require('../utensils');
var eventBus =      require('../server.event.bus');
var debugHandler =  require('../debug.handler');

/**
 * Simple function to clear the cache
 * @param injector
 * @constructor
 */
function ServiceFactory(injector) {
    this.cache = {};
    this.injector = injector || {};

    // if we are in debug mode, then add the debug handler
    var pattern = this.injector.debugPattern || '*.*.*.*.*';
    var handler = this.injector.debugHandler || debugHandler;
    if (this.injector.debug) {
        eventBus.on(pattern, handler);
    }
}

_.extend(ServiceFactory.prototype, {

    /**
     * Candidate if no slash and the modulePath ends in 'Service'
     * @param modulePath
     * @returns {boolean}
     */
    isCandidate: function isCandidate(modulePath) {
        modulePath = modulePath || '';
        var len = modulePath.length;
        return modulePath.indexOf('/') < 0 && len > 7 &&
            modulePath.substring(modulePath.length - 7) === 'Service';
    },

    /**
     * Simply empty the service cache
     */
    clearCache: function clearCache() {
        this.cache = {};
    },

    /**
     * Create a new service (or pull it from cache if it already exists)
     *
     * @param serviceName
     * @param moduleStack
     * @returns {{}}
     */
    create: function create(serviceName, moduleStack) {

        // if the service already exists in cache, then just return it right away
        if (this.cache[serviceName]) {
            return this.cache[serviceName];
        }

        // get all the parts of the service
        var serviceInfo = this.getServiceInfo(serviceName, this.injector.adapterMap);
        var resource = this.getResource(serviceInfo, moduleStack);
        var adapter = this.getAdapter(serviceInfo, resource, moduleStack);

        // check the cache again because the service name may change if it is a default
        if (this.cache[serviceInfo.serviceName]) {
            return this.cache[serviceInfo.serviceName];
        }

        // construct the service, save it to cache and return it
        var service = this.putItAllTogether(serviceInfo, resource, adapter);
        this.cache[serviceInfo.serviceName] = service;
        return service;
    },

    /**
     * Figure out information about the service based on the module path and the adapter map
     *
     * @param serviceName
     * @param adapterMap
     * @returns {{}}
     */
    getServiceInfo: function getServiceInfo(serviceName, adapterMap) {
        var serviceInfo = { serviceName: serviceName };
        var serviceParts = utils.splitCamelCase(serviceName);  // turn oneTwoThree into ['one', 'two', 'three']
        var nbrParts = serviceParts.length;

        // first check to see if the second to last part is an adapter
        serviceInfo.adapterName = serviceParts[nbrParts - 2];  // NOTE: last item in array is 'Service'
        if (adapterMap[serviceInfo.adapterName]) {
            serviceInfo.resourceName = serviceParts.slice(0, nbrParts - 2).join('.');
        }
        // if not, it means we are dealing with a straight service (ex. postService)
        else {
            serviceInfo.adapterName = 'service';
            serviceInfo.resourceName = serviceParts.slice(0, nbrParts - 1).join('.');
        }

        serviceInfo.adapterImpl = adapterMap[serviceInfo.adapterName];

        return serviceInfo;
    },

    /**
     * Get a resource based on the
     * @param serviceInfo
     * @param moduleStack
     * @returns {{}} A resource object
     */
    getResource: function getResource(serviceInfo, moduleStack) {
        var resourceName = serviceInfo.resourceName;
        var resourcePath = '/resources/' + resourceName + '/' + resourceName + '.resource';
        return this.loadIfExists(resourcePath, moduleStack, 'Could not find resource file');
    },

    /**
     * Get a adapter based on the service info and what exists on the file system
     *
     * @param serviceInfo
     * @param resource
     * @param moduleStack
     */
    getAdapter: function getAdapter(serviceInfo, resource, moduleStack) {
        var adapterName = serviceInfo.adapterName;

        // if adapter name is 'service' and there is a default, switch to the default
        if (adapterName === 'service' && resource.adapters[this.injector.container]) {
            adapterName = serviceInfo.adapterName = resource.adapters[this.injector.container];
            serviceInfo.adapterImpl = this.injector.adapterMap[adapterName];
            serviceInfo.serviceName = utils.getCamelCase(serviceInfo.resourceName + '.' +
                serviceInfo.adapterName + '.service');
        }

        // if that doesn't work, we will assume the adapter is in the current codebase, so go get it
        var overridePath = '/resources/' + serviceInfo.resourceName + '/' + serviceInfo.resourceName + '.' +
            (adapterName === 'service' ? adapterName : adapterName + '.service');
        var adapterPath = '/adapters/' + adapterName + '/' +
            serviceInfo.adapterImpl + '.' + adapterName + '.adapter';

        // if override exists, use that one, else use the lower level adapter
        var Adapter =
            this.loadIfExists(overridePath, moduleStack, null) ||
            this.injector.adapters[serviceInfo.adapterImpl] ||
            this.loadIfExists(adapterPath, moduleStack, null);

        // if still no adapter found, then there is an issue
        if (!Adapter) {
            throw new Error('ServiceFactory could not find adapter ' + adapterName +
            ' paths ' + overridePath + ' and ' + adapterPath);
        }

        return new Adapter(resource);
    },

    /**
     * Load a module if it exists
     * @param path
     * @param moduleStack
     * @param errMsg
     * @returns {*}
     */
    loadIfExists: function loadIfExists(path, moduleStack, errMsg) {
        var servicesDir = this.injector.servicesDir;
        var servicesFullPath = this.injector.rootDir + '/' + servicesDir;

        // if the file doesn't exist, either throw an error (if msg passed in), else just return null
        if (!fs.existsSync(p.join(servicesFullPath, path + '.js'))) {
            if (errMsg) {
                throw new Error(errMsg + ' ' + servicesFullPath + path + '.js');
            }
            else {
                return null;
            }
        }

        // else load the module
        return this.injector.loadModule(servicesDir + path, moduleStack);
    },

    /**
     * Take all the objects involved with a service and put them all together. The final service is really
     * just an instance of an adapter with each method enhanced to have various filters added
     *
     * @param serviceInfo
     * @param resource
     * @param adapter
     * @returns {{}}
     */
    putItAllTogether: function putItAllTogether(serviceInfo, resource, adapter) {
        var me = this;
        var debug = this.injector.debug;

        // loop through the methods
        _.each(resource.methods[serviceInfo.adapterName], function (method) {
            if (!adapter[method]) {
                return;
            }

            // we are going to monkey patch the target method on the adapter, so save the original method
            var origMethod = adapter[method].bind(adapter);
            var eventNameBase = {
                resource: serviceInfo.resourceName,
                adapter: serviceInfo.adapterName,
                method: method
            };

            // create the new service function
            adapter[method] = function (req) {
                req = req || {};

                // clean out request
                _.each(req, function (value, name) {
                    if (value && value === 'undefined') {
                        delete req[name];
                    }
                });

                // add event for data before anything happens (used only for debugging)
                if (debug) { me.emitEvent(req, eventNameBase, { type: 'service', timing: 'before' }); }

                // first validate the request
                return me.validateRequestParams(req, resource, method, serviceInfo.adapterName)
                    .then(function () {

                        // add event before calling the original method (used only for debugging)
                        if (debug) { me.emitEvent(req, eventNameBase, { type: 'service', timing: 'before' }); }

                        // call the original target method on the adapter
                        return origMethod(req);
                    })
                    .then(function (res) {

                        // emit event after origin method called; this is what most
                        // reactors key off of (can be disabled with noemit flag)
                        if (!req.noemit && !req.multi && method !== 'find') {
                            var payload = {
                                caller: req.caller,
                                inputId: req._id,
                                targetId: req.targetId,
                                inputData: req.data,
                                data: res
                            };
                            me.emitEvent(payload, eventNameBase, null);
                        }

                        // return the response that will go back to the calling client
                        return res;
                    });
            };
        });

        // so essentially the service is the adapter with each method bulked up with some extra stuff
        return adapter;
    },

    /**
     * This is used to get an mock filter which will be sending out events
     * @param payload
     * @param eventNameBase
     * @param debugParams
     */
    emitEvent: function emitEvent(payload, eventNameBase, debugParams) {

        // create a copy of the payload so that nothing modifies the original object
        try {
            payload = JSON.parse(JSON.stringify(payload));
        }
        catch (err) {
            console.log('issue parsing during emit ' + JSON.stringify(eventNameBase));
        }

        // we don't want to emit the potentially huge resource file
        if (payload && payload.resource) {
            delete payload.resource;
        }

        // create the event data and emit the event
        var name = _.extend({}, eventNameBase, debugParams);
        var eventData = {
            name: name,
            payload: payload
        };
        var eventName = name.resource + '.' + name.adapter + '.' + name.method;
        eventName += debugParams ? '.' + name.type + '.' + name.timing : '';
        eventBus.emit(eventName, eventData);
    },

    /**
     * Used within a service to validate the input params
     * @param req
     * @param resource
     * @param method
     * @param adapter
     * @returns {*}
     */
    validateRequestParams: function validateRequestParams(req, resource, method, adapter) {
        req = req || {};

        var params = resource.params || {};
        var methodParams = _.extend({}, params[method], params[adapter + '.' + method] );
        var requiredParams = methodParams.required || [];
        var eitherorParams = methodParams.eitheror || [];
        var optional = methodParams.optional || [];
        var eitherorExists, param;
        var err, reqObj;

        // make sure all the required params are there
        for (var i = 0; i < requiredParams.length; i++) {
            param = requiredParams[i];

            if (req[param] === undefined || req[param] === null) {
                reqObj = _.extend({}, req);
                delete reqObj.resource;
                err = new Error('Invalid request');
                err.code = 'invalid_request_error';
                err.message = resource.name + ' ' + method + ' missing ' + param +
                    '. Required params: ' + JSON.stringify(requiredParams) +
                    ' req is: ' + JSON.stringify(reqObj);
                return Q.reject(err);
            }
        }

        // make sure at least one of the eitheror params are there
        if (eitherorParams.length) {
            eitherorExists = false;

            _.each(eitherorParams, function (eitherorParam) {
                if (req[eitherorParam]) { eitherorExists = true; }
            });

            if (!eitherorExists) {
                delete req.caller;
                delete req.resource;
                err = new Error('Invalid request');
                err.code = 'invalid_request_error';
                err.message = resource.name + ' ' + method +
                    ' must have one of the following params: ' + JSON.stringify(eitherorParams) +
                    ' request is ' + JSON.stringify(req);
                return Q.reject(err);
            }
        }

        // now loop through the values and error if invalid param in there; also do JSON parsing if an object
        var validParams = requiredParams.concat(eitherorParams, optional,
            ['lang', 'caller', 'resource', 'method', 'auth', 'noemit']);
        for (var key in req) {
            if (req.hasOwnProperty(key)) {
                if (validParams.indexOf(key) < 0) {
                    delete req.caller;
                    delete req.resource;
                    err = new Error('Invalid request');
                    err.code = 'invalid_request_error';
                    err.message = 'For ' + resource.name + ' ' + method + ' the key ' +
                        key + ' is not allowed. Valid params: ' + JSON.stringify(validParams) +
                        ' request is ' + JSON.stringify(req);
                    return Q.reject(err);
                }
            }
        }

        // no errors, so return resolved promise
        return new Q();
    }
});

// expose the class
module.exports = ServiceFactory;

<|endoftext|>