<commit_before>/**
 * Kettle Requests
 *
 * Copyright 2012-2013 OCAD University
 *
 * Licensed under the New BSD license. You may not use this file except in
 * compliance with this License.
 *
 * You may obtain a copy of the License at
 * https://github.com/gpii/kettle/LICENSE.txt
 */

"use strict";

var fluid = require("infusion"),
    $ = fluid.registerNamespace("jQuery"),
    kettle = fluid.registerNamespace("kettle");

fluid.defaults("kettle.requests", {
    gradeNames: ["autoInit", "fluid.eventedComponent"],
    events: {
        onNewRequest: null,
        onHandleRequest: null
    },
    listeners: {
        onHandleRequest: "{that}.handleRequest"
    },
    invokers: {
        onSuccessHandler: {
            funcName: "kettle.requests.eventHandler",
            args: ["onSuccess", "{arguments}"]
        },
        onErrorHandler: {
            funcName: "kettle.requests.eventHandler",
            args: ["onError", "{arguments}"]
        },
        handleRequest: {
            funcName: "kettle.requests.handleRequest",
            args: ["{arguments}.0", "{arguments}.1"]
        }
    },
    dynamicComponents: {
        request: {
            createOnEvent: "onNewRequest",
            type: "kettle.requests.request.http",
            options: {
                req: "{arguments}.0",
                res: "{arguments}.1",
                next: "{arguments}.2"
            }
        }
    },
    members: {
        middlewareListeners: {},
        middlewareEvents: {}
    }
});

fluid.defaults("kettle.requestProxy", {
    gradeNames: ["autoInit", "fluid.eventedComponent"],
    events: {
        onError: null,
        onSuccess: null
    },
    listeners: {
        onError: "{kettle.requests}.onErrorHandler",
        onSuccess: "{kettle.requests}.onSuccessHandler"
    }
});

kettle.requests.handleRequest = function (request, context) {
    // TODO: As well as being completely cack-handed, this scheme supplies no useful diagnostics when the handler is not found
    request.handlerContext = fluid.model.composePath(
        "kettle.requests.request.handler", context);
    request.events.handle.fire();
};

/**
 * Fire an onSuccess or onError event for a particular request object.
 * @param  {String} eventName a name of the event. Can be onSuccess or
 * onError.
 * @param  {Array} args an arbitrary arguments for the event firer.
 */
kettle.requests.eventHandler = function (eventName, args) {
    var request = kettle.getCurrentRequest();
    request.events[eventName].fire.apply(null, args);
};

/** Construct a "promisified" proxy for the handling of this request. It will
 * have handlers registered which forward to this requests success and error events.
 * The promise may be rejected or resolved by the user to represent that disposition
 * for the overall request
 */
kettle.requests.constructRequestPromise = function (request) {
    var togo = fluid.promise();
    togo.then(function (value) {
        request.events.onSuccess.fire(value);
    }, function (error) {
        request.events.onError.fire(error);
    });
    return togo;
};

fluid.defaults("kettle.requests.request", {
    gradeNames: ["autoInit", "fluid.eventedComponent", "fluid.applyGradeLinkage"],
    invokers: {
        onErrorHandler: "kettle.requests.request.onErrorHandler",
        onSuccessHandler: "kettle.requests.request.onSuccessHandler",
        ensureResCompleted: {
            funcName: "kettle.requests.request.ensureResCompleted",
            args: "{that}"
        },
        attachFluidRequest: "kettle.requests.request.attachFluidRequest"
    },
    components: {
        handler: {
            type: "kettle.requests.request.handler",
            createOnEvent: "handle"
        }
    },
    events: {
        handle: null,
        onRequestEnd: null,
        onError: null,
        onSuccess: null
    },
    listeners: {
        onCreate: [
            "{that}.ensureResCompleted",
            "{that}.attachFluidRequest"
        ],
        onError: "{that}.onErrorHandler",
        onSuccess: "{that}.onSuccessHandler"
    }
});

fluid.defaults("kettle.requests.request.http", {
    mergePolicy: {
        "req": "nomerge",
        "res": "nomerge",
        "next": "nomerge"
    },
    members: {
        req: "{that}.options.req",
        res: "{that}.options.res",
        next: "{that}.options.next",
        requestPromise: "@expand:kettle.requests.constructRequestPromise({that})"
    },
    gradeNames: ["autoInit", "kettle.requests.request",
        "{requests}.eventedRequestGrade"],
    invokers: {
        onErrorHandler: {
            funcName: "kettle.requests.request.http.onErrorHandler",
            args: ["{that}.res", "{arguments}.0"]
        },
        onSuccessHandler: {
            funcName: "kettle.requests.request.http.onSuccessHandler",
            args: ["{that}.res", "{arguments}.0"]
        },
        ensureResCompleted: {
            funcName: "kettle.requests.request.http.ensureResCompleted"
        },
        // Adding a request object to express's req.
        attachFluidRequest: {
            funcName: "fluid.set",
            args: ["{that}.req", "fluidRequest", "{that}"]
        },
        proceed: {
            funcName: "kettle.requests.request.http.proceed",
            args: "{that}.next"
        }
    },
    listeners: {
        onAttach: "{that}.proceed"
    }
});

/**
 * Continue resolving current request.
 * @param  {Function} next proceeds to the next step of request resolution.
 */
kettle.requests.request.http.proceed = function (next) {
    next();
};

/**
 * Ensure that the response is properly disposed of when finished.
 * @param  {Object} that request object.
 */
kettle.requests.request.http.ensureResCompleted = function (that) {
    // NOTE: This is here because any of these events can represent the
    // moment when the server is finished with the response.
    fluid.each(["close", "finish", "end", "error"], function addListener(event) {
        that.res.on(event, function eventListener() {
            that.events.onRequestEnd.fire();
            that.destroy();
        });
    });
};

/**
 * Send an error payload to the client if the error event is fired.
 * @param  {Object} res a response object.
 * @param  {Object}   error an error payload.
 */
kettle.requests.request.http.onErrorHandler = function (res, error) {
    var outError = $.extend(true, {
        isError: true,
        message: "Unknown error",
        statusCode: 500
    }, error);
    res.send(outError, outError.statusCode);
};

/**
 * Send a successful payload to the client if the success event is fired.
 * @param  {Object} res a response object.
 * @param  {Object} response a success payload.
 */
kettle.requests.request.http.onSuccessHandler = function (res, response) {
    if (typeof(response) !== "string") {
        res.json(response);
    } else {
        res.send(response, 200);
    }
};

fluid.defaults("kettle.requests.request.handler", {
    gradeNames: ["autoInit", "fluid.eventedComponent", "{request}.handlerContext", "fluid.applyGradeLinkage"],
    invokers: {
        // NB - this is a nonexistent function - this entire block is expected to
        // be overridden by a relevant grade.
        handle: "kettle.requests.request.handler.handle"
    },
    listeners: {
        onAttach: {
            listener: "fluid.withEnvironment",
            args: [{
                request: "{request}"
            }, "{that}.handle"]
        }
    }
});

<commit_msg>KETTLE-33: Quick fix for request error handling issue required to get Device Reporter test cases functioning - wider fix with test cases to follow<commit_after>/**
 * Kettle Requests
 *
 * Copyright 2012-2013 OCAD University
 *
 * Licensed under the New BSD license. You may not use this file except in
 * compliance with this License.
 *
 * You may obtain a copy of the License at
 * https://github.com/gpii/kettle/LICENSE.txt
 */

"use strict";

var fluid = require("infusion"),
    $ = fluid.registerNamespace("jQuery"),
    kettle = fluid.registerNamespace("kettle");

fluid.defaults("kettle.requests", {
    gradeNames: ["autoInit", "fluid.eventedComponent"],
    events: {
        onNewRequest: null,
        onHandleRequest: null
    },
    listeners: {
        onHandleRequest: "{that}.handleRequest"
    },
    invokers: {
        onSuccessHandler: {
            funcName: "kettle.requests.eventHandler",
            args: ["onSuccess", "{arguments}"]
        },
        onErrorHandler: {
            funcName: "kettle.requests.eventHandler",
            args: ["onError", "{arguments}"]
        },
        handleRequest: {
            funcName: "kettle.requests.handleRequest",
            args: ["{arguments}.0", "{arguments}.1"]
        }
    },
    dynamicComponents: {
        request: {
            createOnEvent: "onNewRequest",
            type: "kettle.requests.request.http",
            options: {
                req: "{arguments}.0",
                res: "{arguments}.1",
                next: "{arguments}.2"
            }
        }
    },
    members: {
        middlewareListeners: {},
        middlewareEvents: {}
    }
});

fluid.defaults("kettle.requestProxy", {
    gradeNames: ["autoInit", "fluid.eventedComponent"],
    events: {
        onError: null,
        onSuccess: null
    },
    listeners: {
        onError: "{kettle.requests}.onErrorHandler",
        onSuccess: "{kettle.requests}.onSuccessHandler"
    }
});

kettle.requests.handleRequest = function (request, context) {
    // TODO: As well as being completely cack-handed, this scheme supplies no useful diagnostics when the handler is not found
    request.handlerContext = fluid.model.composePath(
        "kettle.requests.request.handler", context);
    request.events.handle.fire();
};

/**
 * Fire an onSuccess or onError event for a particular request object.
 * @param  {String} eventName a name of the event. Can be onSuccess or
 * onError.
 * @param  {Array} args an arbitrary arguments for the event firer.
 */
kettle.requests.eventHandler = function (eventName, args) {
    var request = kettle.getCurrentRequest();
    request.events[eventName].fire.apply(null, args);
};

/** Construct a "promisified" proxy for the handling of this request. It will
 * have handlers registered which forward to this requests success and error events.
 * The promise may be rejected or resolved by the user to represent that disposition
 * for the overall request
 */
kettle.requests.constructRequestPromise = function (request) {
    var togo = fluid.promise();
    togo.then(function (value) {
        request.events.onSuccess.fire(value);
    }, function (error) {
        request.events.onError.fire(error);
    });
    return togo;
};

fluid.defaults("kettle.requests.request", {
    gradeNames: ["autoInit", "fluid.eventedComponent", "fluid.applyGradeLinkage"],
    invokers: {
        onErrorHandler: "kettle.requests.request.onErrorHandler",
        onSuccessHandler: "kettle.requests.request.onSuccessHandler",
        ensureResCompleted: {
            funcName: "kettle.requests.request.ensureResCompleted",
            args: "{that}"
        },
        attachFluidRequest: "kettle.requests.request.attachFluidRequest"
    },
    components: {
        handler: {
            type: "kettle.requests.request.handler",
            createOnEvent: "handle"
        }
    },
    events: {
        handle: null,
        onRequestEnd: null,
        onError: null,
        onSuccess: null
    },
    listeners: {
        onCreate: [
            "{that}.ensureResCompleted",
            "{that}.attachFluidRequest"
        ],
        onError: "{that}.onErrorHandler",
        onSuccess: "{that}.onSuccessHandler"
    }
});

fluid.defaults("kettle.requests.request.http", {
    mergePolicy: {
        "req": "nomerge",
        "res": "nomerge",
        "next": "nomerge"
    },
    members: {
        req: "{that}.options.req",
        res: "{that}.options.res",
        next: "{that}.options.next",
        requestPromise: "@expand:kettle.requests.constructRequestPromise({that})"
    },
    gradeNames: ["autoInit", "kettle.requests.request",
        "{requests}.eventedRequestGrade"],
    invokers: {
        onErrorHandler: {
            funcName: "kettle.requests.request.http.onErrorHandler",
            args: ["{that}.res", "{arguments}.0"]
        },
        onSuccessHandler: {
            funcName: "kettle.requests.request.http.onSuccessHandler",
            args: ["{that}.res", "{arguments}.0"]
        },
        ensureResCompleted: {
            funcName: "kettle.requests.request.http.ensureResCompleted"
        },
        // Adding a request object to express's req.
        attachFluidRequest: {
            funcName: "fluid.set",
            args: ["{that}.req", "fluidRequest", "{that}"]
        },
        proceed: {
            funcName: "kettle.requests.request.http.proceed",
            args: "{that}.next"
        }
    },
    listeners: {
        onAttach: "{that}.proceed"
    }
});

/**
 * Continue resolving current request.
 * @param  {Function} next proceeds to the next step of request resolution.
 */
kettle.requests.request.http.proceed = function (next) {
    next();
};

/**
 * Ensure that the response is properly disposed of when finished.
 * @param  {Object} that request object.
 */
kettle.requests.request.http.ensureResCompleted = function (that) {
    // NOTE: This is here because any of these events can represent the
    // moment when the server is finished with the response.
    fluid.each(["close", "finish", "end", "error"], function addListener(event) {
        that.res.on(event, function eventListener() {
            if (!fluid.isDestroyed(that)) {
                that.events.onRequestEnd.fire();
                that.destroy();
            }
        });
    });
};

/**
 * Send an error payload to the client if the error event is fired.
 * @param  {Object} res a response object.
 * @param  {Object}   error an error payload.
 */
kettle.requests.request.http.onErrorHandler = function (res, error) {
    var outError = $.extend(true, {
        isError: true,
        message: "Unknown error",
        statusCode: 500
    }, error);
    res.send(outError, outError.statusCode);
};

/**
 * Send a successful payload to the client if the success event is fired.
 * @param  {Object} res a response object.
 * @param  {Object} response a success payload.
 */
kettle.requests.request.http.onSuccessHandler = function (res, response) {
    if (typeof(response) !== "string") {
        res.json(response);
    } else {
        res.send(response, 200);
    }
};

fluid.defaults("kettle.requests.request.handler", {
    gradeNames: ["autoInit", "fluid.eventedComponent", "{request}.handlerContext", "fluid.applyGradeLinkage"],
    invokers: {
        // NB - this is a nonexistent function - this entire block is expected to
        // be overridden by a relevant grade.
        handle: "kettle.requests.request.handler.handle"
    },
    listeners: {
        onAttach: {
            listener: "fluid.withEnvironment",
            args: [{
                request: "{request}"
            }, "{that}.handle"]
        }
    }
});

<|endoftext|>


<commit_before>var querystring = require('querystring');
var https = require('https');
var http = require('http');
var url = require('url');
var rutil = require('./request-util.js');
var util = require('util');
var fs = require('fs');
var path = require('path');
var mime = require('mime');

Request.CONTENT_TYPE = {
  JSON: 'application/json',
  TXT: 'text/plain',
  MULTIPART: 'multipart/form-data'
};

Request.METHODES = {
 GET: 'GET',
 POST: 'POST',
 PUT: 'PUT',
 PATCH: 'PATCH',
 DELETE: 'DELETE',
 OPTIONS: 'OPTIONS',
 HEAD: 'HEAD'
};

/**
 * A simple chainable, readable object with the intense to make speaking HTTP sane.
 * @param {boolean} [debug=false] enable debugging with true
 */
function Request(debug) {

  var _debug = debug;
  var _headers = {};
  var _urlObject = false;
  var _sendContentType = Request.CONTENT_TYPE.JSON;
  var _encoding = 'utf-8';
  var _boundaryKey = false;
  var _data = {};
  var _method = Request.METHODES.GET;
  var _endpoint;
  var _bufferSize = 4 * 1024;
  var _rejectUnauthorized = true;

  /**
   * create a header for multipart requests
   * @private
   * @return {string} the header for the request
   */
  var _createMultipartHeader = function() {
    var fileHeaderLine = [];
    fileHeaderLine.push('--' + _boundaryKey);
    fileHeaderLine.push('Content-Type: ' + mime.lookup(_data));
    fileHeaderLine.push('Content-Disposition: form-data; name="file"; filename="' + path.basename(_data) + '"');
    fileHeaderLine.push('Content-Transfer-Encoding: binary');
    fileHeaderLine.push('\r\n');
    return fileHeaderLine.join('\r\n');
  };

  /**
   * create a footer for the mulitpart request
   * @private
   * @return {string} the footer for the request
   */
  var _createMultipartFooter = function() {
    return ['\r\n--', _boundaryKey, '--'].join('');
  };

  /**
   * create a options object for the request
   * @private
   * @return {obkect} options used for the request
   */
  var _createOptions = function() {
    var options = {
      host: _urlObject.hostname,
      path: _endpoint,
      method: _method,
      headers: _headers,
      port: _urlObject.port,
      rejectUnauthorized: _rejectUnauthorized
    };
    if (_debug) {
      console.log(options);
    }
    return options;
  };

  /**
   * get the needed protocol
   * @private
   * @return {object} the http or https object dependend on the url
   */
  var _getProtocol = function() {
    return (_urlObject.protocol === 'http:') ? http : https;
  }

  /**
   * create functions for each METHODE type (POST, GET, PUT, etc.)
   */
  for (var method in Request.METHODES) {
    this[Request.METHODES[method].toLowerCase()] = (function(method) {
      return function(paraUrl) {
        _urlObject = url.parse(paraUrl);
        _method = method;
        return this;
      }
    })(method);
  }

  /**
   * set the data for the request
   * @param  {object} data data as json object
   * @return {object}      self
   */
  this.data = function(data) {
    _data = data;
    return this;
  };

  /**
   * add a header
   * @param {string} key   header key
   * @param {string} value value of the header entry
   * @return {object} self
   */
  this.addHeader = function(key, value) {
    _headers[key] = value;
    return this;
  };

  /**
   * Don't verifie against the list of supplied CAs.
   * @return {object} self
   */
  this.allowUnauthorized = function() {
    _rejectUnauthorized = false;
    return this;
  }

  /**
   * set a authorization header
   * @param {string} authStr authirization string
   * @return {object} self
   */
  this.addAuthorizationHeader = function(authStr) {
    this.addHeader('authorization', authStr);
    return this;
  };

  /**
   * set which type of format you want to send, default ist json
   * @param {object} contentType a valid content type
   * @return {object} self
   */
  this.setSendContentType = function(contentType) {
    _sendContentType = contentType;
    return this;
  };

  /**
   * function to send plain text to the server only make sense with post or put
   * @return {object} self
   */
  this.sendsPlain = function() {
    _sendContentType = Request.CONTENT_TYPE.TXT;
    return this;
  };

  /**
   * defines a multipart request for files, used with post() and data(filename)
   * @return {object} self
   */
  this.sendMultipart = function() {
    _boundaryKey = Math.random().toString(16);
    _sendContentType = Request.CONTENT_TYPE.MULTIPART;
    this.addHeader('Content-Type', [_sendContentType,'; ', 'boundary="', _boundaryKey, '"'].join(''));
    this.setEncoding('binary');
    return this;
  };

  /**
   * set the buffer size for a multipart request default is 4 * 1024
   * @param {number} bufferSize size in byte
   * @return {object} self
   */
  this.setBufferSize = function(bufferSize) {
    _bufferSize = bufferSize;
    return this;
  }

  /**
   * set the response encoding, default is utf-8
   * @param {string} encoding a valid encoding
   * @return {object} self
   */
  this.setEncoding = function(encoding) {
    _encoding = encoding;
    return this;
  };

  /**
   * set the format for the send callback, default is json
   * @param  {string} type a valid content type
   * @return {object}      self
   */
  this.expects = function(type) {
    this.expects = type;
    return this;
  };

  /**
   * perform the previously created request
   * @param  {Function} [callback] function called when the request is ready
   * @return {object}            self
   */
  this.send = function(callback) {
    var _this = this;
    var dataString;
    var fileHeader;
    var fileFooter;

    _endpoint = _urlObject.path;

    if (_method === Request.METHODES.GET) {
      if (!rutil.isEmpty(_data)) {
        _endpoint += '?' + querystring.stringify(_data);
      }
      _data = false;
    } else if (_sendContentType == Request.CONTENT_TYPE.MULTIPART) {
      fileHeader = _createMultipartHeader();
      fileFooter = _createMultipartFooter();
      this.addHeader('Content-Length', Buffer.byteLength(fs.readFileSync(_data)) + fileHeader.length + fileFooter.length);
    } else {
      dataString = JSON.stringify(_data);
      this.addHeader('Content-Type', _sendContentType);
      this.addHeader('Content-Length', dataString.length);
    }

    var req = _getProtocol().request(_createOptions(), function(res) {
      res.setEncoding(_encoding);

      var responseArray = [];
      res.on('data', function(resData) {
        responseArray.push(resData);
      });

      res.on('end', function() {
        var responseString = responseArray.join('');
        if (_debug) {
          console.log(responseString);
        }
        if (util.isFunction(callback)) {
          if (_this.expects === Request.CONTENT_TYPE.JSON) {
            try {
              callback(JSON.parse(responseString));
            } catch(e) {
              if (_debug) {
                console.log('Response is no valid JSON');
              }
              callback(null);
            }
          } else {
            callback(responseString);
          }
        }
      });

    });

    if (_sendContentType === Request.CONTENT_TYPE.JSON) {
      if (dataString) {
        req.write(dataString);
      }
      req.end();
    } else if (_sendContentType === Request.CONTENT_TYPE.MULTIPART) {
      req.write(fileHeader);
      fs.createReadStream(_data, {
        bufferSize: _bufferSize
      }).on('end', function() {
        req.end(fileFooter);
      }).pipe(req, { end: false });
    } else {
      if (_data && !rutil.isEmpty(_data)) {
        req.write(_data);
      }
      req.end();
    }

    req.on('error', function(error) {
      if (_debug) {
        console.log(error);
      }
    });

    return this;
  };

  return this;
}

module.exports = Request;<commit_msg>some bugfixes and more loggin<commit_after>var querystring = require('querystring');
var https = require('https');
var http = require('http');
var url = require('url');
var rutil = require('./request-util.js');
var util = require('util');
var fs = require('fs');
var path = require('path');
var mime = require('mime');

Request.CONTENT_TYPE = {
  JSON: 'application/json',
  TXT: 'text/plain',
  MULTIPART: 'multipart/form-data'
};

Request.METHODES = {
 GET: 'GET',
 POST: 'POST',
 PUT: 'PUT',
 PATCH: 'PATCH',
 DELETE: 'DELETE',
 OPTIONS: 'OPTIONS',
 HEAD: 'HEAD'
};

/**
 * A simple chainable, readable object with the intense to make speaking HTTP sane.
 * @param {boolean} [debug=false] enable debugging with true
 */
function Request(debug) {

  var _debug = debug;
  var _headers = {};
  var _urlObject = false;
  var _sendContentType = Request.CONTENT_TYPE.JSON;
  var _encoding = 'UTF-8';
  var _boundaryKey = false;
  var _data = {};
  var _method = Request.METHODES.GET;
  var _endpoint;
  var _bufferSize = 4 * 1024;
  var _rejectUnauthorized = true;

  /**
   * create a header for multipart requests
   * @private
   * @return {string} the header for the request
   */
  var _createMultipartHeader = function() {
    var fileHeaderLine = [];
    fileHeaderLine.push('--' + _boundaryKey);
    fileHeaderLine.push('Content-Type: ' + mime.lookup(_data));
    fileHeaderLine.push('Content-Disposition: form-data; name="file"; filename="' + path.basename(_data) + '"');
    fileHeaderLine.push('Content-Transfer-Encoding: binary');
    fileHeaderLine.push('\r\n');
    return fileHeaderLine.join('\r\n');
  };

  /**
   * create a footer for the mulitpart request
   * @private
   * @return {string} the footer for the request
   */
  var _createMultipartFooter = function() {
    return ['\r\n--', _boundaryKey, '--'].join('');
  };

  /**
   * create a options object for the request
   * @private
   * @return {obkect} options used for the request
   */
  var _createOptions = function() {
    var options = {
      host: _urlObject.hostname,
      path: _endpoint,
      method: _method,
      headers: _headers,
      port: _urlObject.port,
      rejectUnauthorized: _rejectUnauthorized
    };
    if (_debug) {
      console.log(options);
    }
    return options;
  };

  /**
   * get the needed protocol
   * @private
   * @return {object} the http or https object dependend on the url
   */
  var _getProtocol = function() {
    return (_urlObject.protocol === 'http:') ? http : https;
  }

  /**
   * create functions for each METHODE type (POST, GET, PUT, etc.)
   */
  for (var method in Request.METHODES) {
    this[Request.METHODES[method].toLowerCase()] = (function(method) {
      return function(paraUrl) {
        _urlObject = url.parse(paraUrl);
        _method = method;
        return this;
      }
    })(method);
  }

  /**
   * set the data for the request
   * @param  {object} data data as json object
   * @return {object}      self
   */
  this.data = function(data) {
    _data = data;
    return this;
  };

  /**
   * add a header
   * @param {string} key   header key
   * @param {string} value value of the header entry
   * @return {object} self
   */
  this.addHeader = function(key, value) {
    _headers[key] = value;
    return this;
  };

  /**
   * Don't verifie against the list of supplied CAs.
   * @return {object} self
   */
  this.allowUnauthorized = function() {
    _rejectUnauthorized = false;
    return this;
  }

  /**
   * set a authorization header
   * @param {string} authStr authirization string
   * @return {object} self
   */
  this.addAuthorizationHeader = function(authStr) {
    this.addHeader('authorization', authStr);
    return this;
  };

  /**
   * set which type of format you want to send, default ist json
   * @param {object} contentType a valid content type
   * @return {object} self
   */
  this.setSendContentType = function(contentType) {
    _sendContentType = contentType;
    return this;
  };

  /**
   * function to send plain text to the server only make sense with post or put
   * @return {object} self
   */
  this.sendsPlain = function() {
    _sendContentType = Request.CONTENT_TYPE.TXT;
    return this;
  };

  /**
   * defines a multipart request for files, used with post() and data(filename)
   * @return {object} self
   */
  this.sendMultipart = function() {
    _boundaryKey = Math.random().toString(16);
    _sendContentType = Request.CONTENT_TYPE.MULTIPART;
    this.addHeader('Content-Type', [_sendContentType,'; ', 'boundary="', _boundaryKey, '"'].join(''));
    this.setEncoding('binary');
    return this;
  };

  /**
   * set the buffer size for a multipart request default is 4 * 1024
   * @param {number} bufferSize size in byte
   * @return {object} self
   */
  this.setBufferSize = function(bufferSize) {
    _bufferSize = bufferSize;
    return this;
  }

  /**
   * set the response encoding, default is utf-8
   * @param {string} encoding a valid encoding
   * @return {object} self
   */
  this.setEncoding = function(encoding) {
    _encoding = encoding;
    return this;
  };

  /**
   * set the format for the send callback, default is json
   * @param  {string} type a valid content type
   * @return {object}      self
   */
  this.expects = function(type) {
    this.expects = type;
    return this;
  };

  /**
   * perform the previously created request
   * @param  {Function} [callback] function called when the request is ready
   * @return {object}            self
   */
  this.send = function(callback) {
    var _this = this;
    var dataString;
    var fileHeader;
    var fileFooter;

    _endpoint = _urlObject.path;

    if (_method === Request.METHODES.GET) {
      if (_data  && !rutil.isEmpty(_data)) {
        _endpoint += '?' + querystring.stringify(_data);
      }
      _data = false;
    } else if (_sendContentType == Request.CONTENT_TYPE.MULTIPART) {
      fileHeader = _createMultipartHeader();
      fileFooter = _createMultipartFooter();
      this.addHeader('Content-Length', Buffer.byteLength(fs.readFileSync(_data)) + fileHeader.length + fileFooter.length);
    } else {
      dataString = JSON.stringify(_data);
      this.addHeader('Content-Type', _sendContentType);
      this.addHeader('Content-Length', dataString.length);
    }

    var req = _getProtocol().request(_createOptions(), function(res) {
      res.setEncoding(_encoding);

      if(_debug) {
        console.log('resonse code:', res.statusCode);
      }

      var responseArray = [];
      res.on('data', function(resData) {
        responseArray.push(resData);
      });

      res.on('end', function() {
        var responseString = responseArray.join('');
        if (_debug) {
          console.log(responseString);
        }
        if (util.isFunction(callback)) {
          if (_this.expects === Request.CONTENT_TYPE.JSON) {
            try {
              if (!responseString) {
                callback({});
              } else {
                callback(JSON.parse(responseString));
              }
            } catch(e) {
              if (_debug) {
                console.log('Response is no valid JSON');
              }
              callback(null);
            }
          } else {
            callback(responseString);
          }
        }
      });

    });

    if (_sendContentType === Request.CONTENT_TYPE.JSON) {
      if (dataString) {
        req.write(dataString);
      }
      req.end();
    } else if (_sendContentType === Request.CONTENT_TYPE.MULTIPART) {
      req.write(fileHeader);
      fs.createReadStream(_data, {
        bufferSize: _bufferSize
      }).on('end', function() {
        req.end(fileFooter);
      }).pipe(req, { end: false });
    } else {
      if (_data && !rutil.isEmpty(_data)) {
        req.write(_data);
      }
      req.end();
    }

    req.on('error', function(error) {
      if (_debug) {
        console.log(error);
      }
    });

    return this;
  };

  return this;
}

module.exports = Request;<|endoftext|>


<commit_before>"use strict"

var fs = require('fs'),
    qs = require('qs'),
    helpers = require('./helpers'),
    chalk = require('chalk'),
    FormData = require('form-data');

class Request {

    constructor(requestKey, config, userArgs) {

        this.start;

        this.end;

        this._defaults = {
            protocol: 'http:',
            method: 'GET',
            endpoint: '',
            query: '',
            headers: {},
            body: '',
            env: '127.0.0.1'
        };

        this.rawConfig = config;

        this.sanitizedConfig = Object.assign(this._defaults,
                                      helpers.cloneWithDefinedProps(config),
                                      helpers.cloneWithDefinedProps(userArgs));
        this.requestKey = requestKey;

        this.url =  this._getUrl();

        this.config = this._parseConfig();
    }

    getExecutionTime() {
        return `${this.end[0]}s:${Math.round(this.end[1]/1000000)}ms`;
    }

    _parseConfig() {
        var c = {};
        c.method = this.sanitizedConfig.method;
        c.body = this._getBody();
        c.headers = this._getHeaders(c.body);
        return c;
    }

    _getUrl() {
        return `${this.sanitizedConfig.protocol}//${this.sanitizedConfig.env}/${this.sanitizedConfig.endpoint ? this.sanitizedConfig.endpoint : ''}${this.sanitizedConfig.query ? '?' + this.sanitizedConfig.query : ''}`
    }

    _getBody() {

        var contentType = helpers.getPropSafely(this.sanitizedConfig.headers, 'content-type', ''),
            body = this.sanitizedConfig.body;

        if (contentType === 'application/json') {

            body = JSON.stringify(this.sanitizedConfig.body);

        } else if (contentType === 'application/x-www-form-urlencoded') {

            body = qs.stringify(this.sanitizedConfig.body);

        } else if (contentType === 'multipart/form-data') {

            body = Object.keys(this.sanitizedConfig.body).reduce((form, prop) => {

                var append = helpers.isFilePath(this.sanitizedConfig.body[prop]) ?
                    fs.createReadStream(helpers.getAbsoluteFilePath(this.sanitizedConfig.body[prop])) :
                    this.sanitizedConfig.body[prop];

                form.append(prop, append);

                return form;

            }, new FormData());

        } else if (typeof this.sanitizedConfig.body === 'object') {
            //TODO create error constants
            console.log(`[Error] \"${this.requestKey}\" request: A 'content-type' header is required if request body is an object:`);
            console.log(`${JSON.stringify(this.sanitizedConfig, null, 4)}`);
            process.exit(1);
        }

        return body;
    }

    _getHeaders(processedBody) {

        var contentHeaders;

        if (processedBody !== '') {
            if (processedBody instanceof FormData) {
                contentHeaders = processedBody.getHeaders();
            } else {
                contentHeaders = { 'Content-Length': Buffer.byteLength(processedBody) };
            }
        }

        return Object.assign(this.sanitizedConfig.headers, contentHeaders || {});
    }
}

module.exports = Request;
<commit_msg>refactor get url method<commit_after>"use strict"

var fs = require('fs'),
    qs = require('qs'),
    helpers = require('./helpers'),
    chalk = require('chalk'),
    FormData = require('form-data');

class Request {

    constructor(requestKey, config, userArgs) {

        this.start;

        this.end;

        this._defaults = {
            protocol: 'http:',
            method: 'GET',
            endpoint: '',
            query: '',
            headers: {},
            body: '',
            env: '127.0.0.1'
        };

        this.rawConfig = config;

        this.sanitizedConfig = Object.assign(this._defaults,
                                      helpers.cloneWithDefinedProps(config),
                                      helpers.cloneWithDefinedProps(userArgs));
        this.requestKey = requestKey;

        this.url =  this._getUrl();

        this.config = this._parseConfig();
    }

    getExecutionTime() {
        return `${this.end[0]}s:${Math.round(this.end[1]/1000000)}ms`;
    }

    _parseConfig() {
        var c = {};
        c.method = this.sanitizedConfig.method;
        c.body = this._getBody();
        c.headers = this._getHeaders(c.body);
        return c;
    }

    _getUrl() {
        return this.sanitizedConfig.protocol + '//'
            + this.sanitizedConfig.env + '/';
            + this.sanitizedConfig.endpoint ? this.sanitizedConfig.endpoint : ''
            + this.sanitizedConfig.query ? '?' + this.sanitizedConfig.query : '';
    }

    _getBody() {

        var contentType = helpers.getPropSafely(this.sanitizedConfig.headers, 'content-type', ''),
            body = this.sanitizedConfig.body;

        if (contentType === 'application/json') {

            body = JSON.stringify(this.sanitizedConfig.body);

        } else if (contentType === 'application/x-www-form-urlencoded') {

            body = qs.stringify(this.sanitizedConfig.body);

        } else if (contentType === 'multipart/form-data') {

            body = Object.keys(this.sanitizedConfig.body).reduce((form, prop) => {

                var append = helpers.isFilePath(this.sanitizedConfig.body[prop]) ?
                    fs.createReadStream(helpers.getAbsoluteFilePath(this.sanitizedConfig.body[prop])) :
                    this.sanitizedConfig.body[prop];

                form.append(prop, append);

                return form;

            }, new FormData());

        } else if (typeof this.sanitizedConfig.body === 'object') {
            //TODO create error constants
            console.log(`[Error] \"${this.requestKey}\" request: A 'content-type' header is required if request body is an object:`);
            console.log(`${JSON.stringify(this.sanitizedConfig, null, 4)}`);
            process.exit(1);
        }

        return body;
    }

    _getHeaders(processedBody) {

        var contentHeaders;

        if (processedBody !== '') {
            if (processedBody instanceof FormData) {
                contentHeaders = processedBody.getHeaders();
            } else {
                contentHeaders = { 'Content-Length': Buffer.byteLength(processedBody) };
            }
        }

        return Object.assign(this.sanitizedConfig.headers, contentHeaders || {});
    }
}

module.exports = Request;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const require = function(){
	"use strict";
	if (!window.scope){
		window.scope = {};
	}
	const scope = window.scope;

	function getScopeName(module){
		var scopeName = module.replace(/^\..*\//, "").replace(/\..+/, "");
		// console.log(scopeName);
		return scopeName;
	}

	function require(module){
		if (module.startsWith(".")){
			var scopeName = getScopeName(module);
			return scope[scopeName];
		}
		throw new ReferenceError("Unable to get non relative module " + module + "!");
	}

	require.register = function(moduleName, module = {}){
		const scopeName = getScopeName(moduleName);
		if (!require.exists(moduleName)){
			scope[scopeName] = module;
			return module;
		}
		else {
			require("./logging").error("Module", moduleName, "already registered.");
			return scope[scopeName];
		}
	};

	require.exists = function(module){
		return scope.hasOwnProperty(getScopeName(module));
	};

	return require;
}();<commit_msg>Minibug in require<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const require = function(){
	"use strict";
	if (!window.scope){
		window.scope = {};
	}
	const scope = window.scope;

	function getScopeName(module){
		var scopeName = module.replace(/^\..*\//, "").replace(/\..+/, "");
		// console.log(scopeName);
		return scopeName;
	}

	function require(module){
		if (module.startsWith(".")){
			var scopeName = getScopeName(module);
			return scope[scopeName];
		}
		throw new ReferenceError("Unable to get non relative module " + module + "!");
	}

	require.register = function(moduleName, module = {}){
		const scopeName = getScopeName(moduleName);
		if (!scope.hasOwnProperty(scopeName)){
			scope[scopeName] = module;
			return module;
		}
		else {
			require("./logging").error("Module", moduleName, "already registered.");
			return scope[scopeName];
		}
	};

	require.exists = function(module){
		return scope.hasOwnProperty(getScopeName(module));
	};

	return require;
}();<|endoftext|>


<commit_before>'use strict';
function RestAPI(apiGateway, api) {
	this._apiGateway = apiGateway;
	this._api = api;

	this._resources = {};
}

RestAPI.prototype.import = function (content) {
	var params = {
		restApiId: this._api.id,
		body: JSON.stringify(content)
	};

	return this._apiGateway.putRestApi(params);
};

module.exports = RestAPI;
<commit_msg>use `overwrite` as default mode<commit_after>'use strict';
function RestAPI(apiGateway, api) {
	this._apiGateway = apiGateway;
	this._api = api;

	this._resources = {};
}

RestAPI.prototype.import = function (content) {
	var params = {
		restApiId: this._api.id,
		body: JSON.stringify(content),
		mode: 'overwrite'
	};

	return this._apiGateway.putRestApi(params);
};

module.exports = RestAPI;
<|endoftext|>


<commit_before>var Stream = require('stream');
var json = typeof JSON === 'object' ? JSON : require('jsonify');
var through = require('through');
var nextTick = typeof setImmediate !== 'undefined'
    ? setImmediate
    : process.nextTick
;

module.exports = function () {
    var output = through();
    output.pause();
    output.queue('TAP version 13\n');

    var results = new Results(output);
    output.push = function (t) { results.push(t) };

    output.only = function (name) {
        results.only = name;
    };

    nextTick(function next () {
        var t = results.tests.shift();
        if (!t && results.running) return;
        if (!t) return results.close();
        t.run();
    });

    return output;
};

function Results (stream) {
    this.count = 0;
    this.fail = 0;
    this.pass = 0;
    this.stream = stream;
    this.tests = [];
    this.running = 0;
}

Results.prototype.push = function (t, parentT) {
    var self = this;
    var write = function (s) { self.stream.queue(s) };
    t.once('prerun', function () {
        if (self.only && self.only !== t.name && !parentT) {
            var nt = self.tests.shift();
            if (nt) nt.run()
            else self.close();
            return;
        }

        self.running ++;
        write('# ' + t.name + '\n');
    });
    if (parentT) {
        var ix = self.tests.indexOf(parentT);
        if (ix >= 0) self.tests.splice(ix, 0, t);
    }
    else self.tests.push(t);

    var plan;
    t.on('plan', function (n) { plan = n });

    var subtests = 0;

    t.on('test', function (st) {
        subtests ++;
        st.on('end', function () {
            subtests --;
            if (subtests === 1) nextTick(function () { st.run() });
            else if (subtests === 0 && !t.ended) {
                t.end();
            }
        });
        self.push(st, t);
        if (subtests === 1) {
            if (plan === undefined) st.run();
            else nextTick(function () {
                st.run();
            });
        }
    });

    t.on('result', function (res) {
        if (typeof res === 'string') {
            write('# ' + res + '\n');
            return;
        }
        write(encodeResult(res, self.count + 1));
        self.count ++;

        if (res.ok) self.pass ++
        else self.fail ++
    });

    t.once('end', function () {
        if (t._skip) {
            var nt = self.tests.shift();
            if (nt) nt.run();
            else self.close();
            return;
        }

        self.running --;
        if (subtests !== 0) return;

        if (self.running === 0 && self.tests.length) {
            var nt = self.tests.shift();
            nt.run();
        }
        else if (self.running === 0) {
            self.close();
        }
    });
};

Results.prototype.close = function () {
    var self = this;
    if (self.closed) self.stream.emit('error', new Error('ALREADY CLOSED'));
    self.closed = true;
    var write = function (s) { self.stream.queue(s) };

    write('\n1..' + self.count + '\n');
    write('# tests ' + self.count + '\n');
    write('# pass  ' + self.pass + '\n');
    if (self.fail) write('# fail  ' + self.fail + '\n')
    else write('\n# ok\n')

    self.stream.queue(null);
};

function encodeResult (res, count) {
    var output = '';
    output += (res.ok ? 'ok ' : 'not ok ') + count;
    output += res.name ? ' ' + res.name.replace(/\s+/g, ' ') : '';

    if (res.skip) output += ' # SKIP';
    else if (res.todo) output += ' # TODO';

    output += '\n';
    if (res.ok) return output;

    var outer = '  ';
    var inner = outer + '  ';
    output += outer + '---\n';
    output += inner + 'operator: ' + res.operator + '\n';

    var ex = json.stringify(res.expected, getSerialize()) || '';
    var ac = json.stringify(res.actual, getSerialize()) || '';

    if (Math.max(ex.length, ac.length) > 65) {
        output += inner + 'expected:\n' + inner + '  ' + ex + '\n';
        output += inner + 'actual:\n' + inner + '  ' + ac + '\n';
    }
    else {
        output += inner + 'expected: ' + ex + '\n';
        output += inner + 'actual:   ' + ac + '\n';
    }
    if (res.at) {
        output += inner + 'at: ' + res.at + '\n';
    }
    if (res.operator === 'error' && res.actual && res.actual.stack) {
        var lines = String(res.actual.stack).split('\n');
        output += inner + 'stack:\n';
        output += inner + '  ' + lines[0] + '\n';
        for (var i = 1; i < lines.length; i++) {
            output += inner + lines[i] + '\n';
        }
    }

    output += outer + '...\n';
    return output;
}

function getSerialize () {
    var seen = [];

    return function (key, value) {
        var ret = value;
        if (typeof value === 'object' && value) {
            var found = false;
            for (var i = 0; i < seen.length; i++) {
                if (seen[i] === value) {
                    found = true
                    break;
                }
            }

            if (found) ret = '[Circular]'
            else seen.push(value)
        }
        return ret;
    };
}
<commit_msg>test.only should not run any other test blocks<commit_after>var Stream = require('stream');
var json = typeof JSON === 'object' ? JSON : require('jsonify');
var through = require('through');
var nextTick = typeof setImmediate !== 'undefined'
    ? setImmediate
    : process.nextTick
;

module.exports = function () {
    var output = through();
    output.pause();
    output.queue('TAP version 13\n');

    var results = new Results(output);
    output.push = function (t) { results.push(t) };

    output.only = function (name) {
        results.only = name;
    };

    nextTick(function next () {
        var t = getNextTest(results);
        if (!t && results.running) return;
        if (!t) return results.close();
        t.run();
    });

    return output;
};

function Results (stream) {
    this.count = 0;
    this.fail = 0;
    this.pass = 0;
    this.stream = stream;
    this.tests = [];
    this.running = 0;
}

Results.prototype.push = function (t, parentT) {
    var self = this;
    var write = function (s) { self.stream.queue(s) };
    t.once('prerun', function () {
        if (self.only && self.only !== t.name && !parentT) {
            var nt = getNextTest(self);
            if (nt) nt.run()
            else self.close();
            return;
        }

        self.running ++;
        write('# ' + t.name + '\n');
    });
    if (parentT) {
        var ix = self.tests.indexOf(parentT);
        if (ix >= 0) self.tests.splice(ix, 0, t);
    }
    else self.tests.push(t);

    var plan;
    t.on('plan', function (n) { plan = n });

    var subtests = 0;

    t.on('test', function (st) {
        subtests ++;
        st.on('end', function () {
            subtests --;
            if (subtests === 1) nextTick(function () { st.run() });
            else if (subtests === 0 && !t.ended) {
                t.end();
            }
        });
        self.push(st, t);
        if (subtests === 1) {
            if (plan === undefined) st.run();
            else nextTick(function () {
                st.run();
            });
        }
    });

    t.on('result', function (res) {
        if (typeof res === 'string') {
            write('# ' + res + '\n');
            return;
        }
        write(encodeResult(res, self.count + 1));
        self.count ++;

        if (res.ok) self.pass ++
        else self.fail ++
    });

    t.once('end', function () {
        if (t._skip) {
            var nt = getNextTest(self);
            if (nt) nt.run();
            else self.close();
            return;
        }

        self.running --;
        if (subtests !== 0) return;

        if (self.running === 0 && self.tests.length) {
            var nt = getNextTest(self);
            if (nt) nt.run();
            else self.close();
        }
        else if (self.running === 0) {
            self.close();
        }
    });
};

Results.prototype.close = function () {
    var self = this;
    if (self.closed) self.stream.emit('error', new Error('ALREADY CLOSED'));
    self.closed = true;
    var write = function (s) { self.stream.queue(s) };

    write('\n1..' + self.count + '\n');
    write('# tests ' + self.count + '\n');
    write('# pass  ' + self.pass + '\n');
    if (self.fail) write('# fail  ' + self.fail + '\n')
    else write('\n# ok\n')

    self.stream.queue(null);
};

function encodeResult (res, count) {
    var output = '';
    output += (res.ok ? 'ok ' : 'not ok ') + count;
    output += res.name ? ' ' + res.name.replace(/\s+/g, ' ') : '';

    if (res.skip) output += ' # SKIP';
    else if (res.todo) output += ' # TODO';

    output += '\n';
    if (res.ok) return output;

    var outer = '  ';
    var inner = outer + '  ';
    output += outer + '---\n';
    output += inner + 'operator: ' + res.operator + '\n';

    var ex = json.stringify(res.expected, getSerialize()) || '';
    var ac = json.stringify(res.actual, getSerialize()) || '';

    if (Math.max(ex.length, ac.length) > 65) {
        output += inner + 'expected:\n' + inner + '  ' + ex + '\n';
        output += inner + 'actual:\n' + inner + '  ' + ac + '\n';
    }
    else {
        output += inner + 'expected: ' + ex + '\n';
        output += inner + 'actual:   ' + ac + '\n';
    }
    if (res.at) {
        output += inner + 'at: ' + res.at + '\n';
    }
    if (res.operator === 'error' && res.actual && res.actual.stack) {
        var lines = String(res.actual.stack).split('\n');
        output += inner + 'stack:\n';
        output += inner + '  ' + lines[0] + '\n';
        for (var i = 1; i < lines.length; i++) {
            output += inner + lines[i] + '\n';
        }
    }

    output += outer + '...\n';
    return output;
}

function getSerialize () {
    var seen = [];

    return function (key, value) {
        var ret = value;
        if (typeof value === 'object' && value) {
            var found = false;
            for (var i = 0; i < seen.length; i++) {
                if (seen[i] === value) {
                    found = true
                    break;
                }
            }

            if (found) ret = '[Circular]'
            else seen.push(value)
        }
        return ret;
    };
}

function getNextTest(results) {
    if (!results.only)
        return results.tests.shift();
    }

    do {
        var t = results.tests.shift();
        if (tick) {
            return null;
        }
        if (results.only === t.name) {
            return t;
        }
    } while (results.tests.length !== 0)
}
<|endoftext|>


<commit_before>//  Grid Data Provider
//	===================
//
//	provides data to a lux.grid using websockets
define(['angular',
        'lux/grid',
        'lux/services/stream'], function (angular) {
    'use strict';

    angular.module('lux.grid.stream', ['lux.grid', 'lux.stream'])

        .run(['$lux', 'luxGridDataProviders', function ($lux, dataProvider) {

            dataProvider.register('websocket', gridDataProviderWebsocketFactory($lux, dataProvider));
        }]);

    function gridDataProviderWebsocketFactory ($lux, dataProvider) {

        function GridDataProviderWebsocket (grid) {
            this._grid = grid;
            this._websocketUrl = grid.options.target.url;
            this._channel = grid.options.target.channel;
            this._model = grid.options.target.model;
        }

        GridDataProviderWebsocket.prototype.destroy = function() {
            this._grid = null;
        };

        GridDataProviderWebsocket.prototype.connect = function() {
            dataProvider.check(this);

            function onMessage (msg) {
                var tasks;

                if (msg.data.event === 'record-update') {
                    tasks = msg.data.data;

                    this._grid.onDataReceived({
                        total: msg.data.total,
                        result: tasks,
                        type: 'update'
                    });

                } else if (msg.data.event === 'records') {
                    tasks = msg.data.data;

                    this._grid.onDataReceived({
                        total: msg.data.total,
                        result: tasks,
                        type: 'update'
                    });

                } else if (msg.data.event === 'columns-metadata') {
                    this._grid.onMetadataReceived(msg.result);
                }
            }

            this._stream = $lux.stream(this._websocketUrl);

            this._stream.rpc(
                'model_metadata',
                { 'model': this._model },
                onMetadataReceived.bind(this),
                function() { console.log('rpc error', arguments); } // TODO display error on grid?
            );
        };

        GridDataProviderWebsocket.prototype.getPage = function (options) {
            this._stream.rpc(
                'model_data',
                { 'model': this._model },
                onDataReceived.bind(this),
                function() { console.log('rpc error', arguments); }
            );
        };

        GridDataProviderWebsocket.prototype.deleteItem = function(identifier, onSuccess, onFailure) {
            var options = {id: identifier};
            this._stream.rpc(this._channel, options).then(onSuccess, onFailure);
        };

        function onMetadataReceived(msg) {
            this._grid.onMetadataReceived(msg.result);
        }

        function onDataReceived(msg) {
            this._grid.onDataReceived(msg.result);
        }

        return GridDataProviderWebsocket;
    }

});
<commit_msg>Websocket grids now have working filtering and sorting<commit_after>//  Grid Data Provider
//	===================
//
//	provides data to a lux.grid using websockets
define(['angular',
        'lux/grid',
        'lux/services/stream'], function (angular) {
    'use strict';

    angular.module('lux.grid.stream', ['lux.grid', 'lux.stream'])

        .run(['$lux', 'luxGridDataProviders', function ($lux, dataProvider) {

            dataProvider.register('websocket', gridDataProviderWebsocketFactory($lux, dataProvider));
        }]);

    function gridDataProviderWebsocketFactory ($lux, dataProvider) {

        function GridDataProviderWebsocket (grid) {
            this._grid = grid;
            this._websocketUrl = grid.options.target.url;
            this._channel = grid.options.target.channel;
            this._model = grid.options.target.model;
        }

        GridDataProviderWebsocket.prototype.destroy = function() {
            this._grid = null;
        };

        GridDataProviderWebsocket.prototype.connect = function() {
            dataProvider.check(this);

            this._stream = $lux.stream(this._websocketUrl);

            this._stream.rpc(
                'model_metadata',
                { 'model': this._model },
                onMetadataReceived.bind(this),
                function() { console.log('rpc model_metadata error', arguments); } // TODO display error on grid?
            );
        };

        GridDataProviderWebsocket.prototype.getPage = function (options) {
            var query = this._grid.state.query();

            if (typeof options === 'object') {
                angular.extend(query, options);
            }

            query.model = this._model;

            this._stream.rpc(
                'model_data',
                query,
                onDataReceived.bind(this),
                function() { console.log('rpc model_data error', arguments); }
            );
        };

        GridDataProviderWebsocket.prototype.deleteItem = function(identifier, onSuccess, onFailure) {
            var options = {id: identifier};
            this._stream.rpc(this._channel, options).then(onSuccess, onFailure);
        };

        function onMetadataReceived(msg) {
            this._grid.onMetadataReceived(msg.result);
        }

        function onDataReceived(msg) {
            this._grid.onDataReceived(msg.result);
        }

        return GridDataProviderWebsocket;
    }

});
<|endoftext|>


<commit_before>"use strict";

var rewards = {};
var groups = require.main.require('./src/groups');
var user = require.main.require('./src/user');
var db = require.main.require('./src/database');

rewards.get = function(rewards, callback) {
	getGroupList(function(err, groups) {
		rewards = rewards.concat([
			{
				"rid": "essentials/add-to-group",
				"name": "Add to Group",
				"inputs": [
					{
						"type": "select",
						"name": "groupname",
						"label": "Group Name:",
						"values": groups
					}
				]
			},
			{
                                "rid": "essentials/remove-from-group",
                                "name": "Remove from Group",
                                "inputs": [
                                        {
                                                "type": "select",
                                                "name": "groupname",
                                                "label": "Group Name:",
                                                "values": groups
                                        }
                                ]
                        },

			{
				"rid": "essentials/alert-user",
				"name": "Send alert message",
				"inputs": [
					{
						"type": "text",
						"name": "title",
						"label": "Title:"
					},
					{
						"type": "text",
						"name": "message",
						"label": "Message:"
					}
				]
			},
			{
				"rid": "essentials/award-reputation",
				"name": "Award Reputation",
				"inputs": [
					{
						"type": "text",
						"name": "reputation",
						"label": "Amount of reputation:"
					}
				]
			}
		]);

		callback(false, rewards);
	});
};

rewards.addToGroup = function(data) {
	groups.join(data.reward.groupname, data.uid);
};

rewards.alertUser = function(data) {
	var websockets = require.main.require('./src/socket.io');
	websockets.in('uid_' + data.uid).emit('event:alert', data.reward);
};

rewards.awardReputation = function(data) {
	user.incrementUserFieldBy(data.uid, 'reputation', data.reward.reputation, function(err, newreputation) {
		db.sortedSetAdd('users:reputation', newreputation, data.uid);
	});
};

function getGroupList(callback) {
	var list = [];

	groups.getGroups('groups:createtime', 0, -1, function(err, groups) {
		groups.forEach(function(group) {
			var name = group;
			if ((name = group.match(/cid:([0-9]*):privileges:groups:([\s\S]*)/)) !== null) {
				name = 'Category ' + name[1] + ' group with privilege ' + name[2];
			}

			list.push({
				name: name ? name : group,
				value: group
			});
		});

		callback(err, list);
	});
}

module.exports = rewards;
<commit_msg>removeFromGroup method<commit_after>"use strict";

var rewards = {};
var groups = require.main.require('./src/groups');
var user = require.main.require('./src/user');
var db = require.main.require('./src/database');

rewards.get = function(rewards, callback) {
	getGroupList(function(err, groups) {
		rewards = rewards.concat([
			{
				"rid": "essentials/add-to-group",
				"name": "Add to Group",
				"inputs": [
					{
						"type": "select",
						"name": "groupname",
						"label": "Group Name:",
						"values": groups
					}
				]
			},
			{
                                "rid": "essentials/remove-from-group",
                                "name": "Remove from Group",
                                "inputs": [
                                        {
                                                "type": "select",
                                                "name": "groupname",
                                                "label": "Group Name:",
                                                "values": groups
                                        }
                                ]
                        },

			{
				"rid": "essentials/alert-user",
				"name": "Send alert message",
				"inputs": [
					{
						"type": "text",
						"name": "title",
						"label": "Title:"
					},
					{
						"type": "text",
						"name": "message",
						"label": "Message:"
					}
				]
			},
			{
				"rid": "essentials/award-reputation",
				"name": "Award Reputation",
				"inputs": [
					{
						"type": "text",
						"name": "reputation",
						"label": "Amount of reputation:"
					}
				]
			}
		]);

		callback(false, rewards);
	});
};

rewards.addToGroup = function(data) {
	groups.join(data.reward.groupname, data.uid);
};

rewards.removeFromGroup = function(data) {
	groups.leave(data.reward.groupname, data.uid);
};

rewards.alertUser = function(data) {
	var websockets = require.main.require('./src/socket.io');
	websockets.in('uid_' + data.uid).emit('event:alert', data.reward);
};

rewards.awardReputation = function(data) {
	user.incrementUserFieldBy(data.uid, 'reputation', data.reward.reputation, function(err, newreputation) {
		db.sortedSetAdd('users:reputation', newreputation, data.uid);
	});
};

function getGroupList(callback) {
	var list = [];

	groups.getGroups('groups:createtime', 0, -1, function(err, groups) {
		groups.forEach(function(group) {
			var name = group;
			if ((name = group.match(/cid:([0-9]*):privileges:groups:([\s\S]*)/)) !== null) {
				name = 'Category ' + name[1] + ' group with privilege ' + name[2];
			}

			list.push({
				name: name ? name : group,
				value: group
			});
		});

		callback(err, list);
	});
}

module.exports = rewards;
<|endoftext|>


<commit_before>import reduce from 'lodash/reduce';
import uniq from 'lodash/uniq';
import each from 'lodash/each';
import isString from 'lodash/isString';
import isNumber from 'lodash/isNumber';
import URIjs from 'urijs';
import { assertTrimmedNonEmptyString, assertRegExp, assertAvailableProps, assertPlainObject } from './assert';

const routesByName = {};
let routesNamesInSearchingOrder = [];

export const getRoutesByName = () => routesByName;

// const reroute = (to, from) => ({ name: to.name, prams: to.params });

const createTreeOfRoutes = (name, { url = '', params = {}, slots = {}, reroute = null }, parent = null) => {
  // pre checking
  assertTrimmedNonEmptyString('name', name);
  assertRegExp(/^([a-zA-Z0-9-.]+)$/, 'name', name);

  const sections = name.split('.');

  if (parent) {
    if (!name.startsWith(parent.name)) {
      throw new Error(`child state name (${name}) must starts from parent name "${parent.name}"`);
    }

    if (`${parent.name}.${sections[sections.length - 1]}` !== name) {
      throw new Error(`state "${name}" has invalid count of real parents in name`);
    }
  } else {
    if (sections.length !== 1) {
      throw new Error(`state "${name}" has invalid format`);
    }
  }

  // create route
  const route = {
    url,
    name,
    path: url.replace(/[?#].*$/, ''),
    slots,
    params,
    reroute,
    searchParams: url.replace(/^[^?]*[?]?/, '').split('&').filter(Boolean),
    pathMaskParams: []
  };

  if (parent) {
    route.slots = { ...parent.slots, ...route.slots };
    route.params = { ...parent.params, ...route.params };
    route.searchParams = [ ...parent.searchParams, ...route.searchParams ];
    route.path = `${parent.path.replace(/\/$/, '')}/${route.path.replace(/^\//, '')}`;
    route.url = `${route.path}${route.searchParams.length ? `?${route.searchParams.join('&')}` : ''}`;
  }

  route.pathMaskParams = [];
  route.pathMask = route.path.replace(/:([^/]+)/g, ($0, paramName) => {
    route.pathMaskParams.push(paramName);

    return `{{${paramName}}}`;
  });

  route.pathMaskExpSrc = route.path.replace(/:([^/]+)/g, () => '([^/]+)');

  route.pathMaskExp = new RegExp(`^${route.pathMaskExpSrc}$`);

  route.availableUrlParams = route.searchParams.concat(route.pathMaskParams);
  route.additionalParams = Object.keys(route.params)
    .filter((param) => !route.pathMaskParams.includes(param) && !route.searchParams.includes(param));

  route.availableParams = route.availableUrlParams.concat(route.additionalParams);

  // post checking
  if (route.availableUrlParams.length !== uniq(route.availableUrlParams).length) {
    throw new Error(`route "${route.name}" has duplication in params [${route.searchParams.join(',')}] and [${route.pathMaskParams.join(',')}]`);
  }

  const invalidParams = route.additionalParams.filter((param) => !/^[^a-zA-Z]/.test(param));

  if (invalidParams.length) {
    throw new Error(`route "${route.name}" has invalid params [${invalidParams.join(',')}]. additional params must not starts from [a-zA-Z] symbold`);
  }

  const invalidUrlParams = route.availableUrlParams.filter((param) => /^[^a-zA-Z]/.test(param));

  if (invalidUrlParams.length) {
    throw new Error(`route "${route.name}" has invalid url params [${invalidUrlParams.join(',')}]. url params must starts only from [a-z] symbols`);
  }

  each(route.params, (val, key) => {
    if (!route.availableUrlParams.includes(key)) {
      return;
    }

    if (!isString(val) && !isNumber(val)) {
      throw new Error(`route "${route.name}" has invalid param type of "${key}". must be Number or String`);
    }
  });

  return route;
};

export const routeCreator = (parentRoute = null) => ({
  create: (name, definition) => {
    const route = createTreeOfRoutes(name, definition, parentRoute);

    routesByName[name] = route;
    routesNamesInSearchingOrder.push(name);

    routesNamesInSearchingOrder = routesNamesInSearchingOrder.sort((name1, name2) => {
      const segmentsLen1 = name1.split('.').length;
      const segmentsLen2 = name2.split('.').length;

      if (segmentsLen1 > segmentsLen2) {
        return -1;
      }

      return segmentsLen1 < segmentsLen2 ? 1 : 0;
    });

    return routeCreator(route);
  }
});

export const route = routeCreator(null);

const parseSearchString = (string) =>
  URIjs.parseQuery(string);

const calcSearchString = (params) =>
  URIjs.buildQuery(params, true);

export const compileStateHash = (name, params) =>
  `${name}?${calcSearchString(params)}`;

export const searchStateByLocation = (location) => {
  const name = routesNamesInSearchingOrder.find((routeName) => {
    const route = routesByName[routeName];

    return route.pathMaskExp.test(location.pathname);
  });

  if (!name) {
    return null;
  }

  const route = routesByName[name];

  let params = { ...route.params };
  const pathname = String(location.pathname || '');

  pathname.replace(route.pathMaskExp, ($0, ...args) => {
    params = route.pathMaskParams.reduce((params, paramName, index) => {
      params[paramName] = args[index];

      return params;
    }, params);

    return $0;
  });

  const search = String(location.search || '').replace(/^\?/, '');
  const searchParams = search ? parseSearchString(search) : {};

  params = reduce(searchParams, (params, paramValue, paramName) => {
    if (route.searchParams.includes(paramName)) {
      params[paramName] = paramValue;
    }

    return params;
  }, params);

  return {
    name,
    params
  };
};

export const moveTo = (history, location, { replace = false, reload = false } = {}) => {
  if (!location) {
    throw new Error('location is empty');
    return;
  }

  if (reload) {
    window.location.href = history.createHref(location);
    return;
  }

  if (replace) {
    history.replace(location);
  } else {
    history.push(location);
  }
};

const calcNewState = (fromState, toRoute, withNewParams) => {
  const route = toRoute;

  let params = route.availableParams.reduce((params, paramName) => {
    if (withNewParams.hasOwnProperty(paramName)) {
      params[paramName] = withNewParams[paramName];
    } else if (fromState.params.hasOwnProperty(paramName)) {
      params[paramName] = toRoute.params[paramName];
    }

    return params;
  }, { ...route.params });

  if (route.filterParams) {
    params = route.filterParams(toRoute.name, params);
  }

  if (process.env.NODE_ENV !== 'production') {
    assertAvailableProps(route.availableParams, 'route params', params);
  }

  if (route.reroute) {
    const newState = route.reroute({ name: route.name, params }, { name: fromState.name, params: fromState.params });

    if (newState !== undefined) {
      if (routesByName.hasOwnProperty(newState.name)) {
        const newRoute = routesByName[newState.name];

        return {
          route: newRoute,
          params: {
            ...newRoute.params,
            ...(newState.params || {})
          }
        };
      }

      throw new Error('invalid route after rerouting');
    }
  }

  return {
    route,
    params
  };
};

export const calcLocation = (fromState, toRoute, withNewParams) => {
  const { route, params } = calcNewState(fromState, toRoute, withNewParams);

  const pathname = route.pathMask.replace(/{{([^}]+)}}/g, ($0, paramName) => {
    if (params.hasOwnProperty(paramName)) {
      return params[paramName];
    }

    throw new Error(`Route param "${paramName}" was not defined for route "${route.name}"`);
  });

  const searchParams = route.searchParams.reduce((search, searchParam) => {
    if (params.hasOwnProperty(searchParam) && params[searchParam] !== route.params[searchParam]) {
      search[searchParam] = params[searchParam];
    }

    return search;
  }, {});

  const location = { pathname, hash: '', search: '' };

  if (searchParams) {
    location.search = calcSearchString(searchParams);
  }

  return location;
};
<commit_msg>[fix] fromState params bug<commit_after>import reduce from 'lodash/reduce';
import uniq from 'lodash/uniq';
import each from 'lodash/each';
import isString from 'lodash/isString';
import isNumber from 'lodash/isNumber';
import URIjs from 'urijs';
import { assertTrimmedNonEmptyString, assertRegExp, assertAvailableProps, assertPlainObject } from './assert';

const routesByName = {};
let routesNamesInSearchingOrder = [];

export const getRoutesByName = () => routesByName;

// const reroute = (to, from) => ({ name: to.name, prams: to.params });

const createTreeOfRoutes = (name, { url = '', params = {}, slots = {}, reroute = null }, parent = null) => {
  // pre checking
  assertTrimmedNonEmptyString('name', name);
  assertRegExp(/^([a-zA-Z0-9-.]+)$/, 'name', name);

  const sections = name.split('.');

  if (parent) {
    if (!name.startsWith(parent.name)) {
      throw new Error(`child state name (${name}) must starts from parent name "${parent.name}"`);
    }

    if (`${parent.name}.${sections[sections.length - 1]}` !== name) {
      throw new Error(`state "${name}" has invalid count of real parents in name`);
    }
  } else {
    if (sections.length !== 1) {
      throw new Error(`state "${name}" has invalid format`);
    }
  }

  // create route
  const route = {
    url,
    name,
    path: url.replace(/[?#].*$/, ''),
    slots,
    params,
    reroute,
    searchParams: url.replace(/^[^?]*[?]?/, '').split('&').filter(Boolean),
    pathMaskParams: []
  };

  if (parent) {
    route.slots = { ...parent.slots, ...route.slots };
    route.params = { ...parent.params, ...route.params };
    route.searchParams = [ ...parent.searchParams, ...route.searchParams ];
    route.path = `${parent.path.replace(/\/$/, '')}/${route.path.replace(/^\//, '')}`;
    route.url = `${route.path}${route.searchParams.length ? `?${route.searchParams.join('&')}` : ''}`;
  }

  route.pathMaskParams = [];
  route.pathMask = route.path.replace(/:([^/]+)/g, ($0, paramName) => {
    route.pathMaskParams.push(paramName);

    return `{{${paramName}}}`;
  });

  route.pathMaskExpSrc = route.path.replace(/:([^/]+)/g, () => '([^/]+)');

  route.pathMaskExp = new RegExp(`^${route.pathMaskExpSrc}$`);

  route.availableUrlParams = route.searchParams.concat(route.pathMaskParams);
  route.additionalParams = Object.keys(route.params)
    .filter((param) => !route.pathMaskParams.includes(param) && !route.searchParams.includes(param));

  route.availableParams = route.availableUrlParams.concat(route.additionalParams);

  // post checking
  if (route.availableUrlParams.length !== uniq(route.availableUrlParams).length) {
    throw new Error(`route "${route.name}" has duplication in params [${route.searchParams.join(',')}] and [${route.pathMaskParams.join(',')}]`);
  }

  const invalidParams = route.additionalParams.filter((param) => !/^[^a-zA-Z]/.test(param));

  if (invalidParams.length) {
    throw new Error(`route "${route.name}" has invalid params [${invalidParams.join(',')}]. additional params must not starts from [a-zA-Z] symbold`);
  }

  const invalidUrlParams = route.availableUrlParams.filter((param) => /^[^a-zA-Z]/.test(param));

  if (invalidUrlParams.length) {
    throw new Error(`route "${route.name}" has invalid url params [${invalidUrlParams.join(',')}]. url params must starts only from [a-z] symbols`);
  }

  each(route.params, (val, key) => {
    if (!route.availableUrlParams.includes(key)) {
      return;
    }

    if (!isString(val) && !isNumber(val)) {
      throw new Error(`route "${route.name}" has invalid param type of "${key}". must be Number or String`);
    }
  });

  return route;
};

export const routeCreator = (parentRoute = null) => ({
  create: (name, definition) => {
    const route = createTreeOfRoutes(name, definition, parentRoute);

    routesByName[name] = route;
    routesNamesInSearchingOrder.push(name);

    routesNamesInSearchingOrder = routesNamesInSearchingOrder.sort((name1, name2) => {
      const segmentsLen1 = name1.split('.').length;
      const segmentsLen2 = name2.split('.').length;

      if (segmentsLen1 > segmentsLen2) {
        return -1;
      }

      return segmentsLen1 < segmentsLen2 ? 1 : 0;
    });

    return routeCreator(route);
  }
});

export const route = routeCreator(null);

const parseSearchString = (string) =>
  URIjs.parseQuery(string);

const calcSearchString = (params) =>
  URIjs.buildQuery(params, true);

export const compileStateHash = (name, params) =>
  `${name}?${calcSearchString(params)}`;

export const searchStateByLocation = (location) => {
  const name = routesNamesInSearchingOrder.find((routeName) => {
    const route = routesByName[routeName];

    return route.pathMaskExp.test(location.pathname);
  });

  if (!name) {
    return null;
  }

  const route = routesByName[name];

  let params = { ...route.params };
  const pathname = String(location.pathname || '');

  pathname.replace(route.pathMaskExp, ($0, ...args) => {
    params = route.pathMaskParams.reduce((params, paramName, index) => {
      params[paramName] = args[index];

      return params;
    }, params);

    return $0;
  });

  const search = String(location.search || '').replace(/^\?/, '');
  const searchParams = search ? parseSearchString(search) : {};

  params = reduce(searchParams, (params, paramValue, paramName) => {
    if (route.searchParams.includes(paramName)) {
      params[paramName] = paramValue;
    }

    return params;
  }, params);

  return {
    name,
    params
  };
};

export const moveTo = (history, location, { replace = false, reload = false } = {}) => {
  if (!location) {
    throw new Error('location is empty');
    return;
  }

  if (reload) {
    window.location.href = history.createHref(location);
    return;
  }

  if (replace) {
    history.replace(location);
  } else {
    history.push(location);
  }
};

const calcNewState = (fromState, toRoute, withNewParams) => {
  const route = toRoute;

  let params = route.availableParams.reduce((params, paramName) => {
    if (withNewParams.hasOwnProperty(paramName)) {
      params[paramName] = withNewParams[paramName];
    } else if (fromState.params.hasOwnProperty(paramName)) {
      params[paramName] = fromState.params[paramName];
    }

    return params;
  }, { ...route.params });

  if (route.filterParams) {
    params = route.filterParams(toRoute.name, params);
  }

  if (process.env.NODE_ENV !== 'production') {
    assertAvailableProps(route.availableParams, 'route params', params);
  }

  if (route.reroute) {
    const newState = route.reroute({ name: route.name, params }, { name: fromState.name, params: fromState.params });

    if (newState !== undefined) {
      if (routesByName.hasOwnProperty(newState.name)) {
        const newRoute = routesByName[newState.name];

        return {
          route: newRoute,
          params: {
            ...newRoute.params,
            ...(newState.params || {})
          }
        };
      }

      throw new Error('invalid route after rerouting');
    }
  }

  return {
    route,
    params
  };
};

export const calcLocation = (fromState, toRoute, withNewParams) => {
  const { route, params } = calcNewState(fromState, toRoute, withNewParams);

  const pathname = route.pathMask.replace(/{{([^}]+)}}/g, ($0, paramName) => {
    if (params.hasOwnProperty(paramName)) {
      return params[paramName];
    }

    throw new Error(`Route param "${paramName}" was not defined for route "${route.name}"`);
  });

  const searchParams = route.searchParams.reduce((search, searchParam) => {
    if (params.hasOwnProperty(searchParam) && params[searchParam] !== route.params[searchParam]) {
      search[searchParam] = params[searchParam];
    }

    return search;
  }, {});

  const location = { pathname, hash: '', search: '' };

  if (searchParams) {
    location.search = calcSearchString(searchParams);
  }

  return location;
};
<|endoftext|>