<commit_before>var util = require("geoscript/util");
util.createRegistry(exports);

var Feature = require("geoscript/feature").Feature;
var Schema = require("geoscript/feature").Schema;
var util = require("geoscript/util");
var Cursor = require("geoscript/cursor").Cursor;
var workspace = require("geoscript/workspace");
var proj = require("geoscript/proj");

var geotools = Packages.org.geotools;
var DefaultQuery = geotools.data.DefaultQuery;
var Query = geotools.data.Query;
var Transaction = geotools.data.Transaction;
var FeatureCollections = geotools.feature.FeatureCollections;
var CQL = geotools.filter.text.cql2.CQL;
var Filter = Packages.org.opengis.filter.Filter

var getTempName = function() {
    var count = workspace.memory.names.length;
    var name = "layer_" + count;
    while (workspace.memory.names.indexOf(name) > -1) {
        ++count;
        name = "layer_" + count;
    }
    return name;
};

/** api: (define)
 *  module = layer
 *  class = Layer
 */
var Layer = util.extend(Object, {

    /** private: property[cache]
     *  ``Object``
     */
    cache: null,

    /** api: constructor
     *  .. class:: Layer
     *
     *  Create a new layer.  If a workspace is not provided, a temporary layer
     *  will be created.
     */
    constructor: function Layer(config) {
        this.cache = {};
        var name;
        if (config) {
            if (config.workspace) {
                if (config.workspace instanceof workspace.Workspace) {
                    this.workspace = config.workspace;
                } else {
                    this.workspace = workspace.create(config.workspace);
                }
                name = config.name;
            } else {
                this.workspace = workspace.memory;
                var schema = config.schema;
                if (!schema) {
                    schema = new Schema({
                        name: config.name || getTempName(),
                        fields: config.fields || [{name: "geom", type: "Geometry"}]
                    });
                }
                this.workspace._store.createSchema(schema._schema);
                name = schema.name;
            }
            if (!name) {
                throw "Layer configuration must include a name or a named schema.";
            }
            this._source = this.workspace._store.getFeatureSource(name);
            var projection = config.projection;
            if (projection) {
                if (projection instanceof proj.Projection) {
                    projection = new proj.Projection(projection);
                }
                this.projection = projection;
            }
        }
    },

    /** api: method[clone]
     *  :arg name: ``String`` New layer name.  If not provided, one will be
     *      generated.
     *  :returns: :class:`layer.Layer` The layer clone.
     *
     *  Create a temporary copy of this layer.
     */
    clone: function(name) {
        name = name || getTempName();
        if (workspace.memory.names.indexOf(name) > -1) {
            throw "Layer named '" + name + "' already exists.";
        }
        var schema = this.schema.clone(name);
        var layer = new Layer({schema: schema});
        this.features().forEach(layer.add, layer);
        return layer;
    },

    /** api: property[schema]
     *  :class:`feature.Schema`
     *  The schema for this layer.
     */
    get schema() {
        if (!this.cache.schema) {
            this.cache.schema = Schema.from_(this._source.getSchema());
        }
        return this.cache.schema;
    },

    /** api: property[projection]
     *  :class:`proj.Projection`
     *  Optional projection for the layer.  If set, any features added to the
     *  layer will be tranformed to this projection if they are in a different
     *  projection.  This must be set before features are added to the layer.
     */
    get projection() {
        var projection = this.cache.projection;
        if (!projection && this.schema) {
            var field = this.schema.geometry;
            if (field) {
                projection = field.projection;
                this.cache.projection = projection;
            }
        }
        return projection;
    },
    set projection(projection) {
        projection = new proj.Projection(projection);
        if (this.projection && !projection.equals(this.projection)) {
            throw "Layer projection already set: " + this.projection.id;
        }
        this.cache.projection = projection;
    },

    /** api: property[temporary]
     *  ``Boolean``
     *  The layer has not been persisted to a workspace.
     */
    get temporary() {
        return (this.workspace instanceof workspace.Memory);
    },

    /** api: property[name]
     *  ``String``
     *  The layer name.
     */
    get name() {
        return String(this._source.getName().getLocalPart());
    },

    /** api: property[count]
     *  ``Number``
     *  The number of features contained in the layer.
     */
    get count() {
        return this._source.getCount(Query.ALL);
    },

    /** private: property[bounds]
     *  ``geotools``
     *  TODO: Provide a geoscript wrapper for this.
     */
    get bounds() {
        return this._source.bounds;
    },

    /** api: method[features]
     *  :arg options: ``Object``
     *  :returns: ``Object`` A generator-like object for accessing features.
     *
     *  Valid options:
     *
     *  * filter - ``String`` Filter for the feature query specified in CQL.
     *
     *  Query for features from the layer.  The return will be an object with
     *  ``forEach``, ``hasNext``, and ``next`` methods.
     *
     *  Example use:
     *
     *  .. code-block:: javascript
     *
     *      layer.features().forEach(function(feature) {
     *          print(feature.toString());
     *      });
     */
    features: function(options) {
        options = options || {};
        var filter;
        if (options.filter) {
            filter = CQL.toFilter(options.filter);
        } else {
            filter = Filter.INCLUDE;
        }
        var query = new DefaultQuery(this.name, filter);
        var results = this._source.dataStore.getFeatureReader(query, Transaction.AUTO_COMMIT);
        var _schema = this.schema._schema;

        var cursor = new Cursor(results, function(_feature) {
            return Feature.from_(_feature, _schema);
        });

        return cursor;
    },

    /** api: method[add]
     *  :arg obj: ``Object`` A :class:`feature.Feature` or a feature attribute
     *      values object.
     *
     *  Add a feature to a layer.  Optionally, an object with feature attribute
     *  values may be provided.
     */
    add: function(obj) {
        var feature;
        if (obj instanceof Feature) {
            feature = obj;
        } else {
            // has to be a values object
            feature = new Feature({schema: this.schema, values: obj});
        }
        if (this.projection) {
            if (feature.projection) {
                if (!this.projection.equals(feature.projection)) {
                    feature.geometry = proj.transform(
                        feature.geometry,
                        feature.projection,
                        this.projection
                    );
                }
            } else {
                feature.projection = projection;
            }
        }
        this.workspace._onFeatureAdd(feature);
        var collection = FeatureCollections.newCollection();
        collection.add(feature._feature);
        this._source.addFeatures(collection);
    },

    /** private: method[toFullString]
     */
    toFullString: function() {
        return "name: " + this.name + ", count: " + this.count;
    }

});

Layer.from_ = function(_source, work) {
    var layer = new Layer();
    layer._source = _source;
    layer.workspace = work;
    return layer;
}

exports.Layer = Layer;

// register a layer factory for the module
var Factory = require("geoscript/factory").Factory;

exports.register(new Factory(Layer, {
    handles: function(config) {
        return true;
    }
}));
<commit_msg>Properly set feature projection if layer projection is set.<commit_after>var util = require("geoscript/util");
util.createRegistry(exports);

var Feature = require("geoscript/feature").Feature;
var Schema = require("geoscript/feature").Schema;
var util = require("geoscript/util");
var Cursor = require("geoscript/cursor").Cursor;
var workspace = require("geoscript/workspace");
var proj = require("geoscript/proj");

var geotools = Packages.org.geotools;
var DefaultQuery = geotools.data.DefaultQuery;
var Query = geotools.data.Query;
var Transaction = geotools.data.Transaction;
var FeatureCollections = geotools.feature.FeatureCollections;
var CQL = geotools.filter.text.cql2.CQL;
var Filter = Packages.org.opengis.filter.Filter

var getTempName = function() {
    var count = workspace.memory.names.length;
    var name = "layer_" + count;
    while (workspace.memory.names.indexOf(name) > -1) {
        ++count;
        name = "layer_" + count;
    }
    return name;
};

/** api: (define)
 *  module = layer
 *  class = Layer
 */
var Layer = util.extend(Object, {

    /** private: property[cache]
     *  ``Object``
     */
    cache: null,

    /** api: constructor
     *  .. class:: Layer
     *
     *  Create a new layer.  If a workspace is not provided, a temporary layer
     *  will be created.
     */
    constructor: function Layer(config) {
        this.cache = {};
        var name;
        if (config) {
            if (config.workspace) {
                if (config.workspace instanceof workspace.Workspace) {
                    this.workspace = config.workspace;
                } else {
                    this.workspace = workspace.create(config.workspace);
                }
                name = config.name;
            } else {
                this.workspace = workspace.memory;
                var schema = config.schema;
                if (!schema) {
                    schema = new Schema({
                        name: config.name || getTempName(),
                        fields: config.fields || [{name: "geom", type: "Geometry"}]
                    });
                }
                this.workspace._store.createSchema(schema._schema);
                name = schema.name;
            }
            if (!name) {
                throw "Layer configuration must include a name or a named schema.";
            }
            this._source = this.workspace._store.getFeatureSource(name);
            var projection = config.projection;
            if (projection) {
                if (projection instanceof proj.Projection) {
                    projection = new proj.Projection(projection);
                }
                this.projection = projection;
            }
        }
    },

    /** api: method[clone]
     *  :arg name: ``String`` New layer name.  If not provided, one will be
     *      generated.
     *  :returns: :class:`layer.Layer` The layer clone.
     *
     *  Create a temporary copy of this layer.
     */
    clone: function(name) {
        name = name || getTempName();
        if (workspace.memory.names.indexOf(name) > -1) {
            throw "Layer named '" + name + "' already exists.";
        }
        var schema = this.schema.clone(name);
        var layer = new Layer({schema: schema});
        this.features().forEach(layer.add, layer);
        return layer;
    },

    /** api: property[schema]
     *  :class:`feature.Schema`
     *  The schema for this layer.
     */
    get schema() {
        if (!this.cache.schema) {
            this.cache.schema = Schema.from_(this._source.getSchema());
        }
        return this.cache.schema;
    },

    /** api: property[projection]
     *  :class:`proj.Projection`
     *  Optional projection for the layer.  If set, any features added to the
     *  layer will be tranformed to this projection if they are in a different
     *  projection.  This must be set before features are added to the layer.
     */
    get projection() {
        var projection = this.cache.projection;
        if (!projection && this.schema) {
            var field = this.schema.geometry;
            if (field) {
                projection = field.projection;
                this.cache.projection = projection;
            }
        }
        return projection;
    },
    set projection(projection) {
        projection = new proj.Projection(projection);
        if (this.projection && !projection.equals(this.projection)) {
            throw "Layer projection already set: " + this.projection.id;
        }
        this.cache.projection = projection;
    },

    /** api: property[temporary]
     *  ``Boolean``
     *  The layer has not been persisted to a workspace.
     */
    get temporary() {
        return (this.workspace instanceof workspace.Memory);
    },

    /** api: property[name]
     *  ``String``
     *  The layer name.
     */
    get name() {
        return String(this._source.getName().getLocalPart());
    },

    /** api: property[count]
     *  ``Number``
     *  The number of features contained in the layer.
     */
    get count() {
        return this._source.getCount(Query.ALL);
    },

    /** private: property[bounds]
     *  ``geotools``
     *  TODO: Provide a geoscript wrapper for this.
     */
    get bounds() {
        return this._source.bounds;
    },

    /** api: method[features]
     *  :arg options: ``Object``
     *  :returns: ``Object`` A generator-like object for accessing features.
     *
     *  Valid options:
     *
     *  * filter - ``String`` Filter for the feature query specified in CQL.
     *
     *  Query for features from the layer.  The return will be an object with
     *  ``forEach``, ``hasNext``, and ``next`` methods.
     *
     *  Example use:
     *
     *  .. code-block:: javascript
     *
     *      layer.features().forEach(function(feature) {
     *          print(feature.toString());
     *      });
     */
    features: function(options) {
        options = options || {};
        var filter;
        if (options.filter) {
            filter = CQL.toFilter(options.filter);
        } else {
            filter = Filter.INCLUDE;
        }
        var query = new DefaultQuery(this.name, filter);
        var results = this._source.dataStore.getFeatureReader(query, Transaction.AUTO_COMMIT);
        var _schema = this.schema._schema;

        var cursor = new Cursor(results, function(_feature) {
            return Feature.from_(_feature, _schema);
        });

        return cursor;
    },

    /** api: method[add]
     *  :arg obj: ``Object`` A :class:`feature.Feature` or a feature attribute
     *      values object.
     *
     *  Add a feature to a layer.  Optionally, an object with feature attribute
     *  values may be provided.
     */
    add: function(obj) {
        var feature;
        if (obj instanceof Feature) {
            feature = obj;
        } else {
            // has to be a values object
            feature = new Feature({schema: this.schema, values: obj});
        }
        if (this.projection) {
            if (feature.projection) {
                if (!this.projection.equals(feature.projection)) {
                    feature.geometry = proj.transform(
                        feature.geometry,
                        feature.projection,
                        this.projection
                    );
                }
            } else {
                feature.projection = this.projection;
            }
        }
        this.workspace._onFeatureAdd(feature);
        var collection = FeatureCollections.newCollection();
        collection.add(feature._feature);
        this._source.addFeatures(collection);
    },

    /** private: method[toFullString]
     */
    toFullString: function() {
        return "name: " + this.name + ", count: " + this.count;
    }

});

Layer.from_ = function(_source, work) {
    var layer = new Layer();
    layer._source = _source;
    layer.workspace = work;
    return layer;
}

exports.Layer = Layer;

// register a layer factory for the module
var Factory = require("geoscript/factory").Factory;

exports.register(new Factory(Layer, {
    handles: function(config) {
        return true;
    }
}));
<|endoftext|>


<commit_before>var _ = require('lodash');
var dd = require('react-dd');
var dateFormat = require('dateformat');
var wrapPreventDefault = require("./wrapPreventDefault");

var icon_prefix = 'react-loose-forms-bs3-date-icon';
var icon_classes = {
  angle_up: icon_prefix + ' ' + icon_prefix + '-angle-up',
  angle_down: icon_prefix + ' ' + icon_prefix + '-angle-down'
};

module.exports = dd.createClass({
  __increment: function(field, inc){
    var self = this;
    return wrapPreventDefault(function(){
      var onTimeChanged = self.props.onTimeChanged;
      var d = _.isDate(self.props.value) ? _.cloneDeep(self.props.value) : new Date(0, -1, 0, 0, 0, 0, 0);

      //save these so we ensure adding a bunch of hours doesn't change the day
      var year = d.getFullYear();
      var month = d.getMonth();
      var day = d.getDate();
      if(field === 'hour'){
        d.setHours(d.getHours() + inc);
      }else if(field === 'min'){
        d.setMinutes(d.getMinutes() + inc);
      }
      d.setFullYear(year);
      d.setMonth(month);
      d.setDate(day);

      onTimeChanged(d.getHours(), d.getMinutes());
    });
  },
  __onTypeHour: function(e){
  },
  __onTypeMinutes: function(e){
  },
  __onTypeAMPM: function(e){
  },
  render: function(){
    var self = this;
    var value = _.isDate(this.props.value) ? this.props.value : null;

    var hours = value ? dateFormat(value, 'h') : '';
    var minutes = value ? dateFormat(value, 'MM') : '';
    var ampm = value ? dateFormat(value, 'TT') : '';

    var incBtn = function(field, inc){
      var onClick = self.__increment(field, inc);
      return dd.button({className: 'btn btn-default', onClick: onClick},
        dd.i({
          className: inc > 0 ? icon_classes.angle_up : icon_classes.angle_down
        })
      );
    };

    return dd.div({className: 'TimePicker'},
      dd.table(null,
        dd.tbody(null,
          dd.tr(null,
            dd.td(null, incBtn('hour', 1)),
            dd.td(),
            dd.td(null, incBtn('min', 5)),
            dd.td(),
            dd.td(null, incBtn('hour', 12))
          ),
          dd.tr(null,
            dd.td(null, dd.input({type: 'text', className: 'form-control input-sm', placeholder: 'HH', maxLength: 2, value: hours, onChange: this.__onTypeHour, disabled: 'disabled'})),
            dd.td(null, ' : '),
            dd.td(null, dd.input({type: 'text', className: 'form-control input-sm', placeholder: 'MM', maxLength: 2, value: minutes, onChange: this.__onTypeMinutes, disabled: 'disabled'})),
            dd.td(null, ' : '),
            dd.td(null, dd.input({type: 'text', className: 'form-control input-sm', placeholder: 'AM/PM', maxLength: 2, value: ampm, onChange: this.__onTypeAMPM, disabled: 'disabled'}))
          ),
          dd.tr(null,
            dd.td(null, incBtn('hour', -1)),
            dd.td(),
            dd.td(null, incBtn('min', -5)),
            dd.td(),
            dd.td(null, incBtn('hour', -12))
          )
        )
      )
    );
  }
});
<commit_msg>timepicker type in<commit_after>var _ = require('lodash');
var dd = require('react-dd');
var dateFormat = require('dateformat');
var wrapPreventDefault = require("./wrapPreventDefault");

var icon_prefix = 'react-loose-forms-bs3-date-icon';
var icon_classes = {
  angle_up: icon_prefix + ' ' + icon_prefix + '-angle-up',
  angle_down: icon_prefix + ' ' + icon_prefix + '-angle-down'
};

var TypeIn = dd.createClass({
  getInitialState: function(){
    return {text_value: this.props.value};
  },
  componentWillReceiveProps: function(next_props){
    if(this.props.value !== next_props.value){
      this.setState({text_value: next_props.value});
    }
  },
  __onChange: function(e){
    this.setState({text_value: e.target.value});
  },
  __onBlur: function(){
    this.props.onValue(this.state.text_value);
  },
  __onKeyUp: function(e){
    if(e.keyCode == 13){//enter key
      e.preventDefault();
      this.props.onValue(this.state.text_value);
    }
  },
  render: function(){
    return dd.input({
      type: 'text',
      className: 'form-control input-sm',
      placeholder: this.props.placeholder,
      maxLength: 2,
      value: this.state.text_value,
      onBlur: this.__onBlur,
      onKeyUp: this.__onKeyUp,
      onChange: this.__onChange
    });
  }
});

module.exports = dd.createClass({
  __changeTime: function(doChange){
    var onTimeChanged = this.props.onTimeChanged;
    var d = _.isDate(this.props.value)
      ? _.cloneDeep(this.props.value)
      : new Date(0, -1, 0, 0, 0, 0, 0);

    //save these so we ensure adding a bunch of hours doesn't change the day
    var year = d.getFullYear();
    var month = d.getMonth();
    var day = d.getDate();

    var changes = doChange(d.getHours(), d.getMinutes());
    if(_.isNumber(changes.hour) && !_.isNaN(changes.hour)){
      d.setHours(changes.hour);
    }
    if(_.isNumber(changes.minute) && !_.isNaN(changes.minute)){
      d.setMinutes(changes.minute);
    }
    d.setFullYear(year);
    d.setMonth(month);
    d.setDate(day);

    onTimeChanged(d.getHours(), d.getMinutes());
  },
  __increment: function(field, inc){
    var self = this;
    return wrapPreventDefault(function(){
      self.__changeTime(function(hour, minute){
        if(field === 'hour'){
          return {hour: hour + inc};
        }else if(field === 'min'){
          return {minute: minute + inc};
        }
      });
    });
  },
  __onTypeHour: function(str){
    var new_hour = _.parseInt(str.replace(/[^[0-9]]/g, ""), 10) || 0;
    this.__changeTime(function(){
      return {hour: new_hour};
    });
  },
  __onTypeMinutes: function(str){
    var new_minute = _.parseInt(str.replace(/[^[0-9]]/g, ""), 10) || 0;
    this.__changeTime(function(){
      return {minute: new_minute};
    });
  },
  __onTypeAMPM: function(ampm){
    this.__changeTime(function(hour){
      var inc = 0;
      if(/am/i.test(ampm)){
        inc += hour < 12 ? 0 : 12;
      }else if(/pm/i.test(ampm)){
        inc += hour < 12 ? 12 : 0;
      }
      return {hour: hour + inc};
    });
  },
  render: function(){
    var self = this;
    var value = _.isDate(this.props.value) ? this.props.value : null;

    var hours = value ? dateFormat(value, 'h') : '';
    var minutes = value ? dateFormat(value, 'MM') : '';
    var ampm = value ? dateFormat(value, 'TT') : '';

    var incBtn = function(field, inc){
      var onClick = self.__increment(field, inc);
      return dd.button({className: 'btn btn-default', onClick: onClick},
        dd.i({
          className: inc > 0 ? icon_classes.angle_up : icon_classes.angle_down
        })
      );
    };

    return dd.div({className: 'TimePicker'},
      dd.table(null,
        dd.tbody(null,
          dd.tr(null,
            dd.td(null, incBtn('hour', 1)),
            dd.td(),
            dd.td(null, incBtn('min', 5)),
            dd.td(),
            dd.td(null, incBtn('hour', 12))
          ),
          dd.tr(null,
            dd.td(null, TypeIn({
              placeholder: 'HH',
              value: hours,
              onValue: this.__onTypeHour
            })),
            dd.td(null, ' : '),
            dd.td(null, TypeIn({
              placeholder: 'MM',
              value: minutes,
              onValue: this.__onTypeMinutes
            })),
            dd.td(null, ' : '),
            dd.td(null, TypeIn({
              placeholder: 'AM/PM',
              value: ampm,
              onValue: this.__onTypeAMPM
            }))
          ),
          dd.tr(null,
            dd.td(null, incBtn('hour', -1)),
            dd.td(),
            dd.td(null, incBtn('min', -5)),
            dd.td(),
            dd.td(null, incBtn('hour', -12))
          )
        )
      )
    );
  }
});
<|endoftext|>


<commit_before>require('fileapi');

var backbone = require('backbone');
var backboneBase = require('backbone-base');
var csv = require('csv');
var getUri = require('get-uri');
var Goodtables = require('goodtables');
var highlight = require('highlight-redux');
var jsonEditor = require('json-editor');
var jtsInfer = require('json-table-schema').infer;
var registry = require('./registry');
var request = require('superagent-bluebird-promise');
var UploadView = require('./upload');
var _ = require('underscore');
var $ = require('jquery');
var validator = require('validator');

// Convert name into title
function titleize(name) {
  return name
    .replace(/[\-\._]+/g, ' ')
    .replace(/([a-z]{1})([A-Z]{1})/g, '$1 $2')
    .replace(/\s+/g, ' ')
    .toLowerCase();
}

// Upload data file and populate .resource array with item
DataUploadView = backbone.BaseView.extend({
  events: {
    // Set up and append .resources row
    'change [data-id=input]': function(E) {
      FileAPI.readAsText(FileAPI.getFiles(E.currentTarget)[0], (function (EV) {
        if(EV.type === 'load') {
          csv.parse(EV.result, (function(E, D) {
            var
              schema,
              editor = this.options.form.getEditor('root.resources');

            if(E)
              throw E;

            schema = jtsInfer(D[0], _.rest(D));

            // Delete last row if empty
            if(_.chain(editor.getValue()).last().flatten().compact().isEmpty().value())
              editor.delete_last_row_button.click();

            editor.addRow({
              name: _.last(EV.target.name.split('/')).toLowerCase().replace(/\.[^.]+$|[^a-z^\-^\d^_^\.]+/g, ''),
              path: EV.target.name,
              schema: schema
            }, true);

            // Save data source in the form
            _.last(editor.rows).dataSource = {schema: schema, data: EV.result};
          }).bind(this));
        } else if( EV.type ==='progress' ) {
          this.setProgress(EV.loaded/EV.total * 100);
        } else {
          this.setError('File upload failed');
        }

        this.$(E.currentTarget).val('');
      }).bind(this));
    },

    'click [data-id=upload-data-file]': function() { this.$('[data-id=input]').trigger('click'); }
  },

  render: function() {
    this.$el
      .append(
        $(this.options.form.theme.getButton('Upload data file', '', 'Upload data file'))
          .attr('data-id', 'upload-data-file')
      )

      .append('<input data-id="input" type="file" accept="text/csv" style="display: none;">');

    return this;
  },

  setError: function() { return this; },
  setProgress: function() { return this; }
});

module.exports = {
  DescriptorEditView: backbone.BaseView.extend({
    activate: function(state) {
      backbone.BaseView.prototype.activate.call(this, state);
      this.layout.upload.activate(state);
      return this;
    },

    events: {
      // Populate main title and resource title fields
      'keyup [data-schemapath].container-name input': function(event) {
        var $input = $(event.currentTarget);
        var $title = $input.closest('[data-schematype=object]').find('.row .container-title input').eq(0);

        // Do not populate user changed field
        if(_.result($title[0], 'edited'))
          return true;

        $title.val(titleize($input.val()));
      },

      // Do not populate title field with name field data if title was edited
      // by user. Consider it is not edited once user empties it.
      'keyup [data-schemapath].container-title input': function(event) {
        var $input = $(event.currentTarget);

        event.currentTarget.edited = Boolean($input.val());

        // If user empties the title field then populate it with name field value
        if(!event.currentTarget.edited)
          $input.closest('[data-schematype=object]').find('.row .container-name input').trigger('keyup');
      },

      'click #validate-resources': function() {
        var goodTables = new Goodtables({method: 'post', report_type: 'grouped'});

        // Navigate to valifation results just once during series of API calls
        var navigateToResults = _.once(function(id) { window.ROUTER.navigate('/validation-results/' + id, {trigger: true}); });

        window.APP.layout.validationResultList.reset(new backbone.Collection());

        _.each(this.layout.form.getEditor('root.resources').rows, function(R) {
          // Conditional promises
          (function() {
            if(R.dataSource)
              return goodTables.run(R.dataSource.data, JSON.stringify(R.dataSource.schema));

            // If data source stored as URL in a row then first grab it and then return goodtables promise
            if(validator.isURL(R.value.url) && _.contains([R.mediatype, R.format], 'text/csv'))
              return request.get(R.value.url).then(function(RES) {
                // Need schema
                return (new Promise(function(RS, RJ) {
                  csv.parse(RES.text, function(E, D) {
                    if(E) {
                      RJ(E);
                      return false;
                    }

                    RS({data: RES.text, schema: jtsInfer(D[0], _.rest(D))});
                  });
                })).then(function(CSV) { return goodTables.run(CSV.data, JSON.stringify(CSV.schema)); });
              });

            return new Promise(function(RS, RJ) { RS(false); });
          })()

            .then(function(M) {
              if(!M)
                return false;

              // Validation completed
              window.APP.layout.validationResultList.collection

                // Grouped report has complicated structure
                .add(M.getGroupedByRows().map(function(SR) { return _.extend(_.values(SR)[0], {
                  headers: M.getHeaders(),
                  resource_id: R.key
                }); }));

              // Navigate between resources in validation results
              window.APP.layout.validationResultList.layout.tabs.add(new backbone.Model({
                title: R.getValue().path,

                // .key is a unique property among all resources rows
                url: '/validation-results/' + R.key
              }));

              navigateToResults(R.key);
            });
        });
      }
    },

    initialize: function(options) {
      highlight.configure({useBR: true});

      // Customize theme
      JSONEditor.defaults.iconlibs.fontawesome4 = JSONEditor.defaults.iconlibs.fontawesome4.extend({
        mapping: {
          'collapse': 'minus',
          'expand'  : 'plus',
          'delete'  : 'times',
          'edit'    : 'pencil',
          'add'     : 'plus',
          'cancel'  : 'ban',
          'save'    : 'save',
          'moveup'  : 'arrow-up',
          'movedown': 'arrow-down'
        }
      });

      // Mark required fields
      JSONEditor.defaults.editors = _.mapObject(JSONEditor.defaults.editors, function(E, K) {
        return E.extend({
          updateHeaderText: function() {
            if(this.parent && _.indexOf(this.parent.schema.required, this.key) >= 0)
              $(this.label).html(this.getTitle() + ' <label class="required-field">*</label>');
            else
              JSONEditor.AbstractEditor.prototype.updateHeaderText.apply(this, arguments);
          }
        });
      });

      return backbone.BaseView.prototype.initialize.call(this, options);
    },

    render: function() {
      this.layout.upload = new UploadView({el: window.APP.$('#upload-data-package'), parent: this});
      this.layout.registryList = new registry.ListView({el: window.APP.$('#registry-list'), container: '[data-id=list-container]', parent: this});
      return this;
    },

    // Utility method to remove empty values from object recursive
    compactObject: function(data) {
      _.each(data, function(v, k) {
        if(_.isEmpty(v)) {
          delete data[k];
        } else if(_.isArray(v) || _.isObject(v)) {
          v = this.compactObject(v);

          if(_.isArray(v))
            v = _.compact(v);

          if(_.isEmpty(v))
            delete data[k];
          else data[k] = v;
        }
      }, this);

      return data;
    },

    getFilledValues: function() { return this.compactObject(this.layout.form.getValue()); },
    getValue: function () { return this.layout.form.getValue(); },
    hasChanges: function() { return Boolean(this.changed); },

    reset: function(schema) {
      var formData;

      // Clean up previous state
      if(this.layout.form) {
        formData = this.getFilledValues();
        this.layout.form.destroy();
        this.layout.uploadData.undelegateEvents().remove();
      }

      // Proper representation of all form buttons. Avoid changing each newly
      // rendered button by rewriting the .getButton()
      JSONEditor.defaults.themes.bootstrap3.prototype.getButton = function(text, icon, title) {
        var el = document.createElement('button');

        el.type = 'button';
        el.className += 'btn btn-info btn-sm';
        this.setButtonText(el,text,icon,title);
        return el;
      };

      this.layout.form = new JSONEditor(this.$('[data-id=form-container]').get(0), {
        schema: schema,
        theme: 'bootstrap3',
        disable_edit_json: true,
        disable_properties: true,
        iconlib: 'fontawesome4'
      });

      // Remove Top-level collapse button
      this.layout.form.root.toggle_button.remove()

      // Bind local event to form nodes after form is renedered
      this.delegateEvents();

      this.layout.uploadData = (new DataUploadView({
        el: this.layout.form.theme.getHeaderButtonHolder(),
        form: this.layout.form,
        parent: this
      })).render();

      this.layout.form.on('ready', (function() {
        // There is no any good way to bind events to custom button or even add cutsom button
        $(this.layout.form.getEditor('root.resources').container)
          .children('h3').append(this.layout.uploadData.el);

        // Detecting changes
        this.changed = false;

        // After `ready` event fired, editor fire `change` event regarding to the initial changes
        this.layout.form.on('change', _.after(2, (function() {
          var resources = this.layout.form.getEditor('root.resources');
          var resourcesLength = _.result(resources.rows, 'length');

          this.changed = true;
          window.APP.layout.download.reset(this.layout.form.getValue(), schema).activate();
          this.showResult();

          // Expand resources section if there are any resources, collapse if row is empty
          if(resourcesLength && resources.collapsed || !resourcesLength && !resources.collapsed)
            $(resources.toggle_button).trigger('click');

          // Do not allow changing schema field type — disable type selectbox
          this.$('[data-schemapath]:not([data-schematype]) select.form-control').prop('hidden', true);

          // Populate empty title fields with name field value. Rely on DOM events defined
          // in DescriptorEditView.events
          _.each($('[data-schemapath].container-title input', this.layout.form.getEditor('root').container), function(I) {
            I.edited = Boolean($(I).val());
          });

          $('[data-schemapath].container-name input', this.layout.form.getEditor('root').container).trigger('keyup');
        }).bind(this)));

        $('#json-code').prop('hidden', true);

        // Collapse editor and add empty item if it has no value
        _.each(this.$('[data-schemapath^="root."]:has(.json-editor-btn-collapse)'), function(E) {
          var editor = this.layout.form.getEditor($(E).data('schemapath'));
          var isEmpty = _.isEmpty(editor.getValue());

          // Empty array data should have one empty item
          if(_.contains(['resources', 'sources', 'licences'], E.dataset.schemapath.replace('root.', '')))
            $(editor.add_row_button).trigger('click');

          if(isEmpty && !editor.collapsed)
            $(editor.toggle_button).trigger('click');
        }, this);

        // Looks like previous loop is somehow async
        setTimeout((function() {
          $('#json-code').prop('hidden', false);
        }).bind(this), 300);

        // If on the previous form was entered values try to apply it to new form
        if(formData)
          this.layout.form.setValue(_.extend({}, this.layout.form.getValue(formData), formData));

        // Remove collapse button on add new item in collection
        _.each(this.$('[data-schemapath][data-schemapath!=root]:has(.json-editor-btn-add)'), function(E) {
          var
            editor = this.layout.form.getEditor($(E).data('schemapath'));

          $(_.pluck(editor.rows, 'toggle_button')).remove();

          $(editor.add_row_button).click((function() {
            $(_.last(this.rows).toggle_button).remove();
          }).bind(editor));
        }, this);
      }).bind(this));
    },

    showResult: function() {
      $('#json-code').html(highlight.fixMarkup(
        highlight.highlight('json', JSON.stringify(this.layout.form.getValue(), undefined, 2)).value
      ));

      return this;
    }
  })
};
<commit_msg>Store CSV data and parsed schema in row property for data sources passed as URL<commit_after>require('fileapi');

var backbone = require('backbone');
var backboneBase = require('backbone-base');
var csv = require('csv');
var getUri = require('get-uri');
var Goodtables = require('goodtables');
var highlight = require('highlight-redux');
var jsonEditor = require('json-editor');
var jtsInfer = require('json-table-schema').infer;
var registry = require('./registry');
var request = require('superagent-bluebird-promise');
var UploadView = require('./upload');
var _ = require('underscore');
var $ = require('jquery');
var validator = require('validator');

// Convert name into title
function titleize(name) {
  return name
    .replace(/[\-\._]+/g, ' ')
    .replace(/([a-z]{1})([A-Z]{1})/g, '$1 $2')
    .replace(/\s+/g, ' ')
    .toLowerCase();
}

// Upload data file and populate .resource array with item
DataUploadView = backbone.BaseView.extend({
  events: {
    // Set up and append .resources row
    'change [data-id=input]': function(E) {
      FileAPI.readAsText(FileAPI.getFiles(E.currentTarget)[0], (function (EV) {
        if(EV.type === 'load') {
          csv.parse(EV.result, (function(E, D) {
            var
              schema,
              editor = this.options.form.getEditor('root.resources');

            if(E)
              throw E;

            schema = jtsInfer(D[0], _.rest(D));

            // Delete last row if empty
            if(_.chain(editor.getValue()).last().flatten().compact().isEmpty().value())
              editor.delete_last_row_button.click();

            editor.addRow({
              name: _.last(EV.target.name.split('/')).toLowerCase().replace(/\.[^.]+$|[^a-z^\-^\d^_^\.]+/g, ''),
              path: EV.target.name,
              schema: schema
            }, true);

            // Save data source in the form
            _.last(editor.rows).dataSource = {schema: schema, data: EV.result};
          }).bind(this));
        } else if( EV.type ==='progress' ) {
          this.setProgress(EV.loaded/EV.total * 100);
        } else {
          this.setError('File upload failed');
        }

        this.$(E.currentTarget).val('');
      }).bind(this));
    },

    'click [data-id=upload-data-file]': function() { this.$('[data-id=input]').trigger('click'); }
  },

  render: function() {
    this.$el
      .append(
        $(this.options.form.theme.getButton('Upload data file', '', 'Upload data file'))
          .attr('data-id', 'upload-data-file')
      )

      .append('<input data-id="input" type="file" accept="text/csv" style="display: none;">');

    return this;
  },

  setError: function() { return this; },
  setProgress: function() { return this; }
});

module.exports = {
  DescriptorEditView: backbone.BaseView.extend({
    activate: function(state) {
      backbone.BaseView.prototype.activate.call(this, state);
      this.layout.upload.activate(state);
      return this;
    },

    events: {
      // Populate main title and resource title fields
      'keyup [data-schemapath].container-name input': function(event) {
        var $input = $(event.currentTarget);
        var $title = $input.closest('[data-schematype=object]').find('.row .container-title input').eq(0);

        // Do not populate user changed field
        if(_.result($title[0], 'edited'))
          return true;

        $title.val(titleize($input.val()));
      },

      // Do not populate title field with name field data if title was edited
      // by user. Consider it is not edited once user empties it.
      'keyup [data-schemapath].container-title input': function(event) {
        var $input = $(event.currentTarget);

        event.currentTarget.edited = Boolean($input.val());

        // If user empties the title field then populate it with name field value
        if(!event.currentTarget.edited)
          $input.closest('[data-schematype=object]').find('.row .container-name input').trigger('keyup');
      },

      'click #validate-resources': function() {
        var goodTables = new Goodtables({method: 'post', report_type: 'grouped'});

        // Navigate to valifation results just once during series of API calls
        var navigateToResults = _.once(function(id) { window.ROUTER.navigate('/validation-results/' + id, {trigger: true}); });

        window.APP.layout.validationResultList.reset(new backbone.Collection());

        _.each(this.layout.form.getEditor('root.resources').rows, function(R) {
          // Conditional promises
          (function() {
            if(R.dataSource)
              return goodTables.run(R.dataSource.data, JSON.stringify(R.dataSource.schema));

            // If data source stored as URL in a row then first grab it and then return goodtables promise
            if(validator.isURL(R.value.url) && _.contains([R.mediatype, R.format], 'text/csv'))
              return request.get(R.value.url).then(function(RES) {
                // Need schema
                return (new Promise(function(RS, RJ) {
                  csv.parse(RES.text, function(E, D) {
                    if(E) {
                      RJ(E);
                      return false;
                    }

                    RS({data: RES.text, schema: jtsInfer(D[0], _.rest(D))});
                  });
                })).then(function(CSV) { R.dataSource = CSV; return goodTables.run(CSV.data, JSON.stringify(CSV.schema)); });
              });

            return new Promise(function(RS, RJ) { RS(false); });
          })()

            .then(function(M) {
              if(!M)
                return false;

              // Validation completed
              window.APP.layout.validationResultList.collection

                // Grouped report has complicated structure
                .add(M.getGroupedByRows().map(function(SR) { return _.extend(_.values(SR)[0], {
                  headers: M.getHeaders(),
                  resource_id: R.key
                }); }));

              // Navigate between resources in validation results
              window.APP.layout.validationResultList.layout.tabs.add(new backbone.Model({
                title: R.getValue().path,

                // .key is a unique property among all resources rows
                url: '/validation-results/' + R.key
              }));

              navigateToResults(R.key);
            });
        });
      }
    },

    initialize: function(options) {
      highlight.configure({useBR: true});

      // Customize theme
      JSONEditor.defaults.iconlibs.fontawesome4 = JSONEditor.defaults.iconlibs.fontawesome4.extend({
        mapping: {
          'collapse': 'minus',
          'expand'  : 'plus',
          'delete'  : 'times',
          'edit'    : 'pencil',
          'add'     : 'plus',
          'cancel'  : 'ban',
          'save'    : 'save',
          'moveup'  : 'arrow-up',
          'movedown': 'arrow-down'
        }
      });

      // Mark required fields
      JSONEditor.defaults.editors = _.mapObject(JSONEditor.defaults.editors, function(E, K) {
        return E.extend({
          updateHeaderText: function() {
            if(this.parent && _.indexOf(this.parent.schema.required, this.key) >= 0)
              $(this.label).html(this.getTitle() + ' <label class="required-field">*</label>');
            else
              JSONEditor.AbstractEditor.prototype.updateHeaderText.apply(this, arguments);
          }
        });
      });

      return backbone.BaseView.prototype.initialize.call(this, options);
    },

    render: function() {
      this.layout.upload = new UploadView({el: window.APP.$('#upload-data-package'), parent: this});
      this.layout.registryList = new registry.ListView({el: window.APP.$('#registry-list'), container: '[data-id=list-container]', parent: this});
      return this;
    },

    // Utility method to remove empty values from object recursive
    compactObject: function(data) {
      _.each(data, function(v, k) {
        if(_.isEmpty(v)) {
          delete data[k];
        } else if(_.isArray(v) || _.isObject(v)) {
          v = this.compactObject(v);

          if(_.isArray(v))
            v = _.compact(v);

          if(_.isEmpty(v))
            delete data[k];
          else data[k] = v;
        }
      }, this);

      return data;
    },

    getFilledValues: function() { return this.compactObject(this.layout.form.getValue()); },
    getValue: function () { return this.layout.form.getValue(); },
    hasChanges: function() { return Boolean(this.changed); },

    reset: function(schema) {
      var formData;

      // Clean up previous state
      if(this.layout.form) {
        formData = this.getFilledValues();
        this.layout.form.destroy();
        this.layout.uploadData.undelegateEvents().remove();
      }

      // Proper representation of all form buttons. Avoid changing each newly
      // rendered button by rewriting the .getButton()
      JSONEditor.defaults.themes.bootstrap3.prototype.getButton = function(text, icon, title) {
        var el = document.createElement('button');

        el.type = 'button';
        el.className += 'btn btn-info btn-sm';
        this.setButtonText(el,text,icon,title);
        return el;
      };

      this.layout.form = new JSONEditor(this.$('[data-id=form-container]').get(0), {
        schema: schema,
        theme: 'bootstrap3',
        disable_edit_json: true,
        disable_properties: true,
        iconlib: 'fontawesome4'
      });

      // Remove Top-level collapse button
      this.layout.form.root.toggle_button.remove()

      // Bind local event to form nodes after form is renedered
      this.delegateEvents();

      this.layout.uploadData = (new DataUploadView({
        el: this.layout.form.theme.getHeaderButtonHolder(),
        form: this.layout.form,
        parent: this
      })).render();

      this.layout.form.on('ready', (function() {
        // There is no any good way to bind events to custom button or even add cutsom button
        $(this.layout.form.getEditor('root.resources').container)
          .children('h3').append(this.layout.uploadData.el);

        // Detecting changes
        this.changed = false;

        // After `ready` event fired, editor fire `change` event regarding to the initial changes
        this.layout.form.on('change', _.after(2, (function() {
          var resources = this.layout.form.getEditor('root.resources');
          var resourcesLength = _.result(resources.rows, 'length');

          this.changed = true;
          window.APP.layout.download.reset(this.layout.form.getValue(), schema).activate();
          this.showResult();

          // Expand resources section if there are any resources, collapse if row is empty
          if(resourcesLength && resources.collapsed || !resourcesLength && !resources.collapsed)
            $(resources.toggle_button).trigger('click');

          // Do not allow changing schema field type — disable type selectbox
          this.$('[data-schemapath]:not([data-schematype]) select.form-control').prop('hidden', true);

          // Populate empty title fields with name field value. Rely on DOM events defined
          // in DescriptorEditView.events
          _.each($('[data-schemapath].container-title input', this.layout.form.getEditor('root').container), function(I) {
            I.edited = Boolean($(I).val());
          });

          $('[data-schemapath].container-name input', this.layout.form.getEditor('root').container).trigger('keyup');
        }).bind(this)));

        $('#json-code').prop('hidden', true);

        // Collapse editor and add empty item if it has no value
        _.each(this.$('[data-schemapath^="root."]:has(.json-editor-btn-collapse)'), function(E) {
          var editor = this.layout.form.getEditor($(E).data('schemapath'));
          var isEmpty = _.isEmpty(editor.getValue());

          // Empty array data should have one empty item
          if(_.contains(['resources', 'sources', 'licences'], E.dataset.schemapath.replace('root.', '')))
            $(editor.add_row_button).trigger('click');

          if(isEmpty && !editor.collapsed)
            $(editor.toggle_button).trigger('click');
        }, this);

        // Looks like previous loop is somehow async
        setTimeout((function() {
          $('#json-code').prop('hidden', false);
        }).bind(this), 300);

        // If on the previous form was entered values try to apply it to new form
        if(formData)
          this.layout.form.setValue(_.extend({}, this.layout.form.getValue(formData), formData));

        // Remove collapse button on add new item in collection
        _.each(this.$('[data-schemapath][data-schemapath!=root]:has(.json-editor-btn-add)'), function(E) {
          var
            editor = this.layout.form.getEditor($(E).data('schemapath'));

          $(_.pluck(editor.rows, 'toggle_button')).remove();

          $(editor.add_row_button).click((function() {
            $(_.last(this.rows).toggle_button).remove();
          }).bind(editor));
        }, this);
      }).bind(this));
    },

    showResult: function() {
      $('#json-code').html(highlight.fixMarkup(
        highlight.highlight('json', JSON.stringify(this.layout.form.getValue(), undefined, 2)).value
      ));

      return this;
    }
  })
};
<|endoftext|>


<commit_before>function namealert(name,last)
{
alert("Welcome " + name + " " + last);
}

function goto(url)
{
window.location.assign(url)
}<commit_msg>forgot a semicolon<commit_after>function namealert(name,last)
{
alert("Welcome " + name + " " + last);
}

function goto(url)
{
window.location.assign(url);
}

<|endoftext|>


<commit_before>'use strict'

const html = require('pithy')
const beautify = require('js-beautify').html
const helpers = require('../helpers')
const settings = require('../api').settings

const head = () => {
	const elements = [
		...helpers.staticHeader(),
		html.title(null, 'Rechtliches | '+settings.title),
        ...helpers.opengraph(),
		html.link({rel: 'stylesheet', type: 'text/css', href: 'assets/styles/impressum.css'})
	]
	return html.head(null, elements)
}

const generate = () => {
	let document = '<!doctype html>' + html.html(null, [
		head(),
		html.body(null, [
			html.div('#page', [
				html.div('#header', [html.a({href: "/", title: "Preiskalender"}, [html.h1(null, 'Preiskalender')])]),
				html.h2(null, 'Impressum'),
				html.div({class: 'section'}, [
					html.p(null, [
						html.a({href: "https://juliustens.eu"}, "Julius Tens"),
						', ',
						html.a({href: "mailto:bahnguru@juliustens.eu"}, 'bahnguru@juliustens.eu'),
						', Schlickweg 10, 14129 Berlin.'
					])
				]),
				html.div({class: 'section'}, [
					html.p(null, [
						'Dieses Projekt ist ',
						html.a({href: "https://github.com/juliuste/bahn.guru/blob/master/LICENSE"}, "MIT-lizenziert"),
						'. Der Quellcode ist auf ',
						html.a({href: "https://github.com/juliuste/bahn.guru"}, 'GitHub'),
						' verfügbar.'
					])
				]),
				html.div({class: 'section'}, [
					html.p(null, 'Alle Preisangaben unverbindlich und ohne Gewähr.')
				]),
				html.div({class: 'section'}, [
					html.p(null, 'Durch die Nutzung unserer Website erklären Sie sich mit der Erhebung, Verarbeitung und Nutzung von Daten gemäß der nachfolgenden Beschreibung einverstanden. Es werden Daten wie beispielsweise aufgerufene Seiten bzw. Namen der abgerufenen Datei, Datum und Uhrzeit zu statistischen Zwecken auf dem Server gespeichert. Personenbezogene Daten werden nicht gespeichert. Ohne Ihre Einwilligung erfolgt keine Weitergabe der Daten an Dritte.')
				])
			]),
			html.div('#footer', [
				html.a({id: 'faq', href: '/faq'}, 'FAQ'),
				html.span(null, ' – '),
				html.a({id: 'impressum', href: '/impressum'}, 'Rechtliches')
			])
		])
	])
	return beautify(document)
}

const main = (req, res, next) => {
	res.send(generate())
}

module.exports = main
<commit_msg>update Datenschutzerklärung<commit_after>'use strict'

const html = require('pithy')
const beautify = require('js-beautify').html
const helpers = require('../helpers')
const settings = require('../api').settings

const head = () => {
	const elements = [
		...helpers.staticHeader(),
		html.title(null, 'Rechtliches | '+settings.title),
        ...helpers.opengraph(),
		html.link({rel: 'stylesheet', type: 'text/css', href: 'assets/styles/impressum.css'})
	]
	return html.head(null, elements)
}

const generate = () => {
	let document = '<!doctype html>' + html.html(null, [
		head(),
		html.body(null, [
			html.div('#page', [
				html.div('#header', [html.a({href: "/", title: "Preiskalender"}, [html.h1(null, 'Preiskalender')])]),
				html.h2(null, 'Impressum'),
				html.div({class: 'section'}, [
					html.p(null, [
						html.a({href: "https://juliustens.eu"}, "Julius Tens"),
						', ',
						html.a({href: "mailto:bahnguru@juliustens.eu"}, 'bahnguru@juliustens.eu'),
						', Schlickweg 10, 14129 Berlin.'
					])
				]),
				html.div({class: 'section'}, [
					html.p(null, [
						'Dieses Projekt ist ',
						html.a({href: "https://github.com/juliuste/bahn.guru/blob/master/LICENSE"}, "MIT-lizenziert"),
						'. Der Quellcode ist auf ',
						html.a({href: "https://github.com/juliuste/bahn.guru"}, 'GitHub'),
						' verfügbar.'
					])
				]),
				html.div({class: 'section'}, [
					html.p(null, 'Alle Preisangaben unverbindlich und ohne Gewähr.')
				]),
				html.div({class: 'section'}, [
					html.p(null, 'Durch die Nutzung unserer Website erklären Sie sich mit der Erhebung, Verarbeitung und Nutzung von Daten gemäß der nachfolgenden Beschreibung einverstanden. Es werden Daten wie beispielsweise aufgerufene Seiten bzw. Namen der abgerufenen Datei, Datum und Uhrzeit zu statistischen Zwecken auf dem Server gespeichert. Personenbezogene Daten werden nicht gespeichert. Für Verbindungsanfragen werden Start- und Zielpunkt, sowie gewählte Optionen, anonymisiert an das Verkehrsunternehmen geschickt. Ohne Ihre Einwilligung erfolgt ansonsten keine Weitergabe der Daten an Dritte.')
				])
			]),
			html.div('#footer', [
				html.a({id: 'faq', href: '/faq'}, 'FAQ'),
				html.span(null, ' – '),
				html.a({id: 'impressum', href: '/impressum'}, 'Rechtliches')
			])
		])
	])
	return beautify(document)
}

const main = (req, res, next) => {
	res.send(generate())
}

module.exports = main
<|endoftext|>


<commit_before>var iconv = require('iconv-lite');
var zlib = require('zlib');
var fs = require('fs');
var fse = require('fs-extra');
var MAX_REQ_SIZE = 256 * 1024;
var MAX_RES_SIZE = 512 * 1024;
var LOCALHOST = '127.0.0.1';
var util = require('../util');
var config = require('../config');
var Transform = require('pipestream').Transform;
var EventEmitter = require('events').EventEmitter;

function passThrough(chunk, encoding, callback) {
	callback(null, chunk);
}

function unzipBody(encoding, body, callback) {
	var unzip;
	switch (body && util.toLowerCase(encoding)) {
	    case 'gzip':
	    	unzip = zlib.gunzip.bind(zlib);
	      break;
	    case 'deflate':
	    	unzip = zlib.inflate.bind(zlib);
	      break;
	}

	unzip ? unzip(body, function(err, data) {
		err ? zlib.inflateRaw(body, callback) : callback(null, data);
	}) : callback(null, body);

}

function emitDataEvents(req, res, proxy) {
	var exportsFile = util.getMatcherValue(req.rules.exports);
	var showHttpData = !req.filter.hide && EventEmitter.listenerCount(proxy, 'request');
	if (!exportsFile && !showHttpData) {
		delete req.headers[config.CLIENT_IP_HEAD];
		return;
	}
	var _res = {};
	var reqEmitter = new EventEmitter();
	var request = new Transform();
	var response = new Transform();
	var now = Date.now();
	var reqData = {
			method: util.toUpperCase(req.method) || 'GET',
			httpVersion: req.httpVersion || '1.1',
            ip: util.getClientIp(req) || LOCALHOST,
            isWhistleHttps: req.isWhistleHttps,
            headers: req.headers,
            trailers: req.trailers
		};
	var resData = {};
	var data = request.data = {
			startTime: now,
			url: req.fullUrl,
			req: reqData,
			res: resData,
			rules: req.rules
	};

	delete req.headers[config.CLIENT_IP_HEAD];
	req.once('dest', function() {
		setReqStatus();
		reqEmitter.emit('send', data);
	});
	res.once('src', function(res) {
		_res = res;
		if (data.endTime) {
			return;
		}

		receiveResBody();
		setResStatus();
		reqEmitter.emit('response', data);
	});
	req.once('close', handleError);
	req.once('error', handleError);
	req.append(request);
	res.append(response);

	reqEmitter.data = data;
	proxy.emit('request', reqEmitter);

	var reqBody = false;
	var reqSize = 0;

	if (util.hasRequestBody(req)) {
		reqBody = showHttpData ? null : '';
	}
	request._transform = function(chunk, encoding, callback) {

		if (chunk) {
			if (reqBody || reqBody === null) {
				reqBody = reqBody ? Buffer.concat([reqBody, chunk]) : chunk;
				if (reqBody.length > MAX_REQ_SIZE) {
					reqBody = false;
				}
			}
			reqSize += chunk.length;
		} else {
			data.requestTime = Date.now();
			reqData.size = reqSize;
			reqData.body = util.decodeBuffer(reqBody);
		}

		callback(null, chunk);
	};

	function receiveResBody() {
		var resBody = false;
		var resSize = 0;
		var contentType = util.getContentType(_res.headers);
		if (contentType && contentType != 'IMG' && util.hasBody(_res)) {
			resBody = showHttpData ? null : '';
		}

		response._transform = function(chunk, encoding, callback) {
			if (chunk) {
				if (resBody || resBody === null) {
					resBody = resBody ? Buffer.concat([resBody, chunk]) : chunk;
					if (resBody.length > MAX_RES_SIZE) {
						resBody = false;
					}
				}
				resSize += chunk.length;
				callback(null, chunk);
			} else {
				unzipBody(util.toLowerCase(_res.headers['content-encoding']), resBody,
						function(err, body) {
					resData.body = err ? util.getErrorStack(err) : util.decodeBuffer(body);
					data.endTime = Date.now();
					resData.size = resSize;
					reqEmitter.emit('end', data);
					callback(null, chunk);
					writeExportsFile();
				});
			}
		};
	}

	function handleError(err) {
		if (data.endTime || (data.responseTime && !err)) {//connection: close的时候，还要数据缓存
			return;
		}

		request._transform = passThrough;
		response._transform = passThrough;
		data.endTime = Date.now();
		if (err) {
			data.resError = true;
			resData.body = util.getErrorStack(err);
			util.emitError(reqEmitter, data);
			setResStatus(502);
		} else {
			data.reqError = true;
			reqData.body = 'aborted';
			reqEmitter.emit('abort', data);
			setResStatus('aborted');
		}
		writeExportsFile();
	}

	function setReqStatus(defaultHost) {
		data.dnsTime = (req.dnsTime || 0) + now;
		data.realUrl = req.realUrl;
		resData.ip = req.hostIp || defaultHost;
	}

	function setResStatus(defaultCode) {
		setReqStatus(LOCALHOST);
		resData.statusCode = _res.statusCode || defaultCode || 502;
		resData.statusMessage = _res.statusMessage;
		if (!data.requestTime) {
			data.requestTime = Date.now();
		}
		data.responseTime = Date.now();
		resData.headers = _res.headers;
		resData.trailers = _res.trailers;
	}

	function writeExportsFile() {
		if (!exportsFile) {
			return;
		}
		fse.ensureFile(exportsFile, function(err) {
			if (err) {
				return;
			}

			fs.writeFile(exportsFile, '\r\n' + JSON.stringify({
				startTime: data.startTime,
				dnsTime: data.dnsTime,
				requestTime: data.requestTime,
				responseTime: data.responseTime,
				endTime: data.endTime,
				url: data.url,
				realUrl: data.url == data.realUrl ? undefined : data.realUrl,
				method: reqData.method,
				httpVersion: reqData.httpVersion,
				clientIp: reqData.ip,
				reqError: data.reqError,
				reqSize: reqData.size,
				reqHeaders: reqData.headers,
				reqTrailers: reqData.trailers,
				statusCode: resData.statusCode,
				hostIp: resData.ip,
				resError: data.resError,
				resSize: resData.size,
				resHeaders: resData.headers,
				resTrailers: resData.trailers,
				rules: req.rules
			}), {flag: 'a'}, util.noop);
		});
	}
}

function addTimeout(req, res, timeout) {
	if (!(timeout > 0) || req.disable.timeout) {
		return;
	}
	var timeoutId, responsed;
	var preReq = new Transform();
	var endReq = new Transform();
	var preRes = new Transform();
	var endRes = new Transform();

	preReq._transform = preRes._transform = function(chunk, encoding, callback) {
		timeoutId && clearTimeout(timeoutId);
		timeoutId = null;
		callback(null, chunk);
	};

	endReq._transform = endRes._transform = function(chunk, encoding, callback) {
		timeoutId && clearTimeout(timeoutId);
		if (!responsed || chunk) {
			timeoutId = setTimeout(emitTimeoutError, timeout);
		}

		if (!chunk) {
			responsed = true;
		}

		callback(null, chunk);
	};

	function emitTimeoutError() {
		util.emitError(responsed ? res : req, new Error('timeout'));
	}

	req.prepend(preReq).append(endReq);
	res.prepend(preRes).append(endRes);
}

module.exports = function(req, res, next) {
	emitDataEvents(req, res, this);
	addTimeout(req, res, req.timeout || this.config.timeout);
	next();
};

<commit_msg>feat: Support exports using relative paths<commit_after>var iconv = require('iconv-lite');
var zlib = require('zlib');
var fs = require('fs');
var fse = require('fs-extra');
var path = require('path');
var MAX_REQ_SIZE = 256 * 1024;
var MAX_RES_SIZE = 512 * 1024;
var LOCALHOST = '127.0.0.1';
var util = require('../util');
var config = require('../config');
var Transform = require('pipestream').Transform;
var EventEmitter = require('events').EventEmitter;

function passThrough(chunk, encoding, callback) {
	callback(null, chunk);
}

function unzipBody(encoding, body, callback) {
	var unzip;
	switch (body && util.toLowerCase(encoding)) {
	    case 'gzip':
	    	unzip = zlib.gunzip.bind(zlib);
	      break;
	    case 'deflate':
	    	unzip = zlib.inflate.bind(zlib);
	      break;
	}

	unzip ? unzip(body, function(err, data) {
		err ? zlib.inflateRaw(body, callback) : callback(null, data);
	}) : callback(null, body);

}

function emitDataEvents(req, res, proxy) {
	var exportsFile = util.getMatcherValue(req.rules.exports);
	var showHttpData = !req.filter.hide && EventEmitter.listenerCount(proxy, 'request');
	if (!exportsFile && !showHttpData) {
		delete req.headers[config.CLIENT_IP_HEAD];
		return;
	}
	var _res = {};
	var reqEmitter = new EventEmitter();
	var request = new Transform();
	var response = new Transform();
	var now = Date.now();
	var reqData = {
			method: util.toUpperCase(req.method) || 'GET',
			httpVersion: req.httpVersion || '1.1',
            ip: util.getClientIp(req) || LOCALHOST,
            isWhistleHttps: req.isWhistleHttps,
            headers: req.headers,
            trailers: req.trailers
		};
	var resData = {};
	var data = request.data = {
			startTime: now,
			url: req.fullUrl,
			req: reqData,
			res: resData,
			rules: req.rules
	};

	delete req.headers[config.CLIENT_IP_HEAD];
	req.once('dest', function() {
		setReqStatus();
		reqEmitter.emit('send', data);
	});
	res.once('src', function(res) {
		_res = res;
		if (data.endTime) {
			return;
		}

		receiveResBody();
		setResStatus();
		reqEmitter.emit('response', data);
	});
	req.once('close', handleError);
	req.once('error', handleError);
	req.append(request);
	res.append(response);

	reqEmitter.data = data;
	proxy.emit('request', reqEmitter);

	var reqBody = false;
	var reqSize = 0;

	if (util.hasRequestBody(req)) {
		reqBody = showHttpData ? null : '';
	}
	request._transform = function(chunk, encoding, callback) {

		if (chunk) {
			if (reqBody || reqBody === null) {
				reqBody = reqBody ? Buffer.concat([reqBody, chunk]) : chunk;
				if (reqBody.length > MAX_REQ_SIZE) {
					reqBody = false;
				}
			}
			reqSize += chunk.length;
		} else {
			data.requestTime = Date.now();
			reqData.size = reqSize;
			reqData.body = util.decodeBuffer(reqBody);
		}

		callback(null, chunk);
	};

	function receiveResBody() {
		var resBody = false;
		var resSize = 0;
		var contentType = util.getContentType(_res.headers);
		if (contentType && contentType != 'IMG' && util.hasBody(_res)) {
			resBody = showHttpData ? null : '';
		}

		response._transform = function(chunk, encoding, callback) {
			if (chunk) {
				if (resBody || resBody === null) {
					resBody = resBody ? Buffer.concat([resBody, chunk]) : chunk;
					if (resBody.length > MAX_RES_SIZE) {
						resBody = false;
					}
				}
				resSize += chunk.length;
				callback(null, chunk);
			} else {
				unzipBody(util.toLowerCase(_res.headers['content-encoding']), resBody,
						function(err, body) {
					resData.body = err ? util.getErrorStack(err) : util.decodeBuffer(body);
					data.endTime = Date.now();
					resData.size = resSize;
					reqEmitter.emit('end', data);
					callback(null, chunk);
					writeExportsFile();
				});
			}
		};
	}

	function handleError(err) {
		if (data.endTime || (data.responseTime && !err)) {//connection: close的时候，还要数据缓存
			return;
		}

		request._transform = passThrough;
		response._transform = passThrough;
		data.endTime = Date.now();
		if (err) {
			data.resError = true;
			resData.body = util.getErrorStack(err);
			util.emitError(reqEmitter, data);
			setResStatus(502);
		} else {
			data.reqError = true;
			reqData.body = 'aborted';
			reqEmitter.emit('abort', data);
			setResStatus('aborted');
		}
		writeExportsFile();
	}

	function setReqStatus(defaultHost) {
		data.dnsTime = (req.dnsTime || 0) + now;
		data.realUrl = req.realUrl;
		resData.ip = req.hostIp || defaultHost;
	}

	function setResStatus(defaultCode) {
		setReqStatus(LOCALHOST);
		resData.statusCode = _res.statusCode || defaultCode || 502;
		resData.statusMessage = _res.statusMessage;
		if (!data.requestTime) {
			data.requestTime = Date.now();
		}
		data.responseTime = Date.now();
		resData.headers = _res.headers;
		resData.trailers = _res.trailers;
	}

	function writeExportsFile() {
		if (!exportsFile) {
			return;
		}
		var root = req.rules.exports.root;
		if (root) {
			exportsFile = path.join(root, exportsFile);
		}
		fse.ensureFile(exportsFile, function(err) {
			if (err) {
				return;
			}

			fs.writeFile(exportsFile, '\r\n' + JSON.stringify({
				startTime: data.startTime,
				dnsTime: data.dnsTime,
				requestTime: data.requestTime,
				responseTime: data.responseTime,
				endTime: data.endTime,
				url: data.url,
				realUrl: data.url == data.realUrl ? undefined : data.realUrl,
				method: reqData.method,
				httpVersion: reqData.httpVersion,
				clientIp: reqData.ip,
				reqError: data.reqError,
				reqSize: reqData.size,
				reqHeaders: reqData.headers,
				reqTrailers: reqData.trailers,
				statusCode: resData.statusCode,
				hostIp: resData.ip,
				resError: data.resError,
				resSize: resData.size,
				resHeaders: resData.headers,
				resTrailers: resData.trailers,
				rules: req.rules
			}), {flag: 'a'}, util.noop);
		});
	}
}

function addTimeout(req, res, timeout) {
	if (!(timeout > 0) || req.disable.timeout) {
		return;
	}
	var timeoutId, responsed;
	var preReq = new Transform();
	var endReq = new Transform();
	var preRes = new Transform();
	var endRes = new Transform();

	preReq._transform = preRes._transform = function(chunk, encoding, callback) {
		timeoutId && clearTimeout(timeoutId);
		timeoutId = null;
		callback(null, chunk);
	};

	endReq._transform = endRes._transform = function(chunk, encoding, callback) {
		timeoutId && clearTimeout(timeoutId);
		if (!responsed || chunk) {
			timeoutId = setTimeout(emitTimeoutError, timeout);
		}

		if (!chunk) {
			responsed = true;
		}

		callback(null, chunk);
	};

	function emitTimeoutError() {
		util.emitError(responsed ? res : req, new Error('timeout'));
	}

	req.prepend(preReq).append(endReq);
	res.prepend(preRes).append(endRes);
}

module.exports = function(req, res, next) {
	emitDataEvents(req, res, this);
	addTimeout(req, res, req.timeout || this.config.timeout);
	next();
};

<|endoftext|>


<commit_before>/**
 * /api/accounts/*
 */
var express = require('express');
var passport = require('passport');
var config = require('config');
var mongoose = require('mongoose');

var appRoot = require('app-root-path');
var Account = require(appRoot + '/modules/accounts');
var Course = require(appRoot + '/modules/catalogs/course.controller.js');

var helper = require(appRoot + '/libs/core/generalLibs.js');

var router = express.Router();

router.post('/accounts/signUp', function(req, res, next){

    if(!helper.checkRequiredParams(req.body, ['username', 'email', 'password'], function (err) {
            helper.resReturn(err, res);
        }))return;

    var account = new Account();
    account.signUp(
        function failedSignUp(err){
            helper.resReturn(err, res);
        },
        req.body,
        function successSignUp(user){
            res.status(201).json({
                result: (user),

                user: {
                    username: user.username,
                    email: user.email,
                    role: user.role
                }
            });
        }
    );
});

router.get('/accounts/logout', function(req, res, next) {
    req.logout();
    res.status(200).json({result:true, message: 'Logged out'});
});

router.get('/accounts', function(req, res, next) {
    if(req.user)
        res.redirect('/api/accounts/' + req.user.username);
    else
        res.status(401).json({message: 'Not authorized'});
});

router.get('/accounts/login/facebook',
    passport.authenticate('facebook', { scope : ['email','public_profile'] })
);

router.get('/accounts/facebook/callback',
    passport.authenticate('facebook', {
        successRedirect : '/accounts',
        failureRedirect : '/login'
    }),

    // on succes
    function(req,res) {
        // return the token or you would wish otherwise give eg. a succes message
        res.status(200).json({result:true, tokens: JSON.stringify(req.user.access_token)});
    },

    // on error; likely to be something FacebookTokenError token invalid or already used token,
    // these errors occur when the user logs in twice with the same token
    function(err,req,res,next) {
        // You could put your own behavior in here, fx: you could force auth again...
        // res.redirect('/auth/facebook/');
        if(err) {
            res.status(400).json({result: false, errors: [err.message]});
        }
    }
);

router.post('/accounts/login',
    function(req, res, next){
        passport.authenticate('local', function(err, user, info) {
            if (err) {
                // if error happens
                return next(err);
            }

            if (!user) {

                return res.status(401).json({
                    result: false,
                    errors: ['Wrong username or password']
                });

            }

            // if everything is OK
            req.logIn(user, function(err) {
                if (err) {
                    req.session.messages = "Error";
                    return next(err);
                }

                // remember me box is checked
                if (req.body.rememberMe) {
                    req.session.cookie.maxAge = config.get('session.maxAge');
                    req.session._garbage = Date();
                    req.session.touch();
                } else {
                    // it means when the browser is closed, the cookie will expire
                    req.session.cookie.expires = false;
                }

                // set the message and redirect
                req.session.messages = "Login successfully";
                res.status(200).json({
                    result: true,
                    user: req.user
                });
            });
        })(req, res, next);
    }
);

router.get('/accounts/:username', function(req, res, next) {
    if (!req.user) {
        res.status(401).send('Unauthorized');
        return;
    }

    // todo: if admin, can get val from url param

    var account = new Account();
    account.getUser(
        function(err){
            helper.resReturn(err, res);
        },

        {username: req.session.passport.user.username},

        function(doc){
            if(doc) {
                res.status(200).json({
                    result: true, user: doc
                });
            } else {
                res.status(404).json({
                    result: false, errors: ["User not found"]
                });
            }
        }
    );
});

/**
 * change password only
 */
router.put('/accounts/:userId/changePassword', function(req, res, next){
    if (!req.user) {
        res.status(401).send('Unauthorized');
        return;
    }

    req.body.userId = mongoose.Types.ObjectId(req.user._id);

    // todo: if admin, can put val from url param

    if(!req.body.password || !req.body.passwordConfirm) {
        res.status(400).json({result: false, errors:["parameter not complete"]});
        next();
    }
    else {
        var account = new Account();
        account.changePassword(
            function error(err) {
                helper.resReturn(err, res);
            },
            req.body,
            function success(r) {
                res.status(200).json({result: true});
            }
        );
    }
});

router.put('/accounts/:userId', function(req, res, next){
    if (!req.user) {
        res.status(401).send('Unauthorized');
        return;
    }

    req.body.userId = mongoose.Types.ObjectId(req.user._id);

    // todo: if admin, can put val from url param

    var account = new Account();
    account.editAccount(
        function error(err) {
            helper.resReturn(err, res);
        },

        req.body,

        function success(r) {
            res.status(200).json({result: true});
        }
    );
});

router.get('/accounts/:userId/courses', function(req, res, next) {
    if (!req.user) {
        res.status(401).send('Unauthorized');
        return;
    }

    var crs = new Course();

    var userId = mongoose.Types.ObjectId(req.params.userId);

    // todo: if admin, can put val from url param

    crs.getUserCourses(
        function error(err){
            helper.resReturn(err, res);
        },
        { user: userId },
        function success(courses){
            res.status(200).json({result:true, courses:courses});
        }
    );
});

router.get('/accounts/:userId/course/:courseId', function(req, res, next) {
    if (!req.user) {
        res.status(401).send('Unauthorized');
        return;
    }

    var crs = new Course();

    var userId = mongoose.Types.ObjectId(req.params.userId);
    var courseId = mongoose.Types.ObjectId(req.params.courseId);

    // todo: if admin, can put val from url param

    crs.getUserCourses(
        function error(err){
            helper.resReturn(err, res);
        },
        {
            user: userId,
            course: courseId
        },
        function success(courses){
            if(courses.length > 0)
                res.status(200).json({result:true, courses:courses[0]});
            else
                res.status(200).json({result:true, courses:null});
        }
    );
});

module.exports = router;
<commit_msg>rearrange put and post<commit_after>/**
 * /api/accounts/*
 */
var express = require('express');
var passport = require('passport');
var config = require('config');
var mongoose = require('mongoose');

var appRoot = require('app-root-path');
var Account = require(appRoot + '/modules/accounts');
var Course = require(appRoot + '/modules/catalogs/course.controller.js');

var helper = require(appRoot + '/libs/core/generalLibs.js');

var router = express.Router();

router.get('/accounts/logout', function (req, res, next) {
    req.logout();
    res.status(200).json({result: true, message: 'Logged out'});
});

router.get('/accounts', function (req, res, next) {
    if (req.user)
        res.redirect('/api/accounts/' + req.user.username);
    else
        res.status(401).json({message: 'Not authorized'});
});

/*router.get('/accounts/req', function (req, res, next) {
    res.status(200).json({
        result: true, user: req.user
    });
});*/

router.get('/accounts/login/facebook',
    passport.authenticate('facebook', {scope: ['email', 'public_profile']})
);

router.get('/accounts/facebook/callback',
    passport.authenticate('facebook', {
        successRedirect: '/accounts',
        failureRedirect: '/login'
    }),

    // on succes
    function (req, res) {
        // return the token or you would wish otherwise give eg. a succes message
        res.status(200).json({result: true, tokens: JSON.stringify(req.user.access_token)});
    },

    // on error; likely to be something FacebookTokenError token invalid or already used token,
    // these errors occur when the user logs in twice with the same token
    function (err, req, res, next) {
        // You could put your own behavior in here, fx: you could force auth again...
        // res.redirect('/auth/facebook/');
        if (err) {
            res.status(400).json({result: false, errors: [err.message]});
        }
    }
);

router.get('/accounts/:username', function (req, res, next) {
    if (!req.user) {
        res.status(401).send('Unauthorized');
        return;
    }

    // todo: if admin, can get val from url param

    var account = new Account();
    account.getUser(
        function (err) {
            helper.resReturn(err, res);
        },

        {username: req.session.passport.user.username},

        function (doc) {
            if (doc) {
                res.status(200).json({
                    result: true, user: doc
                });
            } else {
                res.status(404).json({
                    result: false, errors: ["User not found"]
                });
            }
        }
    );
});

router.get('/accounts/:userId/courses', function (req, res, next) {
    if (!req.user) {
        res.status(401).send('Unauthorized');
        return;
    }

    var crs = new Course();

    var userId = mongoose.Types.ObjectId(req.params.userId);

    // todo: if admin, can put val from url param

    crs.getUserCourses(
        function error(err) {
            helper.resReturn(err, res);
        },
        {user: userId},
        function success(courses) {
            res.status(200).json({result: true, courses: courses});
        }
    );
});

router.get('/accounts/:userId/course/:courseId', function (req, res, next) {
    if (!req.user) {
        res.status(401).send('Unauthorized');
        return;
    }

    var crs = new Course();

    var userId = mongoose.Types.ObjectId(req.params.userId);
    var courseId = mongoose.Types.ObjectId(req.params.courseId);

    // todo: if admin, can put val from url param

    crs.getUserCourses(
        function error(err) {
            helper.resReturn(err, res);
        },
        {
            user: userId,
            course: courseId
        },
        function success(courses) {
            if (courses.length > 0)
                res.status(200).json({result: true, courses: courses[0]});
            else
                res.status(200).json({result: true, courses: null});
        }
    );
});

/**
 * POST
 */

router.post('/accounts/signUp', function (req, res, next) {

    if (!helper.checkRequiredParams(req.body, ['username', 'email', 'password'], function (err) {
            helper.resReturn(err, res);
        }))return;

    var account = new Account();
    account.signUp(
        function failedSignUp(err) {
            helper.resReturn(err, res);
        },
        req.body,
        function successSignUp(user) {
            res.status(201).json({
                result: (user),

                user: {
                    username: user.username,
                    email: user.email,
                    role: user.role
                }
            });
        }
    );
});

router.post('/accounts/login',
    function (req, res, next) {
        passport.authenticate('local', function (err, user, info) {
            if (err) {
                // if error happens
                return next(err);
            }

            if (!user) {

                return res.status(401).json({
                    result: false,
                    errors: ['Wrong username or password']
                });

            }

            // if everything is OK
            req.logIn(user, function (err) {
                if (err) {
                    req.session.messages = "Error";
                    return next(err);
                }

                // remember me box is checked
                if (req.body.rememberMe) {
                    req.session.cookie.maxAge = config.get('session.maxAge');
                    req.session._garbage = Date();
                    req.session.touch();
                } else {
                    // it means when the browser is closed, the cookie will expire
                    req.session.cookie.expires = false;
                }

                // set the message and redirect
                req.session.messages = "Login successfully";
                res.status(200).json({
                    result: true,
                    user: req.user
                });
            });
        })(req, res, next);
    }
);

/**
 * PUT
 */

/**
 * change password only
 */
router.put('/accounts/:userId/changePassword', function (req, res, next) {
    if (!req.user) {
        res.status(401).send('Unauthorized');
        return;
    }

    req.body.userId = mongoose.Types.ObjectId(req.user._id);

    // todo: if admin, can put val from url param

    if (!req.body.password || !req.body.passwordConfirm) {
        res.status(400).json({result: false, errors: ["parameter not complete"]});
        next();
    }
    else {
        var account = new Account();
        account.changePassword(
            function error(err) {
                helper.resReturn(err, res);
            },
            req.body,
            function success(r) {
                res.status(200).json({result: true});
            }
        );
    }
});

router.put('/accounts/:userId', function (req, res, next) {
    if (!req.user) {
        res.status(401).send('Unauthorized');
        return;
    }

    req.body.userId = mongoose.Types.ObjectId(req.user._id);

    // todo: if admin, can put val from url param

    var account = new Account();
    account.editAccount(
        function error(err) {
            helper.resReturn(err, res);
        },

        req.body,

        function success(r) {
            res.status(200).json({result: true});
        }
    );
});

module.exports = router;
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import {namedTypes as t, NodePath} from 'ast-types';
import { traverseShallow } from '../utils/traverse';
import resolve from 'resolve';
import { dirname } from 'path';
import buildParser, { type Options } from '../babelParser';
import fs from 'fs';

export default function resolveImportedValue(
  path: NodePath,
  name: string,
  seen: Set<string> = new Set(),
) {
  // Bail if no filename was provided for the current source file.
  // Also never traverse into react itself.
  const source = path.node.source.value;
  const options = getOptions(path);
  if (!options || !options.filename || source === 'react') {
    return null;
  }

  // Resolve the imported module using the Node resolver
  const basedir = dirname(options.filename);
  let resolvedSource;

  try {
    resolvedSource = resolve.sync(source, {
      basedir,
      extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx'],
    });
  } catch (err) {
    return null;
  }

  // Prevent recursive imports
  if (seen.has(resolvedSource)) {
    return null;
  }

  seen.add(resolvedSource);

  // Read and parse the code
  // TODO: cache and reuse
  const src = fs.readFileSync(resolvedSource, 'utf8');
  const parseOptions: Options = {
    ...options,
    parserOptions: {},
    filename: resolvedSource,
  };

  const parser = buildParser(parseOptions);
  const ast = parser.parse(src);
  ast.__src = src;
  return findExportedValue(new NodePath(ast).get('program'), name, seen);
}

// Find the root Program node, which we attached our options too in babelParser.js
function getOptions(path: NodePath): Options {
  while (!t.Program.check(path.node)) {
    path = path.parentPath;
  }

  return path.node.options || {};
}

// Traverses the program looking for an export that matches the requested name
function findExportedValue(programPath, name, seen) {
  let resultPath: ?NodePath = null;

  traverseShallow(programPath, {
    visitExportNamedDeclaration(path: NodePath) {
      const { declaration, specifiers, source } = path.node;
      if (declaration && declaration.id && declaration.id.name === name) {
        resultPath = path.get('declaration');
      } else if (declaration && declaration.declarations) {
        path.get('declaration', 'declarations').each((declPath: NodePath) => {
          const decl = declPath.node;
          // TODO: ArrayPattern and ObjectPattern
          if (
            t.Identifier.check(decl.id) &&
            decl.id.name === name &&
            decl.init
          ) {
            resultPath = declPath.get('init');
          }
        });
      } else if (specifiers) {
        path.get('specifiers').each((specifierPath: NodePath) => {
          if (specifierPath.node.exported.name === name) {
            if (source) {
              const local = specifierPath.node.local.name;
              resultPath = resolveImportedValue(path, local, seen);
            } else {
              resultPath = specifierPath.get('local');
            }
          }
        });
      }

      return false;
    },
    visitExportDefaultDeclaration(path: NodePath) {
      if (name === 'default') {
        resultPath = path.get('declaration');
      }

      return false;
    },
    visitExportAllDeclaration(path: NodePath) {
      const resolvedPath = resolveImportedValue(path, name, seen);
      if (resolvedPath) {
        resultPath = resolvedPath;
      }

      return false;
    },
  });

  return resultPath;
}
<commit_msg>Lint fixes<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import { namedTypes as t, NodePath } from 'ast-types';
import { traverseShallow } from '../utils/traverse';
import resolve from 'resolve';
import { dirname } from 'path';
import buildParser, { type Options } from '../babelParser';
import fs from 'fs';

export default function resolveImportedValue(
  path: NodePath,
  name: string,
  seen: Set<string> = new Set(),
) {
  // Bail if no filename was provided for the current source file.
  // Also never traverse into react itself.
  const source = path.node.source.value;
  const options = getOptions(path);
  if (!options || !options.filename || source === 'react') {
    return null;
  }

  // Resolve the imported module using the Node resolver
  const basedir = dirname(options.filename);
  let resolvedSource;

  try {
    resolvedSource = resolve.sync(source, {
      basedir,
      extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx'],
    });
  } catch (err) {
    return null;
  }

  // Prevent recursive imports
  if (seen.has(resolvedSource)) {
    return null;
  }

  seen.add(resolvedSource);

  // Read and parse the code
  // TODO: cache and reuse
  const src = fs.readFileSync(resolvedSource, 'utf8');
  const parseOptions: Options = {
    ...options,
    parserOptions: {},
    filename: resolvedSource,
  };

  const parser = buildParser(parseOptions);
  const ast = parser.parse(src);
  ast.__src = src;
  return findExportedValue(new NodePath(ast).get('program'), name, seen);
}

// Find the root Program node, which we attached our options too in babelParser.js
function getOptions(path: NodePath): Options {
  while (!t.Program.check(path.node)) {
    path = path.parentPath;
  }

  return path.node.options || {};
}

// Traverses the program looking for an export that matches the requested name
function findExportedValue(programPath, name, seen) {
  let resultPath: ?NodePath = null;

  traverseShallow(programPath, {
    visitExportNamedDeclaration(path: NodePath) {
      const { declaration, specifiers, source } = path.node;
      if (declaration && declaration.id && declaration.id.name === name) {
        resultPath = path.get('declaration');
      } else if (declaration && declaration.declarations) {
        path.get('declaration', 'declarations').each((declPath: NodePath) => {
          const decl = declPath.node;
          // TODO: ArrayPattern and ObjectPattern
          if (
            t.Identifier.check(decl.id) &&
            decl.id.name === name &&
            decl.init
          ) {
            resultPath = declPath.get('init');
          }
        });
      } else if (specifiers) {
        path.get('specifiers').each((specifierPath: NodePath) => {
          if (specifierPath.node.exported.name === name) {
            if (source) {
              const local = specifierPath.node.local.name;
              resultPath = resolveImportedValue(path, local, seen);
            } else {
              resultPath = specifierPath.get('local');
            }
          }
        });
      }

      return false;
    },
    visitExportDefaultDeclaration(path: NodePath) {
      if (name === 'default') {
        resultPath = path.get('declaration');
      }

      return false;
    },
    visitExportAllDeclaration(path: NodePath) {
      const resolvedPath = resolveImportedValue(path, name, seen);
      if (resolvedPath) {
        resultPath = resolvedPath;
      }

      return false;
    },
  });

  return resultPath;
}
<|endoftext|>


<commit_before>var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
require('dotenv').load();
var url = require('url');

var querystring = require('querystring');

var eventTypesRaw = process.env.BAMBOO_EVENT_NOTIFIER_TYPES;

var eventTypes = [];

if (eventTypesRaw != null) {
    eventTypes = eventTypesRaw.split(',');
} else {
    console.warn("github-repo-event-notifier is not setup to receive any events (BAMBOO_EVENT_NOTIFIER_TYPES is empty).");
}

var express = require('express');
var router = express.Router();

router.get("/", function(req, res) {
    return res.end("GitHub Bamboo Proxy");
});

console.info("registered GET /bamboo");

router.post("/", function(req, res) {
    var auth, auto_trigger, bamboo_uri, bamboo_url, build_key, data, error, error1, eventType, pass, query, room, user;
    user = process.env.BAMBOO_USERNAME;
    pass = process.env.BAMBOO_PASSWORD;
    auth = new Buffer(user + ':' + pass).toString('base64');
    query = querystring.parse(url.parse(req.url).query);
    bamboo_url = query.bamboo;
    build_key = query.buildKey;
    room = query.room;
    auto_trigger = query.auto;
    if (!bamboo_url) {
        return res.end("");
    }

    data = req.body;
    console.log(data);
    eventType = req.headers["x-github-event"];
    console.log("Processing event type " + eventType + "...");
    try {
        if (indexOf.call(eventTypes, eventType) >= 0) {
            if (auto_trigger) {
                bamboo_uri = bamboo_url + "/rest/api/latest/queue/" + build_key + "?bamboo.variable.pull_ref=" + data.pull_request.head.ref + "&bamboo.variable.pull_sha=" + data.pull_request.head.sha + "&bamboo.variable.pull_num=" + data.number;

                var headers = { Authorization: "Basic " + auth};
                fetch(bamboo_uri, { method: 'POST', headers: headers })
                    .catch(function(rejection) {
                        return console.log("Encountered an error sending to bamboo " + rejection);
                    });
            }
        } else {
            console.log("Ignoring " + eventType + " event as it's not allowed.");
        }
    } catch (error1) {
        error = error1;
        console.log("github repo event notifier error: " + error + ". Request: " + req.body);
        console.log(error.stack);
    }
    console.log("Finished processing event type " + eventType);
    return res.end("");
});

module.exports = router
<commit_msg>forgot to require node-fetch<commit_after>var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
require('dotenv').load();
var url = require('url');

var querystring = require('querystring');

var eventTypesRaw = process.env.BAMBOO_EVENT_NOTIFIER_TYPES;

var eventTypes = [];

if (eventTypesRaw != null) {
    eventTypes = eventTypesRaw.split(',');
} else {
    console.warn("github-repo-event-notifier is not setup to receive any events (BAMBOO_EVENT_NOTIFIER_TYPES is empty).");
}

var express = require('express');
var fetch = require('node-fetch');
var router = express.Router();

router.get("/", function(req, res) {
    return res.end("GitHub Bamboo Proxy");
});

console.info("registered GET /bamboo");

router.post("/", function(req, res) {
    var auth, auto_trigger, bamboo_uri, bamboo_url, build_key, data, error, error1, eventType, pass, query, room, user;
    user = process.env.BAMBOO_USERNAME;
    pass = process.env.BAMBOO_PASSWORD;
    auth = new Buffer(user + ':' + pass).toString('base64');
    query = querystring.parse(url.parse(req.url).query);
    bamboo_url = query.bamboo;
    build_key = query.buildKey;
    room = query.room;
    auto_trigger = query.auto;
    if (!bamboo_url) {
        return res.end("");
    }

    data = req.body;
    console.log(data);
    eventType = req.headers["x-github-event"];
    console.log("Processing event type " + eventType + "...");
    try {
        if (indexOf.call(eventTypes, eventType) >= 0) {
            if (auto_trigger) {
                bamboo_uri = bamboo_url + "/rest/api/latest/queue/" + build_key + "?bamboo.variable.pull_ref=" + data.pull_request.head.ref + "&bamboo.variable.pull_sha=" + data.pull_request.head.sha + "&bamboo.variable.pull_num=" + data.number;

                var headers = { Authorization: "Basic " + auth};
                fetch(bamboo_uri, { method: 'POST', headers: headers })
                    .catch(function(rejection) {
                        return console.log("Encountered an error sending to bamboo " + rejection);
                    });
            }
        } else {
            console.log("Ignoring " + eventType + " event as it's not allowed.");
        }
    } catch (error1) {
        error = error1;
        console.log("github repo event notifier error: " + error + ". Request: " + req.body);
        console.log(error.stack);
    }
    console.log("Finished processing event type " + eventType);
    return res.end("");
});

module.exports = router
<|endoftext|>