<commit_before>"use strict";

var _ = require('./lodash');
var Dom = require('./packages/dom');

var TYPE = 'application/vnd.sirtrevor+json'

var SelectionHandler = function(wrapper, mediator, editor) {
  this.wrapper = wrapper;
  this.mediator = mediator;
  this.editor = editor;
  this.options = editor.options;

  this.startIndex = this.endIndex = 0;
  this.selecting = false;

  this._bindFunctions();
  this._bindMediatedEvents();

  this.initialize();
};

Object.assign(SelectionHandler.prototype, require('./function-bind'), require('./mediated-events'), {

  eventNamespace: 'selection',

  bound: ['onCopy', 'onCut', 'onKeyDown', 'onMouseUp', 'onPaste'],

  mediatedEvents: {
    'start': 'start',
    'render': 'render',
    'complete': 'complete',
    'all': 'all',
    'copy': 'copy',
    'update': 'update',
    'delete': 'delete',
    'cancel': 'cancel',
    'block': 'block'
  },

  canSelect: function() {
    // Don't select if within an input field
    var editorEl1 = Dom.getClosest(document.activeElement, 'input');

    if (editorEl1 !== document.body) return false;

    var editorEl2 = Dom.getClosest(document.activeElement, '.st-outer');

    // Don't select all if focused on element outside of the editor.
    if (this.options.selectionLimitToEditor) {
      if (editorEl2 !== this.wrapper) return false;
    }

    return true;
  },

  initialize: function() {
    if (!this.enabled()) return false;

    window.addEventListener("keydown", this.onKeyDown, false);
    window.addEventListener('mouseup', this.onMouseUp, false);
    document.addEventListener('copy', this.onCopy, false);

    if (this.options.selectionCut) {
      document.addEventListener('cut', this.onCut, false);
    }

    if (this.options.selectionPaste) {
      document.addEventListener('paste', this.onPaste, true);
    }
  },

  enabled: function() {
    return !!this.options.selectionCopy;
  },

  start: function(index, options = {}) {
    if (!this.enabled()) return false;

    options = Object.assign({ mouseEnabled: false }, options);

    this.startIndex = this.endIndex = index;
    this.selecting = true;

    if (options.mouseEnabled) {
      window.mouseDown = true;
      this.selecting = false;
      window.addEventListener("mousemove", this.onMouseMove);
    }

    this.mediator.trigger("selection:render");
  },

  startAtEnd: function() {
    this.start(this.editor.getBlocks().length - 1);
  },

  move: function(offset) {
    this.start(this.endIndex + offset);
  },

  onMouseMove: function() {},

  update: function(index) {
    if (index < 0 || index >= this.editor.getBlocks().length) return;
    this.endIndex = index;
    if (index !== this.startIndex) this.selecting = true;
    this.removeNativeSelection();
    this.mediator.trigger("selection:render");
  },

  expand(offset) {
    this.update(this.endIndex + offset);
  },

  expandToStart() {
    this.update(0);
  },

  expandToEnd() {
    this.update(this.editor.getBlocks().length - 1);
  },

  focusAtEnd() {
    const block = this.editor.getBlocks()[this.endIndex];
    block.el.scrollIntoView({ behavior: "smooth" });
  },

  complete: function() {
    window.removeEventListener("mousemove", this.onMouseMove);
  },

  all: function() {
    if (!this.enabled()) return false;

    this.removeNativeSelection();

    var blocks = this.editor.getBlocks();
    this.selecting = true;
    this.startIndex = 0;
    this.endIndex = blocks.length - 1;
    this.mediator.trigger("selection:render");
  },

  cancel: function() {
    window.mouseDown = false;
    this.selecting = false;
    this.render();
  },

  removeNativeSelection: function() {
    var sel = window.getSelection ? window.getSelection() : document.selection;
    if (sel) {
      if (sel.removeAllRanges) {
        sel.removeAllRanges();
      } else if (sel.empty) {
        sel.empty();
      }
    }
    document.activeElement && document.activeElement.blur();
  },

  render: function() {
    var visible = this.selecting;

    this.editor.getBlocks().forEach((block, idx) => {
      block.select(visible && this.indexSelected(idx));
    });
  },

  getClipboardData: function() {
    this.editor.getData();

    var htmlOutput = [];
    var textOutput = [];
    var dataOutput =  [];

    this.editor.getBlocks().forEach((block, idx) => {
      if (this.indexSelected(idx)) {
        var html = block.asClipboardHTML();
        var text = html;
        htmlOutput.push(html);
        textOutput.push(text);
        dataOutput.push(block.getData());
      }
    });

    return {
      html: htmlOutput.join(""),
      text: textOutput.join("\n\n"),
      data: dataOutput
    };
  },

  copy: function() {
    var copyArea = this.createFakeCopyArea();
    copyArea.innerHTML = this.getClipboardData().html;

    var selection = window.getSelection();
    var range = document.createRange();
    range.selectNodeContents(copyArea);
    selection.removeAllRanges();
    selection.addRange(range);

    try {
      document.execCommand('copy');
      copyArea.blur();
    }
    catch (err) {
      console.log("Copy could not be performed");
    }
  },

  createFakeCopyArea: function() {
    var copyArea = document.body.querySelector(".st-copy-area");
    if (!copyArea) {
      copyArea = Dom.createElement("div", {
        contenteditable: true,
        class: 'st-copy-area st-utils__hidden',
      });
      document.body.appendChild(copyArea);
    }
    return copyArea;
  },

  delete: function(options = {}) {
    options = Object.assign({ createNextBlock: true }, options);

    this.editor.getBlocks().forEach((block, idx) => {
      if (!this.indexSelected(idx)) return;
      this.mediator.trigger(
        "block:remove",
        block.blockID, {
          focusOnNext: true,
          createNextBlock: options.createNextBlock
        }
      );
    });
    this.cancel();
  },

  indexSelected: function(index) {
    return index >= this.getStartIndex() && index <= this.getEndIndex();
  },

  block: function(block) {
    var blockPosition = this.editor.blockManager.getBlockPosition(block.el);

    this.mediator.trigger("formatter:hide");
    this.removeNativeSelection();
    this.start(blockPosition);
  },

  getStartIndex: function() {
    return Math.min(this.startIndex, this.endIndex);
  },

  getEndIndex: function() {
    return Math.max(this.startIndex, this.endIndex);
  },

  getStartBlock: function() {
    return this.editor.getBlocks()[this.getStartIndex()];
  },

  getEndBlock: function() {
    return this.editor.getBlocks()[this.getEndIndex()];
  },

  onKeyDown: function(ev) {
    ev = ev || window.event;
    var ctrlKey = ev.ctrlKey || ev.metaKey;
    var key = ev.key;

    if (this.selecting && key === "Backspace") {
      ev.preventDefault();
      this.delete();
    } else if (ctrlKey && key === "a") {
      if (!this.selecting && !this.canSelect()) return;
      ev.preventDefault();
      this.mediator.trigger("selection:all");
    } else if (this.selecting) {
      if (["Down", "ArrowDown"].indexOf(key) > -1) {
        ev.preventDefault();
        if (ev.shiftKey && ev.altKey) this.expandToEnd();
        else if (ev.shiftKey) this.expand(1);
        else if (ev.altKey) this.startAtEnd();
        else {
          this.cancel();
          this.mediator.trigger("block:focusNext", this.getEndBlock().blockID, { force: true });
          return;
        }
        this.focusAtEnd();
      } else if (["Up", "ArrowUp"].indexOf(key) > -1) {
        ev.preventDefault();
        if (ev.shiftKey && ev.altKey) this.expandToStart();
        else if (ev.shiftKey) this.expand(-1);
        else if (ev.altKey) this.start(0);
        else {
          this.cancel();
          this.mediator.trigger("block:focusPrevious", this.getStartBlock().blockID, { force: true });
          return;
        }
        this.focusAtEnd();
      }
    }
  },

  onMouseUp: function() {
    if (!window.mouseDown) {
      this.mediator.trigger("selection:complete");
      this.mediator.trigger("selection:cancel");
      return;
    }

    window.mouseDown = false;
    this.mediator.trigger("selection:complete");
    this.mediator.trigger("selection:render");
  },

  copySelection: function(ev) {
    var content = this.getClipboardData();

    ev.clipboardData.setData(TYPE, JSON.stringify(content.data));
    ev.clipboardData.setData('text/html', content.html);
    ev.clipboardData.setData('text/plain', content.text);
    ev.preventDefault();
  },

  onCopy: function(ev) {
    if (!this.selecting) return;

    this.copySelection(ev);
  },

  onCut: function(ev) {
    if (!this.selecting) return;

    this.copySelection(ev);
    this.delete();
  },

  onPaste: function(ev) {
    if (ev.clipboardData.types.includes(TYPE)) {
      if (!this.selecting && !this.canSelect()) return;

      ev.preventDefault();
      ev.stopPropagation();
      let data = JSON.parse(ev.clipboardData.getData(TYPE));
      if (this.selecting) {
        const nextBlock = this.editor.getBlocks()[this.getEndIndex() + 1];
        this.delete({ createNextBlock: false });
        if (nextBlock && !nextBlock.isEmpty()) {
          this.mediator.trigger("block:createBefore", "text", "", nextBlock, { autoFocus: true });
        } else {
          this.mediator.trigger("block:create", "text", "", null, { autoFocus: true });
        }
      }
      this.mediator.trigger("block:paste", data);
    }
  }
});

module.exports = SelectionHandler;
<commit_msg>Fix Edge clipboardTypes<commit_after>"use strict";

var _ = require('./lodash');
var Dom = require('./packages/dom');

var TYPE = 'application/vnd.sirtrevor+json'

var SelectionHandler = function(wrapper, mediator, editor) {
  this.wrapper = wrapper;
  this.mediator = mediator;
  this.editor = editor;
  this.options = editor.options;

  this.startIndex = this.endIndex = 0;
  this.selecting = false;

  this._bindFunctions();
  this._bindMediatedEvents();

  this.initialize();
};

Object.assign(SelectionHandler.prototype, require('./function-bind'), require('./mediated-events'), {

  eventNamespace: 'selection',

  bound: ['onCopy', 'onCut', 'onKeyDown', 'onMouseUp', 'onPaste'],

  mediatedEvents: {
    'start': 'start',
    'render': 'render',
    'complete': 'complete',
    'all': 'all',
    'copy': 'copy',
    'update': 'update',
    'delete': 'delete',
    'cancel': 'cancel',
    'block': 'block'
  },

  canSelect: function() {
    // Don't select if within an input field
    var editorEl1 = Dom.getClosest(document.activeElement, 'input');

    if (editorEl1 !== document.body) return false;

    var editorEl2 = Dom.getClosest(document.activeElement, '.st-outer');

    // Don't select all if focused on element outside of the editor.
    if (this.options.selectionLimitToEditor) {
      if (editorEl2 !== this.wrapper) return false;
    }

    return true;
  },

  initialize: function() {
    if (!this.enabled()) return false;

    window.addEventListener("keydown", this.onKeyDown, false);
    window.addEventListener('mouseup', this.onMouseUp, false);
    document.addEventListener('copy', this.onCopy, false);

    if (this.options.selectionCut) {
      document.addEventListener('cut', this.onCut, false);
    }

    if (this.options.selectionPaste) {
      document.addEventListener('paste', this.onPaste, true);
    }
  },

  enabled: function() {
    return !!this.options.selectionCopy;
  },

  start: function(index, options = {}) {
    if (!this.enabled()) return false;

    options = Object.assign({ mouseEnabled: false }, options);

    this.startIndex = this.endIndex = index;
    this.selecting = true;

    if (options.mouseEnabled) {
      window.mouseDown = true;
      this.selecting = false;
      window.addEventListener("mousemove", this.onMouseMove);
    }

    this.mediator.trigger("selection:render");
  },

  startAtEnd: function() {
    this.start(this.editor.getBlocks().length - 1);
  },

  move: function(offset) {
    this.start(this.endIndex + offset);
  },

  onMouseMove: function() {},

  update: function(index) {
    if (index < 0 || index >= this.editor.getBlocks().length) return;
    this.endIndex = index;
    if (index !== this.startIndex) this.selecting = true;
    this.removeNativeSelection();
    this.mediator.trigger("selection:render");
  },

  expand(offset) {
    this.update(this.endIndex + offset);
  },

  expandToStart() {
    this.update(0);
  },

  expandToEnd() {
    this.update(this.editor.getBlocks().length - 1);
  },

  focusAtEnd() {
    const block = this.editor.getBlocks()[this.endIndex];
    block.el.scrollIntoView({ behavior: "smooth" });
  },

  complete: function() {
    window.removeEventListener("mousemove", this.onMouseMove);
  },

  all: function() {
    if (!this.enabled()) return false;

    this.removeNativeSelection();

    var blocks = this.editor.getBlocks();
    this.selecting = true;
    this.startIndex = 0;
    this.endIndex = blocks.length - 1;
    this.mediator.trigger("selection:render");
  },

  cancel: function() {
    window.mouseDown = false;
    this.selecting = false;
    this.render();
  },

  removeNativeSelection: function() {
    var sel = window.getSelection ? window.getSelection() : document.selection;
    if (sel) {
      if (sel.removeAllRanges) {
        sel.removeAllRanges();
      } else if (sel.empty) {
        sel.empty();
      }
    }
    document.activeElement && document.activeElement.blur();
  },

  render: function() {
    var visible = this.selecting;

    this.editor.getBlocks().forEach((block, idx) => {
      block.select(visible && this.indexSelected(idx));
    });
  },

  getClipboardData: function() {
    this.editor.getData();

    var htmlOutput = [];
    var textOutput = [];
    var dataOutput =  [];

    this.editor.getBlocks().forEach((block, idx) => {
      if (this.indexSelected(idx)) {
        var html = block.asClipboardHTML();
        var text = html;
        htmlOutput.push(html);
        textOutput.push(text);
        dataOutput.push(block.getData());
      }
    });

    return {
      html: htmlOutput.join(""),
      text: textOutput.join("\n\n"),
      data: dataOutput
    };
  },

  copy: function() {
    var copyArea = this.createFakeCopyArea();
    copyArea.innerHTML = this.getClipboardData().html;

    var selection = window.getSelection();
    var range = document.createRange();
    range.selectNodeContents(copyArea);
    selection.removeAllRanges();
    selection.addRange(range);

    try {
      document.execCommand('copy');
      copyArea.blur();
    }
    catch (err) {
      console.log("Copy could not be performed");
    }
  },

  createFakeCopyArea: function() {
    var copyArea = document.body.querySelector(".st-copy-area");
    if (!copyArea) {
      copyArea = Dom.createElement("div", {
        contenteditable: true,
        class: 'st-copy-area st-utils__hidden',
      });
      document.body.appendChild(copyArea);
    }
    return copyArea;
  },

  delete: function(options = {}) {
    options = Object.assign({ createNextBlock: true }, options);

    this.editor.getBlocks().forEach((block, idx) => {
      if (!this.indexSelected(idx)) return;
      this.mediator.trigger(
        "block:remove",
        block.blockID, {
          focusOnNext: true,
          createNextBlock: options.createNextBlock
        }
      );
    });
    this.cancel();
  },

  indexSelected: function(index) {
    return index >= this.getStartIndex() && index <= this.getEndIndex();
  },

  block: function(block) {
    var blockPosition = this.editor.blockManager.getBlockPosition(block.el);

    this.mediator.trigger("formatter:hide");
    this.removeNativeSelection();
    this.start(blockPosition);
  },

  getStartIndex: function() {
    return Math.min(this.startIndex, this.endIndex);
  },

  getEndIndex: function() {
    return Math.max(this.startIndex, this.endIndex);
  },

  getStartBlock: function() {
    return this.editor.getBlocks()[this.getStartIndex()];
  },

  getEndBlock: function() {
    return this.editor.getBlocks()[this.getEndIndex()];
  },

  onKeyDown: function(ev) {
    ev = ev || window.event;
    var ctrlKey = ev.ctrlKey || ev.metaKey;
    var key = ev.key;

    if (this.selecting && key === "Backspace") {
      ev.preventDefault();
      this.delete();
    } else if (ctrlKey && key === "a") {
      if (!this.selecting && !this.canSelect()) return;
      ev.preventDefault();
      this.mediator.trigger("selection:all");
    } else if (this.selecting) {
      if (["Down", "ArrowDown"].indexOf(key) > -1) {
        ev.preventDefault();
        if (ev.shiftKey && ev.altKey) this.expandToEnd();
        else if (ev.shiftKey) this.expand(1);
        else if (ev.altKey) this.startAtEnd();
        else {
          this.cancel();
          this.mediator.trigger("block:focusNext", this.getEndBlock().blockID, { force: true });
          return;
        }
        this.focusAtEnd();
      } else if (["Up", "ArrowUp"].indexOf(key) > -1) {
        ev.preventDefault();
        if (ev.shiftKey && ev.altKey) this.expandToStart();
        else if (ev.shiftKey) this.expand(-1);
        else if (ev.altKey) this.start(0);
        else {
          this.cancel();
          this.mediator.trigger("block:focusPrevious", this.getStartBlock().blockID, { force: true });
          return;
        }
        this.focusAtEnd();
      }
    }
  },

  onMouseUp: function() {
    if (!window.mouseDown) {
      this.mediator.trigger("selection:complete");
      this.mediator.trigger("selection:cancel");
      return;
    }

    window.mouseDown = false;
    this.mediator.trigger("selection:complete");
    this.mediator.trigger("selection:render");
  },

  copySelection: function(ev) {
    var content = this.getClipboardData();

    ev.clipboardData.setData(TYPE, JSON.stringify(content.data));
    ev.clipboardData.setData('text/html', content.html);
    ev.clipboardData.setData('text/plain', content.text);
    ev.preventDefault();
  },

  onCopy: function(ev) {
    if (!this.selecting) return;

    this.copySelection(ev);
  },

  onCut: function(ev) {
    if (!this.selecting) return;

    this.copySelection(ev);
    this.delete();
  },

  onPaste: function(ev) {
    // Fix Edge types DomStringList.
    var types = [].slice.call(ev.clipboardData.types);
    if (types.includes(TYPE)) {
      if (!this.selecting && !this.canSelect()) return;

      ev.preventDefault();
      ev.stopPropagation();
      let data = JSON.parse(ev.clipboardData.getData(TYPE));
      if (this.selecting) {
        const nextBlock = this.editor.getBlocks()[this.getEndIndex() + 1];
        this.delete({ createNextBlock: false });
        if (nextBlock && !nextBlock.isEmpty()) {
          this.mediator.trigger("block:createBefore", "text", "", nextBlock, { autoFocus: true });
        } else {
          this.mediator.trigger("block:create", "text", "", null, { autoFocus: true });
        }
      }
      this.mediator.trigger("block:paste", data);
    }
  }
});

module.exports = SelectionHandler;
<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2020
 */

export const selectUsingSupplierCredits = ({ modules }) => {
  const { usingSupplierCredits } = modules;
  return usingSupplierCredits;
};
<commit_msg>Add modules selector<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2020
 */

export const selectUsingSupplierCredits = ({ modules }) => {
  const { usingSupplierCredits } = modules;
  return usingSupplierCredits;
};

export const selectUsingPayments = ({ modules }) => {
  const { usingPayments } = modules;
  return usingPayments;
};
<|endoftext|>


<commit_before>/**
 * @fileOverview A wrapper for the Jetty HTTP server.
 */

var log = require('ringo/logging').getLogger(module.id);
var Parser = require('ringo/args').Parser;
var system = require('system');
var {WebSocket, WebSocketServlet} = org.eclipse.jetty.websocket;

export('Server', 'main', 'init', 'start', 'stop', 'destroy');

var options,
    server,
    parser,
    started = false;

/**
 * Create a Jetty HTTP server with the given options. The options may
 * either define properties to be used with the default jetty.xml, or define
 * a custom configuration file.
 *
 * @param {Object} options A javascript object with any of the following properties,
 * with the default value in parentheses:
 *

 *
jettyConfig ('config/jetty.xml')

 *
port (8080)

 *
host (undefined)

 *

 *
 * For convenience, the constructor supports the definition of a JSGI application
 * and static resource mapping in the config object using the following properties:
 *

 *
virtualHost (undefined)

 *
mountpoint ('/')

 *
staticDir ('static')

 *
staticMountpoint ('/static')

 *
config ('config')

 *
app ('app')

 *

 */
function Server(options) {

    if (!(this instanceof Server)) {
        return new Server(options);
    }

    // the jetty server instance
    var jetty;
    var defaultContext;
    var contextMap = {};
    var xmlconfig;

    /**
     * Get the server's default context. The default context is the
     * context that is created when the server is created.
     * @since: 0.6
     * @returns the default context
     */
    this.getDefaultContext = function() {
        return defaultContext;
    };

    /**
     * Get a servlet application context for the given path and virtual hosts, creating
     * it if it doesn't exist.
     * @param {string} path the context root path such as "/" or "/app"
     * @param {string|array} virtualHosts optional single or multiple virtual host names.
     *   A virtual host may start with a "*." wildcard.
     * @param {Object} options may have the following properties:
     *   sessions: true to enable sessions for this context, false otherwise
     *   security: true to enable security for this context, false otherwise
     * @since: 0.6
     * @returns a Context object
     */
    this.getContext = function(path, virtualHosts, options) {
        var idMap = xmlconfig.getIdMap();
        options = options || {};
        var contextKey = virtualHosts ? String(virtualHosts) + path : path;
        var cx = contextMap[contextKey];
        if (!cx) {
            var contexts = idMap.get("Contexts");
            var sessions = Boolean(options.sessions);
            var security = Boolean(options.security);
            cx = new org.eclipse.jetty.servlet.ServletContextHandler(contexts, path, sessions, security);
            if (virtualHosts) {
                cx.setVirtualHosts(Array.isArray(virtualHosts) ? virtualHosts : [String(virtualHosts)]);
            }
            contextMap[contextKey] = cx;
            if (jetty.isRunning()) {
                cx.start();
            }
        }

        return {
            /**
             * Map this context to a JSGI application.
             * @param {function|object} app a JSGI application, either as a function or an object
             *   with properties config and app defining
             *   the application.
             *
{ config: 'config', app: 'app' }

             * @param {RhinoEngine} engine optional RhinoEngine instance for multi-engine setups
             * @since: 0.6
             * @name Context.instance.serveApplication
             */
            serveApplication: function(app, engine) {
                log.debug("Adding JSGI application:", cx, "->", app);
                engine = engine || require('ringo/engine').getRhinoEngine();
                var isFunction = typeof app === "function";
                var servlet = isFunction ?
                              new JsgiServlet(engine, app) :
                              new JsgiServlet(engine);
                var jpkg = org.eclipse.jetty.servlet;
                var servletHolder = new jpkg.ServletHolder(servlet);
                if (!isFunction) {
                    servletHolder.setInitParameter('config', app.config || 'config');
                    servletHolder.setInitParameter('app', app.app || 'app');
                }
                cx.addServlet(servletHolder, "/*");
            },
            /**
             * Map this context to a directory containing static resources.
             * @param {string} dir the directory from which to serve static resources
             * @since: 0.6
             * @name Context.instance.serveStatic
             */
            serveStatic: function(dir) {
                log.debug("Adding static handler:", cx, "->", dir);
                var repo = getRepository(dir);
                cx.setResourceBase(repo.exists() ? repo.getPath() : dir);
                var jpkg = org.eclipse.jetty.servlet;
                var servletHolder = new jpkg.ServletHolder(jpkg.DefaultServlet);
                cx.addServlet(servletHolder, "/*");
            },
            /**
             * Map a request path within this context to the given servlet.
             * @param {string} servletPath the servlet path
             * @param {Servlet} servlet a java object implementing the javax.servlet.Servlet interface.
             * @param {Object} initParams optional object containing servlet init parameters
             * @since: 0.6
             * @name Context.instance.addServlet
             */
            addServlet: function(servletPath, servlet, initParams) {
                log.debug("Adding Servlet:", servletPath, "->", servlet);
                var jpkg = org.eclipse.jetty.servlet;
                var servletHolder = new jpkg.ServletHolder(servlet);
                for (var p in initParams) {
                    servletHolder.setInitParameter(p, initParams[p])
                }
                cx.addServlet(servletHolder, servletPath);
            },
            /**
             * Start accepting WebSocket connections in this context context.
             *
             * @param path The URL path on which to accept WebSocket connections
             * @param onconnect a function called for each new WebSocket connection
             *        with the WebSocket object as argument.
             * @since 0.8
             * @see WebSocket
             * @name Context.instance.addWebSocket
             */
            addWebSocket: function(path, onconnect) {
                log.info("Starting websocket support");
                this.addServlet(path, new WebSocketServlet({
                    doWebSocketConnect : function(request, protocol) {
                        log.debug("new websocket");
                        var socket;

                        return new WebSocket({
                            onConnect: function(outbound) {
                                log.debug("onconnect");

                                /**
                                 * The WebSocket object passed as argument to the `connect` callback.
                                 * Assign callbacks to its [onmessage](#WebSocket.prototype.onmessage)
                                 * and [onclose](#WebSocket.prototype.onclose) properties.
                                 * @name WebSocket
                                 * @class
                                 */
                                socket = {
                                    /**
                                     * Closes the WebSocket connection.
                                     * @name WebSocket.instance.close
                                     * @function
                                     */
                                    close: function() {
                                        outbound.disconnect();
                                    },
                                    /**
                                     * Send a string over the WebSocket.
                                     * @param msg a string
                                     * @name WebSocket.instance.send
                                     * @function
                                     */
                                    send: function(msg) {
                                        outbound.sendMessage(msg);
                                    },
                                    /**
                                     * Check whether the WebSocket is open.
                                     * @name WebSocket.instance.isOpen
                                     * @function
                                     */
                                    isOpen: function() {
                                        return outbound.isOpen();
                                    },
                                    /**
                                     * Callback slot for receiving messages on this WebSocket. To receive
                                     * messages on this WebSocket, assign a function to this property.
                                     * The function is called with a single argument containing the message string.
                                     * @name WebSocket.instance.onmessage
                                     */
                                    onmessage: null,
                                    /**
                                     * Callback slot for getting notified when the WebSocket is closed.
                                     * To get called when the WebSocket is closed assign a function to this
                                     * property. The function is called without arguments.
                                     * @name WebSocket.instance.onclose
                                     */
                                    onclose: null
                                };
                                if (typeof onconnect === "function") {
                                    onconnect(socket)
                                }
                            },

                            onMessage: function(frame, data) {
                                log.debug("onmessage");
                                if (typeof socket.onmessage === "function") {
                                    socket.onmessage(data);
                                }
                            },

                            onDisconnect: function() {
                                log.debug("ondisconnect");
                                if (typeof socket.onclose === "function") {
                                    socket.onclose();
                                }
                            }
                        });
                    }
                }));
            }
        };
    };

    /**
     * Start the HTTP server.
     */
    this.start = function() {
        jetty.start();
        log.info('Server on http://' + (props.get('host') || 'localhost') +
                ':' + props.get('port') + ' started.');
    };

    /**
     * Stop the HTTP server.
     */
    this.stop = function() {
        jetty.stop();
        contextMap = {};
    };

    /**
     * Destroy the HTTP server, freeing its resources.
     */
    this.destroy = function() {
        jetty.destroy();
    };

    /**
     * Checks whether this server is currently running.
     * @returns true if the server is running, false otherwise.
     */
    this.isRunning = function() {
        return jetty != null && jetty.isRunning();
    };

    /**
     * Get the Jetty server instance
     * @returns the Jetty Server instance
     */
    this.getJetty = function() {
        return jetty;
    };

    options = options || {};

    var jettyFile = options.jettyConfig || 'config/jetty.xml';
    var jettyConfig = getResource(jettyFile);
    if (!jettyConfig.exists()) {
        throw Error('Resource "' + jettyFile + '" not found');
    }
    var XmlConfiguration = org.eclipse.jetty.xml.XmlConfiguration;
    var JsgiServlet = org.ringojs.jsgi.JsgiServlet;
    jetty = new org.eclipse.jetty.server.Server();
    xmlconfig = new XmlConfiguration(jettyConfig.inputStream);

    // port config is done via properties
    var props = xmlconfig.getProperties();
    props.put('port', (options.port || 8080).toString());
    if (options.host) props.put('host', options.host);
    xmlconfig.configure(jetty);

    // create default context
    defaultContext = this.getContext(options.mountpoint || "/", options.virtualHost, {
        security: true,
        sessions: true
    });

    // If options defines an application mount it
    if (typeof options.app === "function") {
        defaultContext.serveApplication(options.app);
    } else if (options.app && options.config) {
        defaultContext.serveApplication(options);
    }

    // Allow definition of app/static mappings in server config for convenience
    if (options.staticDir) {
        var files = require('ringo/utils/files');
        var staticContext = this.getContext(options.staticMountpoint || '/static', options.virtualHost);
        staticContext.serveStatic(files.resolveId(options.config, options.staticDir));
    }

    // Start listeners. This allows us to run on privileged port 80 under jsvc
    // even as non-root user if the constructor is called with root privileges
    // while start() is called with the user we will actually run as
    var connectors = jetty.getConnectors();
    for each (var connector in connectors) {
        connector.open();
    }

}

function parseOptions(arguments, defaults) {
    // parse command line options
    parser = new Parser();
    parser.addOption("a", "app", "APP", "The exported property name of the JSGI app (default: 'app')");
    parser.addOption("c", "config", "MODULE", "The module containing the JSGI app (default: 'config')");
    parser.addOption("j", "jetty-config", "PATH", "The jetty xml configuration file (default. 'config/jetty.xml')");
    parser.addOption("H", "host", "ADDRESS", "The IP address to bind to (default: 0.0.0.0)");
    parser.addOption("m", "mountpoint", "PATH", "The URI path where to mount the application (default: /)");
    parser.addOption("p", "port", "PORT", "The TCP port to listen on (default: 80)");
    parser.addOption("s", "static-dir", "DIR", "A directory with static resources to serve");
    parser.addOption("S", "static-mountpoint", "PATH", "The URI path where ot mount the static resources");
    parser.addOption("v", "virtual-host", "VHOST", "The virtual host name (default: undefined)");
    parser.addOption("h", "help", null, "Print help message to stdout");
    options = parser.parse(arguments, defaults);
    if (options.port && !isFinite(options.port)) {
        var port = parseInt(options.port, 10);
        if (isNaN(port) || port < 1) {
            throw "Invalid value for port: " + options.port;
        }
        options.port = port;
    }
    return options;
}

/**
 * Function invoked by `ringo/daemon`. Creates a new Server with the application
 * at `path`. If the application exports a function called `init`, it will be
 * invoked with the new server as argument.
 *
 * @param path {string} optional path to the application. If undefined,
 *     the path will be taken from `system.args`.
 * @returns {Server} the Server instance.
 */
function init(path) {
    // protect against module reloading
    if (started) {
        return server;
    }
    // parse command line options
    var cmd = system.args.shift();
    try {
        options = parseOptions(system.args, {
            app: "app",
            config: "config"
        });
    } catch (error) {
        print(error);
        system.exit(1);
    }

    if (options.help) {
        print("Usage:");
        print("", cmd, "[OPTIONS]", "[PATH]");
        print("Options:");
        print(parser.help());
        system.exit(0);
    }

    var appDir = "";
    // if no explicit path is given use first command line argument
    path = path || system.args[0];
    var fs = require("fs");
    if (path) {
        try {
            // check if argument can be resolved as module id
            require(path);
            options.config = path;
        } catch (error) {
            path = fs.absolute(path);
            if (fs.isDirectory(path)) {
                // if argument is a directory assume app in config.js
                options.config = fs.join(path, "config");
                appDir = path;
            } else {
                // if argument is a file use it as config module
                options.config = path;
                appDir = fs.directory(path);
            }
        }
    } else {
        appDir = fs.workingDirectory();
        options.config = fs.join(appDir, "config");
    }

    // logging module is already loaded and configured, check if webapp provides
    // its own log4j configuration file and apply it if so.
    var logConfig = getResource(fs.join(appDir, "config/log4j.properties"));
    if (logConfig.exists()) {
        require("./logging").setConfig(logConfig);
    }

    server = new Server(options);
    var app = require(options.config);
    if (typeof app.init === "function") {
        app.init(server);
    }
    return server;
}

/**
 * Function invoked by `ringo/daemon`. Starts the Server created by `init()`.
 * If the application exports a function called `start`, it will be
 * invoked with the server as argument immediately after it has started.
 *
 * @returns {Server} the Server instance.
 */
function start() {
    server.start();
    started = true;
    var app = require(options.config);
    if (typeof app.start === "function") {
        app.start(server);
    }
    return server;
}

/**
 * Function invoked by `ringo/daemon`. Stops the Server started by `start()`.
 * @returns {Server} the Server instance. If the application exports a function
 * called `stop`, it will be invoked with the server as argument immediately
 * before it is stopped.
 *
 * @returns {Server} the Server instance.
 */
function stop() {
    var app = require(options.config);
    if (typeof app.stop === "function") {
        app.stop(server);
    }
    server.stop();
    started = false;
    return server;
}

/**
 * Function invoked by `ringo/daemon`. Frees any resources occupied by the
 * Server instance.  If the application exports a function called `destroy`,
 * it will be invoked with the server as argument.
 *
 * @returns {Server} the Server instance.
 */
function destroy() {
    var app = require(options.config);
    if (typeof app.destroy === "function") {
        app.destroy(server);
    }
    server.destroy();
    try {
        return server;
    } finally {
        server = null;
    }
}

/**
 * Main webapp startup function.
 * @param {String} path optional path to the web application directory or config module.
 * @returns {Server} the Server instance.
 */
function main(path) {
    init(path);
    start();
    // return the server instance
    return server;
}

if (require.main == module) {
    main();
}

<commit_msg>Fix httpserver life cycle documentation.<commit_after>/**
 * @fileOverview A wrapper for the Jetty HTTP server.
 */

var log = require('ringo/logging').getLogger(module.id);
var Parser = require('ringo/args').Parser;
var system = require('system');
var {WebSocket, WebSocketServlet} = org.eclipse.jetty.websocket;

export('Server', 'main', 'init', 'start', 'stop', 'destroy');

var options,
    server,
    parser,
    started = false;

/**
 * Create a Jetty HTTP server with the given options. The options may
 * either define properties to be used with the default jetty.xml, or define
 * a custom configuration file.
 *
 * @param {Object} options A javascript object with any of the following properties,
 * with the default value in parentheses:
 *

 *
jettyConfig ('config/jetty.xml')

 *
port (8080)

 *
host (undefined)

 *

 *
 * For convenience, the constructor supports the definition of a JSGI application
 * and static resource mapping in the config object using the following properties:
 *

 *
virtualHost (undefined)

 *
mountpoint ('/')

 *
staticDir ('static')

 *
staticMountpoint ('/static')

 *
config ('config')

 *
app ('app')

 *

 */
function Server(options) {

    if (!(this instanceof Server)) {
        return new Server(options);
    }

    // the jetty server instance
    var jetty;
    var defaultContext;
    var contextMap = {};
    var xmlconfig;

    /**
     * Get the server's default context. The default context is the
     * context that is created when the server is created.
     * @since: 0.6
     * @returns the default context
     */
    this.getDefaultContext = function() {
        return defaultContext;
    };

    /**
     * Get a servlet application context for the given path and virtual hosts, creating
     * it if it doesn't exist.
     * @param {string} path the context root path such as "/" or "/app"
     * @param {string|array} virtualHosts optional single or multiple virtual host names.
     *   A virtual host may start with a "*." wildcard.
     * @param {Object} options may have the following properties:
     *   sessions: true to enable sessions for this context, false otherwise
     *   security: true to enable security for this context, false otherwise
     * @since: 0.6
     * @returns a Context object
     */
    this.getContext = function(path, virtualHosts, options) {
        var idMap = xmlconfig.getIdMap();
        options = options || {};
        var contextKey = virtualHosts ? String(virtualHosts) + path : path;
        var cx = contextMap[contextKey];
        if (!cx) {
            var contexts = idMap.get("Contexts");
            var sessions = Boolean(options.sessions);
            var security = Boolean(options.security);
            cx = new org.eclipse.jetty.servlet.ServletContextHandler(contexts, path, sessions, security);
            if (virtualHosts) {
                cx.setVirtualHosts(Array.isArray(virtualHosts) ? virtualHosts : [String(virtualHosts)]);
            }
            contextMap[contextKey] = cx;
            if (jetty.isRunning()) {
                cx.start();
            }
        }

        return {
            /**
             * Map this context to a JSGI application.
             * @param {function|object} app a JSGI application, either as a function or an object
             *   with properties config and app defining
             *   the application.
             *
{ config: 'config', app: 'app' }

             * @param {RhinoEngine} engine optional RhinoEngine instance for multi-engine setups
             * @since: 0.6
             * @name Context.instance.serveApplication
             */
            serveApplication: function(app, engine) {
                log.debug("Adding JSGI application:", cx, "->", app);
                engine = engine || require('ringo/engine').getRhinoEngine();
                var isFunction = typeof app === "function";
                var servlet = isFunction ?
                              new JsgiServlet(engine, app) :
                              new JsgiServlet(engine);
                var jpkg = org.eclipse.jetty.servlet;
                var servletHolder = new jpkg.ServletHolder(servlet);
                if (!isFunction) {
                    servletHolder.setInitParameter('config', app.config || 'config');
                    servletHolder.setInitParameter('app', app.app || 'app');
                }
                cx.addServlet(servletHolder, "/*");
            },
            /**
             * Map this context to a directory containing static resources.
             * @param {string} dir the directory from which to serve static resources
             * @since: 0.6
             * @name Context.instance.serveStatic
             */
            serveStatic: function(dir) {
                log.debug("Adding static handler:", cx, "->", dir);
                var repo = getRepository(dir);
                cx.setResourceBase(repo.exists() ? repo.getPath() : dir);
                var jpkg = org.eclipse.jetty.servlet;
                var servletHolder = new jpkg.ServletHolder(jpkg.DefaultServlet);
                cx.addServlet(servletHolder, "/*");
            },
            /**
             * Map a request path within this context to the given servlet.
             * @param {string} servletPath the servlet path
             * @param {Servlet} servlet a java object implementing the javax.servlet.Servlet interface.
             * @param {Object} initParams optional object containing servlet init parameters
             * @since: 0.6
             * @name Context.instance.addServlet
             */
            addServlet: function(servletPath, servlet, initParams) {
                log.debug("Adding Servlet:", servletPath, "->", servlet);
                var jpkg = org.eclipse.jetty.servlet;
                var servletHolder = new jpkg.ServletHolder(servlet);
                for (var p in initParams) {
                    servletHolder.setInitParameter(p, initParams[p])
                }
                cx.addServlet(servletHolder, servletPath);
            },
            /**
             * Start accepting WebSocket connections in this context context.
             *
             * @param path The URL path on which to accept WebSocket connections
             * @param onconnect a function called for each new WebSocket connection
             *        with the WebSocket object as argument.
             * @since 0.8
             * @see WebSocket
             * @name Context.instance.addWebSocket
             */
            addWebSocket: function(path, onconnect) {
                log.info("Starting websocket support");
                this.addServlet(path, new WebSocketServlet({
                    doWebSocketConnect : function(request, protocol) {
                        log.debug("new websocket");
                        var socket;

                        return new WebSocket({
                            onConnect: function(outbound) {
                                log.debug("onconnect");

                                /**
                                 * The WebSocket object passed as argument to the `connect` callback.
                                 * Assign callbacks to its [onmessage](#WebSocket.prototype.onmessage)
                                 * and [onclose](#WebSocket.prototype.onclose) properties.
                                 * @name WebSocket
                                 * @class
                                 */
                                socket = {
                                    /**
                                     * Closes the WebSocket connection.
                                     * @name WebSocket.instance.close
                                     * @function
                                     */
                                    close: function() {
                                        outbound.disconnect();
                                    },
                                    /**
                                     * Send a string over the WebSocket.
                                     * @param msg a string
                                     * @name WebSocket.instance.send
                                     * @function
                                     */
                                    send: function(msg) {
                                        outbound.sendMessage(msg);
                                    },
                                    /**
                                     * Check whether the WebSocket is open.
                                     * @name WebSocket.instance.isOpen
                                     * @function
                                     */
                                    isOpen: function() {
                                        return outbound.isOpen();
                                    },
                                    /**
                                     * Callback slot for receiving messages on this WebSocket. To receive
                                     * messages on this WebSocket, assign a function to this property.
                                     * The function is called with a single argument containing the message string.
                                     * @name WebSocket.instance.onmessage
                                     */
                                    onmessage: null,
                                    /**
                                     * Callback slot for getting notified when the WebSocket is closed.
                                     * To get called when the WebSocket is closed assign a function to this
                                     * property. The function is called without arguments.
                                     * @name WebSocket.instance.onclose
                                     */
                                    onclose: null
                                };
                                if (typeof onconnect === "function") {
                                    onconnect(socket)
                                }
                            },

                            onMessage: function(frame, data) {
                                log.debug("onmessage");
                                if (typeof socket.onmessage === "function") {
                                    socket.onmessage(data);
                                }
                            },

                            onDisconnect: function() {
                                log.debug("ondisconnect");
                                if (typeof socket.onclose === "function") {
                                    socket.onclose();
                                }
                            }
                        });
                    }
                }));
            }
        };
    };

    /**
     * Start the HTTP server.
     */
    this.start = function() {
        jetty.start();
        log.info('Server on http://' + (props.get('host') || 'localhost') +
                ':' + props.get('port') + ' started.');
    };

    /**
     * Stop the HTTP server.
     */
    this.stop = function() {
        jetty.stop();
        contextMap = {};
    };

    /**
     * Destroy the HTTP server, freeing its resources.
     */
    this.destroy = function() {
        jetty.destroy();
    };

    /**
     * Checks whether this server is currently running.
     * @returns true if the server is running, false otherwise.
     */
    this.isRunning = function() {
        return jetty != null && jetty.isRunning();
    };

    /**
     * Get the Jetty server instance
     * @returns the Jetty Server instance
     */
    this.getJetty = function() {
        return jetty;
    };

    options = options || {};

    var jettyFile = options.jettyConfig || 'config/jetty.xml';
    var jettyConfig = getResource(jettyFile);
    if (!jettyConfig.exists()) {
        throw Error('Resource "' + jettyFile + '" not found');
    }
    var XmlConfiguration = org.eclipse.jetty.xml.XmlConfiguration;
    var JsgiServlet = org.ringojs.jsgi.JsgiServlet;
    jetty = new org.eclipse.jetty.server.Server();
    xmlconfig = new XmlConfiguration(jettyConfig.inputStream);

    // port config is done via properties
    var props = xmlconfig.getProperties();
    props.put('port', (options.port || 8080).toString());
    if (options.host) props.put('host', options.host);
    xmlconfig.configure(jetty);

    // create default context
    defaultContext = this.getContext(options.mountpoint || "/", options.virtualHost, {
        security: true,
        sessions: true
    });

    // If options defines an application mount it
    if (typeof options.app === "function") {
        defaultContext.serveApplication(options.app);
    } else if (options.app && options.config) {
        defaultContext.serveApplication(options);
    }

    // Allow definition of app/static mappings in server config for convenience
    if (options.staticDir) {
        var files = require('ringo/utils/files');
        var staticContext = this.getContext(options.staticMountpoint || '/static', options.virtualHost);
        staticContext.serveStatic(files.resolveId(options.config, options.staticDir));
    }

    // Start listeners. This allows us to run on privileged port 80 under jsvc
    // even as non-root user if the constructor is called with root privileges
    // while start() is called with the user we will actually run as
    var connectors = jetty.getConnectors();
    for each (var connector in connectors) {
        connector.open();
    }

}

function parseOptions(arguments, defaults) {
    // parse command line options
    parser = new Parser();
    parser.addOption("a", "app", "APP", "The exported property name of the JSGI app (default: 'app')");
    parser.addOption("c", "config", "MODULE", "The module containing the JSGI app (default: 'config')");
    parser.addOption("j", "jetty-config", "PATH", "The jetty xml configuration file (default. 'config/jetty.xml')");
    parser.addOption("H", "host", "ADDRESS", "The IP address to bind to (default: 0.0.0.0)");
    parser.addOption("m", "mountpoint", "PATH", "The URI path where to mount the application (default: /)");
    parser.addOption("p", "port", "PORT", "The TCP port to listen on (default: 80)");
    parser.addOption("s", "static-dir", "DIR", "A directory with static resources to serve");
    parser.addOption("S", "static-mountpoint", "PATH", "The URI path where ot mount the static resources");
    parser.addOption("v", "virtual-host", "VHOST", "The virtual host name (default: undefined)");
    parser.addOption("h", "help", null, "Print help message to stdout");
    options = parser.parse(arguments, defaults);
    if (options.port && !isFinite(options.port)) {
        var port = parseInt(options.port, 10);
        if (isNaN(port) || port < 1) {
            throw "Invalid value for port: " + options.port;
        }
        options.port = port;
    }
    return options;
}

/**
 * Daemon life cycle function invoked by init script. Creates a new Server with
 * the application at `path`. If the application exports a function called
 * `init`, it will be invoked with the new server as argument.
 *
 * @param path {string} optional path to the application. If undefined,
 *     the path will be taken from `system.args`.
 * @returns {Server} the Server instance.
 */
function init(path) {
    // protect against module reloading
    if (started) {
        return server;
    }
    // parse command line options
    var cmd = system.args.shift();
    try {
        options = parseOptions(system.args, {
            app: "app",
            config: "config"
        });
    } catch (error) {
        print(error);
        system.exit(1);
    }

    if (options.help) {
        print("Usage:");
        print("", cmd, "[OPTIONS]", "[PATH]");
        print("Options:");
        print(parser.help());
        system.exit(0);
    }

    var appDir = "";
    // if no explicit path is given use first command line argument
    path = path || system.args[0];
    var fs = require("fs");
    if (path) {
        try {
            // check if argument can be resolved as module id
            require(path);
            options.config = path;
        } catch (error) {
            path = fs.absolute(path);
            if (fs.isDirectory(path)) {
                // if argument is a directory assume app in config.js
                options.config = fs.join(path, "config");
                appDir = path;
            } else {
                // if argument is a file use it as config module
                options.config = path;
                appDir = fs.directory(path);
            }
        }
    } else {
        appDir = fs.workingDirectory();
        options.config = fs.join(appDir, "config");
    }

    // logging module is already loaded and configured, check if webapp provides
    // its own log4j configuration file and apply it if so.
    var logConfig = getResource(fs.join(appDir, "config/log4j.properties"));
    if (logConfig.exists()) {
        require("./logging").setConfig(logConfig);
    }

    server = new Server(options);
    var app = require(options.config);
    if (typeof app.init === "function") {
        app.init(server);
    }
    return server;
}

/**
 * Daemon life cycle function invoked by init script. Starts the Server created
 * by `init()`. If the application exports a function called `start`, it will be
 * invoked with the server as argument immediately after it has started.
 *
 * @returns {Server} the Server instance.
 */
function start() {
    server.start();
    started = true;
    var app = require(options.config);
    if (typeof app.start === "function") {
        app.start(server);
    }
    return server;
}

/**
 * Daemon life cycle function invoked by init script. Stops the Server started
 * by `start()`.
 * @returns {Server} the Server instance. If the application exports a function
 * called `stop`, it will be invoked with the server as argument immediately
 * before it is stopped.
 *
 * @returns {Server} the Server instance.
 */
function stop() {
    var app = require(options.config);
    if (typeof app.stop === "function") {
        app.stop(server);
    }
    server.stop();
    started = false;
    return server;
}

/**
 * Daemon life cycle function invoked by init script. Frees any resources
 * occupied by the Server instance.  If the application exports a function
 * called `destroy`, it will be invoked with the server as argument.
 *
 * @returns {Server} the Server instance.
 */
function destroy() {
    var app = require(options.config);
    if (typeof app.destroy === "function") {
        app.destroy(server);
    }
    server.destroy();
    try {
        return server;
    } finally {
        server = null;
    }
}

/**
 * Main webapp startup function.
 * @param {String} path optional path to the web application directory or config module.
 * @returns {Server} the Server instance.
 */
function main(path) {
    init(path);
    start();
    // return the server instance
    return server;
}

if (require.main == module) {
    main();
}

<|endoftext|>


<commit_before>var Deferred  = require('./deferred');

var IterativeDeferred = module.exports = Deferred.extend({
  initialize: function(to_map) {
    this.supr();
    this.to_map = to_map;
    this._started = false;

    this._onFly = 0;
    this._mapped = [];
    this._resolved = [];
    this._rejected = [];
    this._reduceBuffer = [];
    this._endShouldBeLaunched = false;
  },

  /**
   * Functional programming: easy setter for the map function.
   *
   *   | The map function, to be defined: should map a key to a deferred object.
   *   | Should return a deferred object that will be registered: the iterative
   *   | process won't stop until all registered deferred are completed or a
   *   | manual intervention.
   *   |
   *   | If the key has already been mapped, the mapping will be ignored. To test
   *   | equality between key, @see #equalTestFn.
   *   |
   *   | @param  {object} key - key to map to a Deferred
   *   | @return {undefined | Deferred} mapped Deferred
   *
   * @param  {Function} mapFn [description]
   */
  map: function(mapFn) {
    this.mapFn = mapFn;

    //directly start if anything to map
    if (this.to_map)
      this.start();
    return this;
  },

  /**
   * Set itinial reduce value.
   *
   * @param  {*} init_value
   */
  init: function(init_value) {
    this._currentReduceResult = init_value;
    return this;
  },

  /**
   * Functional programming: easy setter for the reduce function:
   *
   *   | The reduce function, to be defined: should combine resolved result from
   *   | mapped deferred and the previous reduce result. It can feed the mapping
   *   | process with keys to map, by calling the map argument function.
   *   | If the deferred resolved multiple arguments, the additional arguments are
   *   | present.
   *   | At any moment the iterative process can be stopped manually just by
   *   | completing the working process as deferred: simply call `this.resolve` or
   *   | `this.reject`.
   *   | The end arguments key, resolved and rejected are if needed to decide the
   *   | reduce process.
   *   | @param  {*}     previous - previously returned by the reduce function
   *   | @param  {*}       result - the result resolved by the mapped Deferred
   *   | @param  {*} [additional] - if the resolve callback was called with multiple
   *   |                            arguments, additional arguments are present
   *   | @param  {function}   map - use this function to feed the mapping process with
   *   |                            new keys
   *   | @param  {object}     key - original mapping key whose deferred produced the
   *   |                            given resolved result
   *   | @param  {array} resolved - array of keys which mapped Deferred have been resolved
   *   | @param  {array} rejected - array of keys which mapped Deferred have been rejected
   *   | @return {*} reduce result
   *
   * @param {function} reduceFn -  see above
   * @param {*}    initialValue - initial reduce value
   */
  reduce: function(reduceFn, initialValue) {
    this.reduceFn = reduceFn;

    if (initialValue)
      this.init(initialValue);

    //if waiting reduces in buffer, empty it :
    while (this._reduceBuffer.length >0) {
      var args = this._reduceBuffer.shift();
      this._launchReduce.apply(this, args);
    }

    return this;
  },

  /**
   * Functionnal programming: easy setter for the end function.
   *
   *   | The end function, will be called when the iterative process ends, ie. there
   *   | is no more uncompleted mapped Deferred and all reduce processes are finished.
   *   |
   *   | The end function should complete the process by calling `this.resolve` or
   *   | `this.reject`. If this is not done, the process will be automatically resolved.
   *   |
   *   | @param {*} reduce_result - what finally came out the reduce process
   *   | @param {function}    map - use this function to feed the mapping process with
   *   |                            new keys if you want to relaunch the process again
   *   | @param {array}  resolved - array of keys which mapped Deferred have been resolved
   *   | @param {array}  rejected - array of keys which mapped Deferred have been rejected
   *
   * @param  {function} endFn [description]
   */
  end: function(endFn) {
    this.endFn = endFn;

    //it's over : launch immediatly end
    if (this._endShouldBeLaunched)
      this._launchEnd();

    return this;
  },

  /**
   * Start the iterative map/reduce given the this array of
   * map consumable.
   *
   * @param  {Array<key>} array [description]
   */
  start: function(array) {
    if (this._started)
      return this;
    this._started = true;

    if (array)
      this.to_map = array;

    var to_map = this.to_map;
    var length = to_map.length || to_map.size();
    if (length !== 0) {
      //go !
      this.to_map.forEach(function(key) {
        this._launchMap(key);
      }, this);
    } else {
      this._launchEnd();
    }
    return this;
  },

  /**
   * Test the equality of 2 keys.
   *
   * Used to determine if a key has already been mapped. Use an #equals method if
   * present. Else use the result of `===`.
   *
   * @param  {*} key1
   * @param  {*} key2
   * @return {boolean} result
   */
  equalTestFn: function(key1, key2) {
    return (typeof key1.equals === 'function') ?
            key1.equals(key2)
          : key1 === key2;
  },

  _launchMap: function(key) {

    //if the key has alreday been mapped
    var already = this._mapped.some(function(key2) {
      return this.equalTestFn(key, key2);
    }, this);

    if (already) {
      return false;
    }

    this._mapped.push(key);

    //call the map function and get the deferred
    var def = this.mapFn(key);

    if (!def) return true;
    def = Deferred.when(def);

    //we've got a new deferred on the fly
    this._onFly ++;

    function callback() {
      this._onFly --;
      if (!this.isCompleted()) {
        //add to resolved
        this._resolved.push(key);
        //reduce result
        this._launchReduce(key, arguments);
      }
    }

    function errback() {
      this._onFly --;
      if (!this.isCompleted()) {
        //add to rejected
        this._rejected.push(key);
        //end ?
        this._checkFinish();
      }
    }

    //on deferred resolve or reject, decrement
    def.then(callback, errback, this);
    return true;
  },

  _launchReduce: function(key, result) {
    //if the reduce function is not yet defined, put in a buffer for later
    if (!this.reduceFn) {
      this._reduceBuffer.push(arguments);
      return;
    }

    var reduce_args = [],
        i, l, that = this;

    //add previous reduce result
    reduce_args.push(this._currentReduceResult);
    //add resolve result of the mapped deferred
    for (i = 0, l = result.length; i < l; i++) { reduce_args.push(result[i]); }
    reduce_args.push(function map(key) {
      return that._launchMap(key);
    });
    //add the key that produced result
    reduce_args.push(key);
    //add current resolved key
    reduce_args.push(this._resolved);
    //add current rejected key
    reduce_args.push(this._rejected);

    //call reduce
    this._currentReduceResult = this.reduceFn.apply(this, reduce_args);

    //end ?
    this._checkFinish();
  },

  _launchEnd: function() {
    this._endShouldBeLaunched = true;

    if (this.endFn) {
      var toMap = [];
      var map = function(key) { toMap.push(key); };
      this.endFn(this._currentReduceResult, map, this._resolved, this._rejected);

      // if we have to relaunch a mapping
      if (toMap.length) {
        for (var i = 0, l = toMap.length; i < l; i++) {
          this._launchMap(toMap[i]);
        }
      } else if (!this.isCompleted()) {
        //force the completion of the process if endFn didn't do it
        this.resolve(this._currentReduceResult);
      }

    }
  },

  _checkFinish: function() {
    if (this._onFly === 0 && this._reduceBuffer.length === 0 && !this.isCompleted()) {
      this._launchEnd();
    }
  }
});<commit_msg>Code-review on iterative-deferred<commit_after>var Deferred  = require('./deferred');

var _push = Array.prototype.push;

var IterativeDeferred = module.exports = Deferred.extend({
  initialize: function(toMap) {
    this.supr();
    this.toMap = toMap;

    this._started = false;
    this._ended = false;

    this._onFly = 0;
    this._mapped = [];
    this._resolved = [];
    this._rejected = [];
    this._reduceBuffer = [];

    this._mapper = this._launchMap.bind(this);
  },

  /**
   * Functional programming: easy setter for the map function.
   *
   *   | The map function, to be defined: should map a key to a deferred object.
   *   | Should return a deferred object that will be registered: the iterative
   *   | process won't stop until all registered deferred are completed or a
   *   | manual intervention.
   *   |
   *   | If the key has already been mapped, the mapping will be ignored. To test
   *   | equality between key, @see #equalTestFn.
   *   |
   *   | @param  {object} key - key to map to a Deferred
   *   | @return {undefined | Deferred} mapped Deferred
   *
   * @param  {Function} mapFn [description]
   */
  map: function(mapFn) {
    this.mapFn = mapFn;

    // directly start if something to map
    if (this.toMap) this.start();

    return this;
  },

  /**
   * Set itinial reduce value.
   *
   * @param  {*} initialValue
   */
  init: function(initialValue) {
    this._results = initialValue;
    return this;
  },

  /**
   * Functional programming: easy setter for the reduce function:
   *
   *   | The reduce function, to be defined: should combine resolved result from
   *   | mapped deferred and the previous reduce result. It can feed the mapping
   *   | process with keys to map, by calling the map argument function.
   *   | If the deferred resolved multiple arguments, the additional arguments are
   *   | present.
   *   | At any moment the iterative process can be stopped manually just by
   *   | completing the working process as deferred: simply call `this.resolve` or
   *   | `this.reject`.
   *   | The end arguments key, resolved and rejected are if needed to decide the
   *   | reduce process.
   *   | @param  {*}     previous - previously returned by the reduce function
   *   | @param  {*}       result - the result resolved by the mapped Deferred
   *   | @param  {*} [additional] - if the resolve callback was called with multiple
   *   |                            arguments, additional arguments are present
   *   | @param  {function}   map - use this function to feed the mapping process with
   *   |                            new keys
   *   | @param  {object}     key - original mapping key whose deferred produced the
   *   |                            given resolved result
   *   | @param  {array} resolved - array of keys which mapped Deferred have been resolved
   *   | @param  {array} rejected - array of keys which mapped Deferred have been rejected
   *   | @return {*} reduce result
   *
   * @param {function} reduceFn -  see above
   * @param {*}    initialValue - initial reduce value
   */
  reduce: function(reduceFn, initialValue) {
    this.reduceFn = reduceFn;

    if (initialValue) this.init(initialValue);

    // if waiting reduces in buffer, empty it :
    while (this._reduceBuffer.length > 0) {
      this._launchReduce.apply(this, this._reduceBuffer.shift());
    }

    return this;
  },

  /**
   * Functionnal programming: easy setter for the end function.
   *
   *   | The end function, will be called when the iterative process ends, ie. there
   *   | is no more uncompleted mapped Deferred and all reduce processes are finished.
   *   |
   *   | The end function should complete the process by calling `this.resolve` or
   *   | `this.reject`. If this is not done, the process will be automatically resolved.
   *   |
   *   | @param {*} reduce_result - what finally came out the reduce process
   *   | @param {function}    map - use this function to feed the mapping process with
   *   |                            new keys if you want to relaunch the process again
   *   | @param {array}  resolved - array of keys which mapped Deferred have been resolved
   *   | @param {array}  rejected - array of keys which mapped Deferred have been rejected
   *
   * @param  {function} endFn [description]
   */
  end: function(endFn) {
    this.endFn = endFn;

    // it's over : launch immediatly end
    if (this._ended) this._launchEnd();

    return this;
  },

  /**
   * Start the iterative map/reduce given the this array of
   * map consumable.
   *
   * @param  {Array<key>} array [description]
   */
  start: function(array) {
    if (this._started) return this;
    this._started = true;

    if (array) this.toMap = array;

    // go if toMap not empty
    if ((this.toMap.length || this.toMap.size()) > 0) {
      this.toMap.forEach(this._mapper, this);
    } else {
      this._launchEnd();
    }

    return this;
  },

  /**
   * Test the equality of 2 keys.
   *
   * Used to determine if a key has already been mapped. Use an #equals method if
   * present. Else use the result of `===`.
   *
   * @param  {*} key1
   * @param  {*} key2
   * @return {boolean} result
   */
  equalTestFn: function(key1, key2) {
    return (typeof key1.equals === 'function') ? key1.equals(key2) : key1 === key2;
  },

  _launchMap: function(key) {
    var alreday, ret;

    // if the key has alreday been mapped
    already = this._mapped.some(function(key2) {
      return this.equalTestFn(key, key2);
    }, this);

    if (already) return false;
    this._mapped.push(key);

    // call the map function and get the value returned
    if (!(ret = this.mapFn(key))) return true;

    // we've got a new deferred on the fly
    this._onFly++;

    function success() {
      this._onFly--;
      if (this.isCompleted()) return;
      this._resolved.push(key);
      this._launchReduce(key, arguments);
    }

    function failure() {
      this._onFly--;
      if (this.isCompleted()) return;
      this._rejected.push(key);
      this._checkFinish();
    }

    // on deferred resolve or reject, decrement `_onFly
    // and store the result in memory arrays `_rejected` or `_resolved`
    Deferred.when(ret).then(success, failure, this);
    return true;
  },

  _launchReduce: function(key, result) {
    // if the reduce function is not yet defined, put in a buffer for later
    if (!this.reduceFn) {
      this._reduceBuffer.push(arguments);
      return;
    }

    // generate args for the reduce method
    var args = [this._results /*, result..., mapper, key, resolved, rejected */];
    _push.apply(args, result);
    _push.apply(args, [this._mapper, key, this._resolved, this._rejected]);

    // call reduceFn with generated args
    this._results = this.reduceFn.apply(this, args);

    // check if ended
    this._checkFinish();
  },

  _launchEnd: function() {
    // if the end function is not yet defined, save the ended state
    if (!this.endFn) {
      this._ended = true;
      return;
    }

    this.endFn(this._results, this._mapper, this._resolved, this._rejected);
    if (this._onFly === 0 && !this.isCompleted()) {
      // force the completion of the process if endFn didn't do it
      this.resolve(this._results);
    }
  },

  _checkFinish: function() {
    if (this._onFly > 0 || this._reduceBuffer.length > 0 || this.isCompleted()) return;
    this._launchEnd();
  }
});
<|endoftext|>


<commit_before>// @flow
import {readFileSync} from 'fs' // readFile
import path from 'path'
import {sync as globSync} from 'glob'
// import {addLocaleData} from 'react-intl'
import enLocaleData from 'react-intl/locale-data/en'
import ruLocaleData from 'react-intl/locale-data/ru'
import type {i18nConfigObject} from 'types'

const translations = globSync('locals/*.json')
	.map((filename: string) => [
		path.basename(filename, '.json'),
		readFileSync(filename, 'utf8')
	])
	.map(([locale, file]) => [locale, JSON.parse(file)])
	.reduce((acc, [locale, messages]) => {
		acc[locale] = messages
		return acc
	}, {})

const summaryLocaleData = {
	en: enLocaleData,
	ru: ruLocaleData
}

export const defaultLanguage = 'en'
export const supportedLanguages = ['en', 'ru']

export default (lang: string): i18nConfigObject => {
	console.log(lang)
	return {
		lang,
		localeData: summaryLocaleData[lang],
		locale: lang,
		messages: translations[lang]
	}
}
<commit_msg>fix(server/i18n): move summaryLocaleData to inner func<commit_after>// @flow
import {readFileSync} from 'fs' // readFile
import path from 'path'
import {sync as globSync} from 'glob'
// import {addLocaleData} from 'react-intl'
import enLocaleData from 'react-intl/locale-data/en'
import ruLocaleData from 'react-intl/locale-data/ru'
import type {i18nConfigObject} from 'types'

const translations = globSync('locals/*.json')
	.map((filename: string) => [
		path.basename(filename, '.json'),
		readFileSync(filename, 'utf8')
	])
	.map(([locale, file]) => [locale, JSON.parse(file)])
	.reduce((acc, [locale, messages]) => {
		acc[locale] = messages
		return acc
	}, {})

export const defaultLanguage = 'en'
export const supportedLanguages = ['en', 'ru']

export default (lang: string = defaultLanguage): i18nConfigObject => {
	const summaryLocaleData = {
		en: enLocaleData,
		ru: ruLocaleData
	}
	return {
		lang,
		localeData: summaryLocaleData[lang],
		locale: lang,
		messages: translations[lang]
	}
}
<|endoftext|>


<commit_before>const AssignMail = require('../mail/assign')
const PaymentMail = require('../mail/payment')
const Promise = require('bluebird')
const models = require('../../models')
const Stripe = require('stripe')
const stripe = new Stripe(process.env.STRIPE_KEY)
const TransferMail = require('../mail/transfer')
const DeadlineMail = require('../mail/deadline')
const assignExist = require('../assigns').assignExists
const offerExists = require('../offers').offerExists
const memberExists = require('../members').memberExists
const i18n = require('i18n')
const constants = require('../mail/constants')
const TaskMail = require('../mail/task')

const createSourceAndCharge = Promise.method((customer, orderParameters, order, task, user) => {
  return stripe.customers.createSource(customer.id, { source: orderParameters.source_id }).then(card => {
    const centavosAmount = orderParameters.amount * 100
    return stripe.charges.create({
      amount: centavosAmount * 0.92, // 8% base fee
      currency: orderParameters.currency,
      customer: customer.id,
      source: card.id,
      transfer_group: `task_${task.dataValues.id}`,
      metadata: { order_id: order.dataValues.id }
    }).then(charge => {
      if (charge) {
        return order.updateAttributes({
          source: charge.id,
          source_id: card.id,
          paid: charge.paid,
          status: charge.status
        }).then(updatedUser => {
          PaymentMail.success(user, task, order.amount)
          TaskMail.notifyPayment(task.dataValues.User, {
            task: {
              title: task.dataValues.title,
              value: order.dataValues.amount,
              issue_url: task.dataValues.url,
              url: constants.taskUrl(task.dataValues.id)
            }
          })
          if (task.dataValues.assigned) {
            const assignedId = task.dataValues.assigned
            return models.Assign.findById(assignedId, {
              include: [models.User]
            }).then(assign => {
              PaymentMail.assigned(assign.dataValues.User.dataValues.email, task, order.amount)
              return task
            })
          }
          return task
        })
      }
      throw new Error('no charge')
    }).catch(e => {
      // eslint-disable-next-line no-console
      console.log('could not create charge', e)
      throw new Error(e)
    })
  })
})

const createCustomer = Promise.method((orderParameters, order, task, user) => {
  return stripe.customers.create({
    email: orderParameters.email
  }).then(customer => {
    if (order.userId) {
      return models.User.update({ customer_id: customer.id }, { where: { id: order.userId } }).then(update => {
        if (!update) {
          throw new Error('user not updated')
        }
        return createSourceAndCharge(customer, orderParameters, order, task, user)
      })
    }
    return createSourceAndCharge(customer, orderParameters, order, task, user)
  })
})

const postCreateOrUpdateOffer = Promise.method((task, offer) => {
  if (offer) {
    return models.User.findOne({
      where: {
        id: offer.userId
      }
    }).then((user) => {
      const usermail = user.dataValues.email
      const language = user.language || 'en'
      i18n.setLocale(language)
      if (!usermail) {
        AssignMail.error('mail.assign.register.error' + task.dataValues)
      }
      if (!user.account_id) {
        TransferMail.futurePaymentForInvalidAccount(user)
      }
      AssignMail.interested(user.dataValues, task.dataValues)
      if (task.dataValues.User) {
        const ownerUser = task.dataValues.User.dataValues
        AssignMail.owner(ownerUser, task.dataValues, user, offer)
      }
      return task.dataValues
    })
  }
})

module.exports = Promise.method(function taskUpdate (taskParameters) {
  return models.Task
    .update(taskParameters, {
      where: {
        id: taskParameters.id,
      },
      include: [models.User, models.Order, models.Offer, models.Member]
    }).then((data) => {
      if (!data) {
        return new Error('task_updated_failed')
      }
      return models.Task.findById(taskParameters.id, { include: [ models.User, models.Order, models.Assign, models.Member ] })
        .then((task) => {
          if (!task) {
            return new Error('task_find_failed')
          }
          if (taskParameters.Orders) {
            return task.createOrder(taskParameters.Orders[0]).then((order) => {
              const orderParameters = taskParameters.Orders[0]
              if (order.userId) {
                return models.User.findById(order.userId).then((user) => {
                  if (user && user.dataValues.customer_id) {
                    return stripe.customers.retrieve(user.customer_id).then((customer) => {
                      return createSourceAndCharge(customer, orderParameters, order, task, user.dataValues)
                    })
                  }
                  else {
                    return createCustomer(orderParameters, order, task, user.dataValues)
                  }
                })
              }
              else {
                return createCustomer(orderParameters, order, task, { email: taskParameters.Orders[0].email })
              }
            })
          }

          if (taskParameters.deadline) {
            if (task.dataValues.assigned) {
              return models.Assign.findOne({
                where: {
                  id: task.dataValues.assigned
                },
                include: [models.User]
              }).then((assigned) => {
                const assignedUserDeadline = assigned.User.dataValues
                DeadlineMail.update(assignedUserDeadline.email, task.dataValues, assignedUserDeadline.username)
                return task.dataValues
              })
            }
          }

          if (taskParameters.Offers || taskParameters.Assigns) {
            return assignExist({
              userId: taskParameters.Assigns[0].userId,
              taskId: taskParameters.id
            }).then(existingAssign => {
              return task.createAssign(taskParameters.Assigns[0]).then(assign => {
                return offerExists({
                  userId: taskParameters.Offers[0].userId,
                  taskId: taskParameters.id
                }).then(resp => {
                  if (!resp) {
                    return task.createOffer(taskParameters.Offers[0]).then(offer => {
                      return postCreateOrUpdateOffer(task, taskParameters.Offers[0])
                    })
                  }
                  else {
                    return models.Offer.update(taskParameters.Offers[0], { where: { userId: taskParameters.Offers[0].userId,
                      taskId: taskParameters.id } }).then(update => {
                      return postCreateOrUpdateOffer(task, taskParameters.Offers[0])
                    })
                  }
                })
              })
            })
          }

          if (taskParameters.Members) {
            return memberExists({
              userId: taskParameters.Members[0].userId
            }).then(resp => {
              if (!resp) {
                return task.createMember(taskParameters.Members[0]).then(member => {
                  return task.dataValues
                }).catch(e => {
                  return task.dataValues
                })
              }
              else {
                return models.Member.update(taskParameters.Members[0], { where: { userId: taskParameters.Members[0].userId,
                  taskId: taskParameters.id } }).then(update => {
                  return task.dataValues
                })
              }
            })
          }

          if (taskParameters.assigned) {
            return models.Assign.findOne({
              where: {
                id: taskParameters.assigned
              },
              include: [models.User]
            }).then((assigned) => {
              const assignedUser = assigned.User.dataValues
              AssignMail.assigned(assignedUser, task.dataValues)
              return task.dataValues
            })
          }
          return task.dataValues
        })
    })
})
<commit_msg>commenting the new bounty added notification for now (#393)<commit_after>const AssignMail = require('../mail/assign')
const PaymentMail = require('../mail/payment')
const Promise = require('bluebird')
const models = require('../../models')
const Stripe = require('stripe')
const stripe = new Stripe(process.env.STRIPE_KEY)
const TransferMail = require('../mail/transfer')
const DeadlineMail = require('../mail/deadline')
const assignExist = require('../assigns').assignExists
const offerExists = require('../offers').offerExists
const memberExists = require('../members').memberExists
const i18n = require('i18n')
// const constants = require('../mail/constants')
// const TaskMail = require('../mail/task')

const createSourceAndCharge = Promise.method((customer, orderParameters, order, task, user) => {
  return stripe.customers.createSource(customer.id, { source: orderParameters.source_id }).then(card => {
    const centavosAmount = orderParameters.amount * 100
    return stripe.charges.create({
      amount: centavosAmount * 0.92, // 8% base fee
      currency: orderParameters.currency,
      customer: customer.id,
      source: card.id,
      transfer_group: `task_${task.dataValues.id}`,
      metadata: { order_id: order.dataValues.id }
    }).then(charge => {
      if (charge) {
        return order.updateAttributes({
          source: charge.id,
          source_id: card.id,
          paid: charge.paid,
          status: charge.status
        }).then(updatedUser => {
          PaymentMail.success(user, task, order.amount)
          /*
          TaskMail.notifyPayment(task.dataValues.User, {
            task: {
              title: task.dataValues.title,
              value: order.dataValues.amount,
              issue_url: task.dataValues.url,
              url: constants.taskUrl(task.dataValues.id)
            }
          })
          */
          if (task.dataValues.assigned) {
            const assignedId = task.dataValues.assigned
            return models.Assign.findById(assignedId, {
              include: [models.User]
            }).then(assign => {
              PaymentMail.assigned(assign.dataValues.User.dataValues.email, task, order.amount)
              return task
            })
          }
          return task
        })
      }
      throw new Error('no charge')
    }).catch(e => {
      // eslint-disable-next-line no-console
      console.log('could not create charge', e)
      throw new Error(e)
    })
  })
})

const createCustomer = Promise.method((orderParameters, order, task, user) => {
  return stripe.customers.create({
    email: orderParameters.email
  }).then(customer => {
    if (order.userId) {
      return models.User.update({ customer_id: customer.id }, { where: { id: order.userId } }).then(update => {
        if (!update) {
          throw new Error('user not updated')
        }
        return createSourceAndCharge(customer, orderParameters, order, task, user)
      })
    }
    return createSourceAndCharge(customer, orderParameters, order, task, user)
  })
})

const postCreateOrUpdateOffer = Promise.method((task, offer) => {
  if (offer) {
    return models.User.findOne({
      where: {
        id: offer.userId
      }
    }).then((user) => {
      const usermail = user.dataValues.email
      const language = user.language || 'en'
      i18n.setLocale(language)
      if (!usermail) {
        AssignMail.error('mail.assign.register.error' + task.dataValues)
      }
      if (!user.account_id) {
        TransferMail.futurePaymentForInvalidAccount(user)
      }
      AssignMail.interested(user.dataValues, task.dataValues)
      if (task.dataValues.User) {
        const ownerUser = task.dataValues.User.dataValues
        AssignMail.owner(ownerUser, task.dataValues, user, offer)
      }
      return task.dataValues
    })
  }
})

module.exports = Promise.method(function taskUpdate (taskParameters) {
  return models.Task
    .update(taskParameters, {
      where: {
        id: taskParameters.id,
      },
      include: [models.User, models.Order, models.Offer, models.Member]
    }).then((data) => {
      if (!data) {
        return new Error('task_updated_failed')
      }
      return models.Task.findById(taskParameters.id, { include: [ models.User, models.Order, models.Assign, models.Member ] })
        .then((task) => {
          if (!task) {
            return new Error('task_find_failed')
          }
          if (taskParameters.Orders) {
            return task.createOrder(taskParameters.Orders[0]).then((order) => {
              const orderParameters = taskParameters.Orders[0]
              if (order.userId) {
                return models.User.findById(order.userId).then((user) => {
                  if (user && user.dataValues.customer_id) {
                    return stripe.customers.retrieve(user.customer_id).then((customer) => {
                      return createSourceAndCharge(customer, orderParameters, order, task, user.dataValues)
                    })
                  }
                  else {
                    return createCustomer(orderParameters, order, task, user.dataValues)
                  }
                })
              }
              else {
                return createCustomer(orderParameters, order, task, { email: taskParameters.Orders[0].email })
              }
            })
          }

          if (taskParameters.deadline) {
            if (task.dataValues.assigned) {
              return models.Assign.findOne({
                where: {
                  id: task.dataValues.assigned
                },
                include: [models.User]
              }).then((assigned) => {
                const assignedUserDeadline = assigned.User.dataValues
                DeadlineMail.update(assignedUserDeadline.email, task.dataValues, assignedUserDeadline.username)
                return task.dataValues
              })
            }
          }

          if (taskParameters.Offers || taskParameters.Assigns) {
            return assignExist({
              userId: taskParameters.Assigns[0].userId,
              taskId: taskParameters.id
            }).then(existingAssign => {
              return task.createAssign(taskParameters.Assigns[0]).then(assign => {
                return offerExists({
                  userId: taskParameters.Offers[0].userId,
                  taskId: taskParameters.id
                }).then(resp => {
                  if (!resp) {
                    return task.createOffer(taskParameters.Offers[0]).then(offer => {
                      return postCreateOrUpdateOffer(task, taskParameters.Offers[0])
                    })
                  }
                  else {
                    return models.Offer.update(taskParameters.Offers[0], { where: { userId: taskParameters.Offers[0].userId,
                      taskId: taskParameters.id } }).then(update => {
                      return postCreateOrUpdateOffer(task, taskParameters.Offers[0])
                    })
                  }
                })
              })
            })
          }

          if (taskParameters.Members) {
            return memberExists({
              userId: taskParameters.Members[0].userId
            }).then(resp => {
              if (!resp) {
                return task.createMember(taskParameters.Members[0]).then(member => {
                  return task.dataValues
                }).catch(e => {
                  return task.dataValues
                })
              }
              else {
                return models.Member.update(taskParameters.Members[0], { where: { userId: taskParameters.Members[0].userId,
                  taskId: taskParameters.id } }).then(update => {
                  return task.dataValues
                })
              }
            })
          }

          if (taskParameters.assigned) {
            return models.Assign.findOne({
              where: {
                id: taskParameters.assigned
              },
              include: [models.User]
            }).then((assigned) => {
              const assignedUser = assigned.User.dataValues
              AssignMail.assigned(assignedUser, task.dataValues)
              return task.dataValues
            })
          }
          return task.dataValues
        })
    })
})
<|endoftext|>


<commit_before>import React from 'react' // required for JSX
import { renderToString } from 'react-dom/server'
import App from '../components/App'
import { Provider } from 'react-redux'
import getPopulatedStore from './store'
import * as api from './api'
import { readFileSync } from 'fs'
import { Router, match, RoutingContext } from 'react-router'
import configureRoutes from '../configure-routes'

const INDEX_HTML = readFileSync(__dirname + '/../../static/index.html', 'utf8')

export default (req, res, next) => {
  // Fetch data depending on URL, that may be hard to maintain
  getPopulatedStore().then(store => {
    var pending = []
    const addPending = (promise) => pending.push(promise)
    const routes = configureRoutes(api, store, addPending)

    match({ routes, location: req.url }, (error, redirection, props) => {
      Promise.all(pending).then(() => {
        if (error) {
          res.status(500).send(error.message)
        } else if (redirection) {
          res.redirect(302, redirection.pathname + redirection.search)
        } else if (props) {
          renderRoute(req, res, props, store)
        } else {
          res.status(404).send('Not found')
        }
      }).catch(next)
    })
  })
}

function renderRoute (req, res, props, store) {
  const state = store.getState()
  const stateScript = '<script>window.APP_STATE=' + JSON.stringify(state) + '</script>'

  const root = <Provider store={ store }><RoutingContext { ...props } /></Provider>
  const div = renderToString(root)

  const html = INDEX_HTML
    .replace(/<!-- APP_HERE -->/, div)
    .replace(/<!-- STATE_HERE -->/, stateScript)

  res.send(html)
}
<commit_msg>22 - revert use of getPopulatedStore in render-app<commit_after>import React from 'react' // required for JSX
import { renderToString } from 'react-dom/server'
import App from '../components/App'
import { Provider } from 'react-redux'
import configureStore from '../configure-store'
import * as api from './api'
import { readFileSync } from 'fs'
import { Router, match, RoutingContext } from 'react-router'
import configureRoutes from '../configure-routes'

const INDEX_HTML = readFileSync(__dirname + '/../../static/index.html', 'utf8')

export default (req, res, next) => {
  // Fetch data depending on URL, that may be hard to maintain
  const store = configureStore()
  var pending = []
  const addPending = (promise) => pending.push(promise)
  const routes = configureRoutes(api, store, addPending)

  match({ routes, location: req.url }, (error, redirection, props) => {
    Promise.all(pending).then(() => {
      if (error) {
        res.status(500).send(error.message)
      } else if (redirection) {
        res.redirect(302, redirection.pathname + redirection.search)
      } else if (props) {
        renderRoute(req, res, props, store)
      } else {
        res.status(404).send('Not found')
      }
    }).catch(next)
  })
}

function renderRoute (req, res, props, store) {
  const state = store.getState()
  const stateScript = '<script>window.APP_STATE=' + JSON.stringify(state) + '</script>'

  const root = <Provider store={ store }><RoutingContext { ...props } /></Provider>
  const div = renderToString(root)

  const html = INDEX_HTML
    .replace(/<!-- APP_HERE -->/, div)
    .replace(/<!-- STATE_HERE -->/, stateScript)

  res.send(html)
}
<|endoftext|>


<commit_before>/**
 * Created by mhylle on 29-11-2015.
 */
var utils = require('../framework/utils/generator')

function user() {
    this.internalId = utils.uniqueID();
    this.publicId = '';
    this.nickname = '';
    this.firstname = '';
    this.lastname = '';
    this.username = '';

    this.salt = '';
    this.hash = '';

    // todo handle address section..
    this.address = '';
    this.mail = '';
    this.phone = '';
    this.isadmin = false;

}
<commit_msg>started modelling the data model. Should help going forward. Group and User for now<commit_after>/**
 * Created by mhylle on 29-11-2015.
 */
var utils = require('../framework/utils/generator')

function user() {
    this.internalId = utils.uniqueID();
    this.publicId = '';
    this.nickname = '';
    this.firstname = '';
    this.lastname = '';
    this.username = '';

    this.salt = '';
    this.hash = '';

    // todo handle address section..
    this.address = '';
    this.mail = '';
    this.phone = '';
    this.isadmin = false;

    this.groups = [];
}
<|endoftext|>