<commit_before>'use strict';
/*global angular: false, Highcharts: false */

angular.module('highcharts-ng', [])
  .factory('highchartsNGUtils', function () {

    return {

      //IE8 support
      indexOf: function (arr, find, i /*opt*/) {
        if (i === undefined) i = 0;
        if (i < 0) i += arr.length;
        if (i < 0) i = 0;
        for (var n = arr.length; i < n; i++)
          if (i in arr && arr[i] === find)
            return i;
        return -1;
      },

      prependMethod: function (obj, method, func) {
        var original = obj[method];
        obj[method] = function () {
          var args = Array.prototype.slice.call(arguments);
          func.apply(this, args);
          if (original) {
            return original.apply(this, args);
          } else {
            return;
          }

        };
      },

      deepExtend: function deepExtend(destination, source) {
        //Slightly strange behaviour in edge cases (e.g. passing in non objects)
        //But does the job for current use cases.
        if (angular.isArray(source)) {
          destination = angular.isArray(destination) ? destination : [];
          for (var i = 0; i < source.length; i++) {
            destination[i] = deepExtend(destination[i] || {}, source[i]);
          }
        } else if (angular.isObject(source)) {
          for (var property in source) {
            destination[property] = deepExtend(destination[property] || {}, source[property]);
          }
        } else {
          destination = source;
        }
        return destination;
      }
    };

  }).directive('highchart', ['highchartsNGUtils', function (highchartsNGUtils) {

    // acceptable shared state
    var seriesId = 0;
    var ensureIds = function (series) {
      var changed = false;
      angular.forEach(series, function(s) {
        if (!angular.isDefined(s.id)) {
          s.id = 'series-' + seriesId++;
          changed = true;
        }
      });
      return changed;
    };

    // immutable
    var axisNames = [ 'xAxis', 'yAxis' ];

    var getMergedOptions = function (scope, element, config) {
      var mergedOptions = {};

      var defaultOptions = {
        chart: {
          events: {}
        },
        title: {},
        subtitle: {},
        series: [],
        credits: {},
        plotOptions: {},
        navigator: {enabled: false}
      };

      if (config.options) {
        mergedOptions = highchartsNGUtils.deepExtend(defaultOptions, config.options);
      } else {
        mergedOptions = defaultOptions;
      }
      mergedOptions.chart.renderTo = element[0];

      angular.forEach(axisNames, function(axisName) {
        if(angular.isDefined(config[axisName])) {
          mergedOptions[axisName] = angular.copy(config[axisName]);

          if(angular.isDefined(config[axisName].currentMin) ||
              angular.isDefined(config[axisName].currentMax)) {

            highchartsNGUtils.prependMethod(mergedOptions.chart.events, 'selection', function(e){
              var thisChart = this;
              if (e[axisName]) {
                scope.$apply(function () {
                  scope.config[axisName].currentMin = e[axisName][0].min;
                  scope.config[axisName].currentMax = e[axisName][0].max;
                });
              } else {
                //handle reset button - zoom out to all
                scope.$apply(function () {
                  scope.config[axisName].currentMin = thisChart[axisName][0].dataMin;
                  scope.config[axisName].currentMax = thisChart[axisName][0].dataMax;
                });
              }
            });

            highchartsNGUtils.prependMethod(mergedOptions.chart.events, 'addSeries', function(e){
              scope.config[axisName].currentMin = this[axisName][0].min || scope.config[axisName].currentMin;
              scope.config[axisName].currentMax = this[axisName][0].max || scope.config[axisName].currentMax;
            });
          }
        }
      });

      if(config.title) {
        mergedOptions.title = config.title;
      }
      if (config.subtitle) {
        mergedOptions.subtitle = config.subtitle;
      }
      if (config.credits) {
        mergedOptions.credits = config.credits;
      }
      if(config.size) {
        if (config.size.width) {
          mergedOptions.chart.width = config.size.width;
        }
        if (config.size.height) {
          mergedOptions.chart.height = config.size.height;
        }
      }
      return mergedOptions;
    };

    var updateZoom = function (axis, modelAxis) {
      var extremes = axis.getExtremes();
      if(modelAxis.currentMin !== extremes.dataMin || modelAxis.currentMax !== extremes.dataMax) {
        axis.setExtremes(modelAxis.currentMin, modelAxis.currentMax, false);
      }
    };

    var processExtremes = function(chart, axis, axisName) {
      if(axis.currentMin || axis.currentMax) {
        chart[axisName][0].setExtremes(axis.currentMin, axis.currentMax, true);
      }
    };

    var chartOptionsWithoutEasyOptions = function (options) {
      return angular.extend({}, options, {data: null, visible: null});
    };

    return {
      restrict: 'EAC',
      replace: true,
      template: '

',
      scope: {
        config: '=',
        disableDataWatch: '='
      },
      link: function (scope, element, attrs) {
        // We keep some chart-specific variables here as a closure
        // instead of storing them on 'scope'.

        // prevSeriesOptions is maintained by processSeries
        var prevSeriesOptions = {};

        var processSeries = function(series) {
          var i;
          var ids = [];

          if(series) {
            var setIds = ensureIds(series);
            if(setIds && !scope.disableDataWatch) {
              //If we have set some ids this will trigger another digest cycle.
              //In this scenario just return early and let the next cycle take care of changes
              return false;
            }

            //Find series to add or update
            angular.forEach(series, function(s) {
              ids.push(s.id);
              var chartSeries = chart.get(s.id);
              if (chartSeries) {
                if (!angular.equals(prevSeriesOptions[s.id], chartOptionsWithoutEasyOptions(s))) {
                  chartSeries.update(angular.copy(s), false);
                } else {
                  if (s.visible !== undefined && chartSeries.visible !== s.visible) {
                    chartSeries.setVisible(s.visible, false);
                  }
                  chartSeries.setData(angular.copy(s.data), false);
                }
              } else {
                chart.addSeries(angular.copy(s), false);
              }
              prevSeriesOptions[s.id] = chartOptionsWithoutEasyOptions(s);
            });

            //  Shows no data text if all series are empty
            if(scope.config.noData) {
              var chartContainsData = false;

              for(i = 0; i < series.length; i++) {
                if (series[i].data && series[i].data.length > 0) {
                  chartContainsData = true;

                  break;
                }
              }

              if (!chartContainsData) {
                chart.showLoading(scope.config.noData);
              } else {
                chart.hideLoading();
              }
            }
          }

          //Now remove any missing series
          for(i = chart.series.length - 1; i >= 0; i--) {
            var s = chart.series[i];
            if (highchartsNGUtils.indexOf(ids, s.options.id) < 0) {
              s.remove(false);
            }
          }

          return true;
        };

        // chart is maintained by initChart
        var chart = false;
        var initChart = function() {
          if (chart) chart.destroy();
          prevSeriesOptions = {};
          var config = scope.config || {};
          var mergedOptions = getMergedOptions(scope, element, config);
          var func = config.func || undefined;
          chart = config.useHighStocks ?
            new Highcharts.StockChart(mergedOptions, func) :
            new Highcharts.Chart(mergedOptions, func);
          for (var i = 0; i < axisNames.length; i++) {
            if (config[axisNames[i]]) {
              processExtremes(chart, config[axisNames[i]], axisNames[i]);
            }
          }
          if(config.loading) {
            chart.showLoading();
          }

        };
        initChart();

        if(scope.disableDataWatch){
          scope.$watchCollection('config.series', function (newSeries, oldSeries) {
            processSeries(newSeries);
            chart.redraw();
          });
        } else {
          scope.$watch('config.series', function (newSeries, oldSeries) {
            var needsRedraw = processSeries(newSeries);
            if(needsRedraw) {
              chart.redraw();
            }
          }, true);
        }

        scope.$watch('config.title', function (newTitle) {
          chart.setTitle(newTitle, true);
        }, true);

        scope.$watch('config.subtitle', function (newSubtitle) {
          chart.setTitle(true, newSubtitle);
        }, true);

        scope.$watch('config.loading', function (loading) {
          if(loading) {
            chart.showLoading();
          } else {
            chart.hideLoading();
          }
        });

        scope.$watch('config.credits.enabled', function (enabled) {
          if (enabled) {
            chart.credits.show();
          } else if (chart.credits) {
            chart.credits.hide();
          }
        });

        scope.$watch('config.useHighStocks', function (useHighStocks, oldUseHighStocks) {
          if(useHighStocks === oldUseHighStocks) return;
          initChart();
        });

        angular.forEach(axisNames, function(axisName) {
          scope.$watch('config.' + axisName, function (newAxes, oldAxes) {
            if (newAxes === oldAxes) return;
            if(newAxes) {
              chart[axisName][0].update(newAxes, false);
              updateZoom(chart[axisName][0], angular.copy(newAxes));
              chart.redraw();
            }
          }, true);
        });
        scope.$watch('config.options', function (newOptions, oldOptions, scope) {
          //do nothing when called on registration
          if (newOptions === oldOptions) return;
          initChart();
          processSeries(scope.config.series);
          chart.redraw();
        }, true);

        scope.$watch('config.size', function (newSize, oldSize) {
          if(newSize === oldSize) return;
          if(newSize) {
            chart.setSize(newSize.width || undefined, newSize.height || undefined);
          }
        }, true);

        scope.$on('highchartsng.reflow', function () {
          chart.reflow();
        });

        scope.$on('$destroy', function() {
          if (chart) {
            chart.destroy();
            setTimeout(function(){
              element.remove();
            }, 0);
          }
        });

      }
    };
  }]);
<commit_msg>updated the processSeries method<commit_after>'use strict';
/*global angular: false, Highcharts: false */

angular.module('highcharts-ng', [])
  .factory('highchartsNGUtils', function () {

    return {

      //IE8 support
      indexOf: function (arr, find, i /*opt*/) {
        if (i === undefined) i = 0;
        if (i < 0) i += arr.length;
        if (i < 0) i = 0;
        for (var n = arr.length; i < n; i++)
          if (i in arr && arr[i] === find)
            return i;
        return -1;
      },

      prependMethod: function (obj, method, func) {
        var original = obj[method];
        obj[method] = function () {
          var args = Array.prototype.slice.call(arguments);
          func.apply(this, args);
          if (original) {
            return original.apply(this, args);
          } else {
            return;
          }

        };
      },

      deepExtend: function deepExtend(destination, source) {
        //Slightly strange behaviour in edge cases (e.g. passing in non objects)
        //But does the job for current use cases.
        if (angular.isArray(source)) {
          destination = angular.isArray(destination) ? destination : [];
          for (var i = 0; i < source.length; i++) {
            destination[i] = deepExtend(destination[i] || {}, source[i]);
          }
        } else if (angular.isObject(source)) {
          for (var property in source) {
            destination[property] = deepExtend(destination[property] || {}, source[property]);
          }
        } else {
          destination = source;
        }
        return destination;
      }
    };

  }).directive('highchart', ['highchartsNGUtils', function (highchartsNGUtils) {

    // acceptable shared state
    var seriesId = 0;
    var ensureIds = function (series) {
      var changed = false;
      angular.forEach(series, function(s) {
        if (!angular.isDefined(s.id)) {
          s.id = 'series-' + seriesId++;
          changed = true;
        }
      });
      return changed;
    };

    // immutable
    var axisNames = [ 'xAxis', 'yAxis' ];

    var getMergedOptions = function (scope, element, config) {
      var mergedOptions = {};

      var defaultOptions = {
        chart: {
          events: {}
        },
        title: {},
        subtitle: {},
        series: [],
        credits: {},
        plotOptions: {},
        navigator: {enabled: false}
      };

      if (config.options) {
        mergedOptions = highchartsNGUtils.deepExtend(defaultOptions, config.options);
      } else {
        mergedOptions = defaultOptions;
      }
      mergedOptions.chart.renderTo = element[0];

      angular.forEach(axisNames, function(axisName) {
        if(angular.isDefined(config[axisName])) {
          mergedOptions[axisName] = angular.copy(config[axisName]);

          if(angular.isDefined(config[axisName].currentMin) ||
              angular.isDefined(config[axisName].currentMax)) {

            highchartsNGUtils.prependMethod(mergedOptions.chart.events, 'selection', function(e){
              var thisChart = this;
              if (e[axisName]) {
                scope.$apply(function () {
                  scope.config[axisName].currentMin = e[axisName][0].min;
                  scope.config[axisName].currentMax = e[axisName][0].max;
                });
              } else {
                //handle reset button - zoom out to all
                scope.$apply(function () {
                  scope.config[axisName].currentMin = thisChart[axisName][0].dataMin;
                  scope.config[axisName].currentMax = thisChart[axisName][0].dataMax;
                });
              }
            });

            highchartsNGUtils.prependMethod(mergedOptions.chart.events, 'addSeries', function(e){
              scope.config[axisName].currentMin = this[axisName][0].min || scope.config[axisName].currentMin;
              scope.config[axisName].currentMax = this[axisName][0].max || scope.config[axisName].currentMax;
            });
          }
        }
      });

      if(config.title) {
        mergedOptions.title = config.title;
      }
      if (config.subtitle) {
        mergedOptions.subtitle = config.subtitle;
      }
      if (config.credits) {
        mergedOptions.credits = config.credits;
      }
      if(config.size) {
        if (config.size.width) {
          mergedOptions.chart.width = config.size.width;
        }
        if (config.size.height) {
          mergedOptions.chart.height = config.size.height;
        }
      }
      return mergedOptions;
    };

    var updateZoom = function (axis, modelAxis) {
      var extremes = axis.getExtremes();
      if(modelAxis.currentMin !== extremes.dataMin || modelAxis.currentMax !== extremes.dataMax) {
        axis.setExtremes(modelAxis.currentMin, modelAxis.currentMax, false);
      }
    };

    var processExtremes = function(chart, axis, axisName) {
      if(axis.currentMin || axis.currentMax) {
        chart[axisName][0].setExtremes(axis.currentMin, axis.currentMax, true);
      }
    };

    var chartOptionsWithoutEasyOptions = function (options) {
      return angular.extend({}, options, {data: null, visible: null});
    };

    return {
      restrict: 'EAC',
      replace: true,
      template: '

',
      scope: {
        config: '=',
        disableDataWatch: '='
      },
      link: function (scope, element, attrs) {
        // We keep some chart-specific variables here as a closure
        // instead of storing them on 'scope'.

        // prevSeriesOptions is maintained by processSeries
        var prevSeriesOptions = {};

        var processSeries = function(series) {
          var i;
          var ids = [];

          if(series) {
            var setIds = ensureIds(series);
            if(setIds && !scope.disableDataWatch) {
              //If we have set some ids this will trigger another digest cycle.
              //In this scenario just return early and let the next cycle take care of changes
              return false;
            }

            //Find series to add or update
            angular.forEach(series, function(s) {
              ids.push(s.id);
              var chartSeries = chart.get(s.id);
              if (chartSeries) {
                if (!angular.equals(prevSeriesOptions[s.id], chartOptionsWithoutEasyOptions(s))) {
                  chartSeries.update(angular.copy(s), false);
                } else {
                  if (s.visible !== undefined && chartSeries.visible !== s.visible) {
                    chartSeries.setVisible(s.visible, false);
                  }
                  chartSeries.setData(angular.copy(s.data), false);
                }
              } else {
                chart.addSeries(angular.copy(s), false);
              }
              prevSeriesOptions[s.id] = chartOptionsWithoutEasyOptions(s);
            });

            //  Shows no data text if all series are empty
            if(scope.config.noData) {
              var chartContainsData = false;

              for(i = 0; i < series.length; i++) {
                if (series[i].data && series[i].data.length > 0) {
                  chartContainsData = true;

                  break;
                }
              }

              if (!chartContainsData) {
                chart.showLoading(scope.config.noData);
              } else {
                chart.hideLoading();
              }
            }
          }

          //Now remove any missing series
          for(i = chart.series.length - 1; i >= 0; i--) {
            var s = chart.series[i];
            if (s.options.id !== 'highcharts-navigator-series' && highchartsNGUtils.indexOf(ids, s.options.id) < 0) {
              s.remove(false);
            }
          }

          return true;
        };

        // chart is maintained by initChart
        var chart = false;
        var initChart = function() {
          if (chart) chart.destroy();
          prevSeriesOptions = {};
          var config = scope.config || {};
          var mergedOptions = getMergedOptions(scope, element, config);
          var func = config.func || undefined;
          chart = config.useHighStocks ?
            new Highcharts.StockChart(mergedOptions, func) :
            new Highcharts.Chart(mergedOptions, func);
          for (var i = 0; i < axisNames.length; i++) {
            if (config[axisNames[i]]) {
              processExtremes(chart, config[axisNames[i]], axisNames[i]);
            }
          }
          if(config.loading) {
            chart.showLoading();
          }

        };
        initChart();

        if(scope.disableDataWatch){
          scope.$watchCollection('config.series', function (newSeries, oldSeries) {
            processSeries(newSeries);
            chart.redraw();
          });
        } else {
          scope.$watch('config.series', function (newSeries, oldSeries) {
            var needsRedraw = processSeries(newSeries);
            if(needsRedraw) {
              chart.redraw();
            }
          }, true);
        }

        scope.$watch('config.title', function (newTitle) {
          chart.setTitle(newTitle, true);
        }, true);

        scope.$watch('config.subtitle', function (newSubtitle) {
          chart.setTitle(true, newSubtitle);
        }, true);

        scope.$watch('config.loading', function (loading) {
          if(loading) {
            chart.showLoading();
          } else {
            chart.hideLoading();
          }
        });

        scope.$watch('config.credits.enabled', function (enabled) {
          if (enabled) {
            chart.credits.show();
          } else if (chart.credits) {
            chart.credits.hide();
          }
        });

        scope.$watch('config.useHighStocks', function (useHighStocks, oldUseHighStocks) {
          if(useHighStocks === oldUseHighStocks) return;
          initChart();
        });

        angular.forEach(axisNames, function(axisName) {
          scope.$watch('config.' + axisName, function (newAxes, oldAxes) {
            if (newAxes === oldAxes) return;
            if(newAxes) {
              chart[axisName][0].update(newAxes, false);
              updateZoom(chart[axisName][0], angular.copy(newAxes));
              chart.redraw();
            }
          }, true);
        });
        scope.$watch('config.options', function (newOptions, oldOptions, scope) {
          //do nothing when called on registration
          if (newOptions === oldOptions) return;
          initChart();
          processSeries(scope.config.series);
          chart.redraw();
        }, true);

        scope.$watch('config.size', function (newSize, oldSize) {
          if(newSize === oldSize) return;
          if(newSize) {
            chart.setSize(newSize.width || undefined, newSize.height || undefined);
          }
        }, true);

        scope.$on('highchartsng.reflow', function () {
          chart.reflow();
        });

        scope.$on('$destroy', function() {
          if (chart) {
            chart.destroy();
            setTimeout(function(){
              element.remove();
            }, 0);
          }
        });

      }
    };
  }]);
<|endoftext|>


<commit_before>/* @flow */

import type VueRouter from '../index'
import { cleanPath } from '../util/path'
import { History } from './base'

const genKey = () => String(Date.now())
let _key: string = genKey()

export class HTML5History extends History {
  constructor (router: VueRouter) {
    super(router)

    // possible redirect on start
    if (this.getLocation() !== this.current.fullPath) {
      replaceState(this.current.fullPath)
    }

    const expectScroll = router.options.scrollBehavior

    window.addEventListener('popstate', e => {
      _key = e.state && e.state.key
      const current = this.current
      this.transitionTo(this.getLocation(), next => {
        if (expectScroll) {
          this.handleScroll(current, next)
        }
      })
    })

    if (expectScroll) {
      _key = genKey()
      window.addEventListener('scroll', saveScrollPosition)
    }
  }

  go (n: number) {
    window.history.go(n)
  }

  push (location: RawLocation) {
    super.push(location, route => {
      const url = cleanPath(this.base + route.fullPath)
      pushState(url)
    })
  }

  replace (location: RawLocation) {
    super.replace(location, route => {
      const url = cleanPath(this.base + route.fullPath)
      replaceState(url)
    })
  }

  getLocation (): string {
    return getLocation(this.base)
  }

  handleScroll (from: Route, to: Route) {
    const router = this.router
    if (!router.app) {
      return
    }

    let shouldScroll = false
    const behavior = router.options.scrollBehavior
    if (typeof behavior === 'boolean') {
      shouldScroll = behavior
    } else if (typeof behavior === 'function') {
      shouldScroll = behavior(from, to)
    }

    if (!shouldScroll) {
      return
    }

    let position = getScrollPosition()
    if (typeof shouldScroll === 'object' &&
        shouldScroll.x != null &&
        shouldScroll.y != null) {
      position = shouldScroll
    }
    if (position) {
      const { x, y } = position
      router.app.$nextTick(() => {
        window.scrollTo(x, y)
      })
    }
  }
}

export function getLocation (base: string): string {
  let path = window.location.pathname
  if (base && path.indexOf(base) === 0) {
    path = path.slice(base.length)
  }
  return path + window.location.search + window.location.hash
}

function pushState (url: string, replace?: boolean) {
  // try...catch the pushState call to get around Safari
  // DOM Exception 18 where it limits to 100 pushState calls
  const history = window.history
  try {
    if (replace) {
      history.replaceState({ key: _key }, '', url)
    } else {
      _key = genKey()
      history.pushState({ key: _key }, '', url)
    }
    saveScrollPosition()
  } catch (e) {
    window.location[replace ? 'assign' : 'replace'](url)
  }
}

function replaceState (url: string) {
  pushState(url, true)
}

function saveScrollPosition () {
  if (!_key) return
  window.sessionStorage.setItem(_key, JSON.stringify({
    x: window.pageXOffset,
    y: window.pageYOffset
  }))
}

function getScrollPosition (): ?{ x: number, y: number } {
  if (!_key) return
  return JSON.parse(window.sessionStorage.getItem(_key))
}
<commit_msg>fix history mode base<commit_after>/* @flow */

import type VueRouter from '../index'
import { cleanPath } from '../util/path'
import { History } from './base'

const genKey = () => String(Date.now())
let _key: string = genKey()

export class HTML5History extends History {
  constructor (router: VueRouter, base: ?string) {
    super(router, base)

    // possible redirect on start
    if (this.getLocation() !== this.current.fullPath) {
      replaceState(this.current.fullPath)
    }

    const expectScroll = router.options.scrollBehavior

    window.addEventListener('popstate', e => {
      _key = e.state && e.state.key
      const current = this.current
      this.transitionTo(this.getLocation(), next => {
        if (expectScroll) {
          this.handleScroll(current, next)
        }
      })
    })

    if (expectScroll) {
      _key = genKey()
      window.addEventListener('scroll', saveScrollPosition)
    }
  }

  go (n: number) {
    window.history.go(n)
  }

  push (location: RawLocation) {
    super.push(location, route => {
      const url = cleanPath(this.base + route.fullPath)
      pushState(url)
    })
  }

  replace (location: RawLocation) {
    super.replace(location, route => {
      const url = cleanPath(this.base + route.fullPath)
      replaceState(url)
    })
  }

  getLocation (): string {
    return getLocation(this.base)
  }

  handleScroll (from: Route, to: Route) {
    const router = this.router
    if (!router.app) {
      return
    }

    let shouldScroll = false
    const behavior = router.options.scrollBehavior
    if (typeof behavior === 'boolean') {
      shouldScroll = behavior
    } else if (typeof behavior === 'function') {
      shouldScroll = behavior(from, to)
    }

    if (!shouldScroll) {
      return
    }

    let position = getScrollPosition()
    if (typeof shouldScroll === 'object' &&
        shouldScroll.x != null &&
        shouldScroll.y != null) {
      position = shouldScroll
    }
    if (position) {
      const { x, y } = position
      router.app.$nextTick(() => {
        window.scrollTo(x, y)
      })
    }
  }
}

export function getLocation (base: string): string {
  let path = window.location.pathname
  if (base && path.indexOf(base) === 0) {
    path = path.slice(base.length)
  }
  return path + window.location.search + window.location.hash
}

function pushState (url: string, replace?: boolean) {
  // try...catch the pushState call to get around Safari
  // DOM Exception 18 where it limits to 100 pushState calls
  const history = window.history
  try {
    if (replace) {
      history.replaceState({ key: _key }, '', url)
    } else {
      _key = genKey()
      history.pushState({ key: _key }, '', url)
    }
    saveScrollPosition()
  } catch (e) {
    window.location[replace ? 'assign' : 'replace'](url)
  }
}

function replaceState (url: string) {
  pushState(url, true)
}

function saveScrollPosition () {
  if (!_key) return
  window.sessionStorage.setItem(_key, JSON.stringify({
    x: window.pageXOffset,
    y: window.pageYOffset
  }))
}

function getScrollPosition (): ?{ x: number, y: number } {
  if (!_key) return
  return JSON.parse(window.sessionStorage.getItem(_key))
}
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {Wrapper as FormsyHOC} from 'formsy-react';
import styleClassNames from '../components/prop-types';

function getDisplayName(component) {
  return (
    component.displayName ||
    component.name ||
    (typeof component === 'string' ? component : 'Component')
  );
}

// Component HOC
// -------------
//
// This HOC provides shared code for our form components.
//
// We use this to merge props set using our OptionsProvider, so that
// we can set commonly used props on an enclosing component.
//
// This allows us to set these properties 'as a whole' for each component in the
// the form, while retaining the ability to override the prop on a per-component
// basis.
const FormsyReactComponent = ComposedComponent => {
  class ComponentHOC extends Component {
    // Use the following value for layout:
    // 1. layout prop (if supplied)
    // 2. [else] layout context (if defined)
    // 3. [else] 'horizontal' (default value)
    getLayout = () =>
      this.props.layout || (this.context.layout || 'horizontal');

    // Use the following value for validatePristine:
    // 1. validatePristine prop (if supplied)
    // 2. [else] validatePristine context (if defined)
    // 3. [else] false (default value)
    getValidatePristine = () => {
      if (typeof this.props.validatePristine === 'boolean') {
        return this.props.validatePristine;
      }
      return this.context.validatePristine || false;
    };

    // Use the following value for validateOnSubmit:
    // 1. validateOnSubmit prop (if supplied)
    // 2. [else] validateOnSubmit context (if defined)
    // 3. [else] false (default value)
    getValidateOnSubmit = () => {
      if (typeof this.props.validateOnSubmit === 'boolean') {
        return this.props.validateOnSubmit;
      }
      return this.context.validateOnSubmit || false;
    };

    // getId
    // -----
    //
    // The ID is used as an attribute on the form control, and is used to allow
    // associating the label element with the form control.
    //
    // If we don't explicitly pass an `id` prop, we generate one based on the
    // `name` and `label` properties.
    getId = () => {
      const {id, label, name} = this.props;
      if (id !== '') {
        return id;
      }
      return [
        'frc',
        name
          .split('[')
          .join('_')
          .replace(']', ''),
        this.hashString(JSON.stringify(label)),
      ].join('-');
    };

    // Combine a parent context value with a component prop value.
    // This is used for CSS classnames, where the value is passed to `JedWatson/classnames`.
    combineContextWithProp = key => [this.context[key], this.props[key]];

    hashString = string => {
      let hash = 0;
      for (let i = 0; i < string.length; i += 1) {
        // eslint-disable-next-line no-bitwise
        hash = ((hash << 5) - hash + string.charCodeAt(i)) & 0xffffffff;
      }
      return hash;
    };

    // Determine whether to show errors, or not.
    shouldShowErrors = () => {
      if (this.props.isPristine() === true) {
        if (this.getValidatePristine() === false) {
          return false;
        }
      }
      if (this.getValidateOnSubmit() === true) {
        if (this.props.isFormSubmitted() === false) {
          return false;
        }
      }
      return this.props.isValid() === false;
    };

    // We pass through all unknown props, but delete some formsy HOC props
    // that we know we don't need.
    render() {
      const cssProps = {
        elementWrapperClassName: this.combineContextWithProp(
          'elementWrapperClassName',
        ),
        labelClassName: this.combineContextWithProp('labelClassName'),
        rowClassName: this.combineContextWithProp('rowClassName'),
      };

      const props = {
        ...this.props,
        ...cssProps,
        disabled: this.props.isFormDisabled() || this.props.disabled,
        errorMessages: this.props.getErrorMessages(),
        id: this.getId(),
        layout: this.getLayout(),
        ref: this.props.componentRef,
        required: this.props.isRequired(),
        showErrors: this.shouldShowErrors(),
        value: this.props.getValue(),
        onSetValue: this.props.setValue,
      };

      // Formsy HOC props we don't use.
      delete props.getErrorMessage;
      delete props.getErrorMessages;
      delete props.getValue;
      delete props.hasValue;
      delete props.isFormDisabled;
      delete props.isFormSubmitted;
      delete props.isRequired;
      delete props.isValid;
      delete props.isValidValue;
      delete props.resetValue;
      delete props.setValidations;
      delete props.setValue;
      delete props.showError;
      delete props.showRequired;

      // Formsy props we don't use
      delete props.validationError;
      delete props.validationErrors;
      delete props.validations;

      // HOC refs
      delete props.innerRef;
      delete props.componentRef;

      // These props aren't used by child components, they are only used by
      // `shouldShowErrors` in this HOC.
      delete props.validateOnSubmit;
      delete props.validatePristine;

      return <ComposedComponent {...props} />;
    }
  }

  // These are the props that we require from the formsy-react HOC.
  // There are others, but as we don't use them, we don't need to define their PropTypes.
  const formsyPropTypes = {
    getErrorMessages: PropTypes.func.isRequired,
    getValue: PropTypes.func.isRequired,
    isFormDisabled: PropTypes.func.isRequired,
    isPristine: PropTypes.func.isRequired,
    isRequired: PropTypes.func.isRequired,
    isValid: PropTypes.func.isRequired,
    setValue: PropTypes.func.isRequired,
  };

  ComponentHOC.propTypes = {
    ...formsyPropTypes,
    ...styleClassNames,

    name: PropTypes.string.isRequired,
    disabled: PropTypes.bool,

    // Composed components expect this to be a string.
    help: PropTypes.string,

    id: PropTypes.string,
    label: PropTypes.string,
    layout: PropTypes.string,

    // * validateOnSubmit
    // * validatePristine
    //
    // Neither of these props actually stop the validations from running,
    // they just determine whether the error messages should be shown on
    // components or not.

    // Whether to hide validation errors on components before the form is
    // submitted.
    validateOnSubmit: PropTypes.bool,

    // Whether to show validation errors on pristine (untouched) components.
    validatePristine: PropTypes.bool,
  };

  ComponentHOC.contextTypes = {
    ...styleClassNames,
    layout: PropTypes.string,
    validateOnSubmit: PropTypes.bool,
    validatePristine: PropTypes.bool,
  };

  // TODO: Should we add default props for the following?:
  // * elementWrapperClassName
  // * labelClassName
  // * rowClassName

  // The following props get their default values by first looking for props in the parent context.
  // * layout (See getLayout, defaults to 'horizontal')
  // * validatePristine: (See getValidatePristine, defaults to 'false'),
  // * validateOnSubmit: (See getValidateOnSubmit, defaults to 'false'),
  ComponentHOC.defaultProps = {
    disabled: false,
    help: '',
    id: '',
    label: '',
    layout: '',
    validateOnSubmit: null,
    validatePristine: null,
  };

  ComponentHOC.displayName = `withFRC(${getDisplayName(ComposedComponent)})`;

  return FormsyHOC(ComponentHOC);
};

export default FormsyReactComponent;
<commit_msg>refactor: Tweak proptype definitions.<commit_after>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {Wrapper as FormsyHOC} from 'formsy-react';
import styleClassNames from '../components/prop-types';

function getDisplayName(component) {
  return (
    component.displayName ||
    component.name ||
    (typeof component === 'string' ? component : 'Component')
  );
}

// Component HOC
// -------------
//
// This HOC provides shared code for our form components.
//
// We use this to merge props set using our OptionsProvider, so that
// we can set commonly used props on an enclosing component.
//
// This allows us to set these properties 'as a whole' for each component in the
// the form, while retaining the ability to override the prop on a per-component
// basis.
const FormsyReactComponent = ComposedComponent => {
  class ComponentHOC extends Component {
    // Use the following value for layout:
    // 1. layout prop (if supplied)
    // 2. [else] layout context (if defined)
    // 3. [else] 'horizontal' (default value)
    getLayout = () =>
      this.props.layout || (this.context.layout || 'horizontal');

    // Use the following value for validatePristine:
    // 1. validatePristine prop (if supplied)
    // 2. [else] validatePristine context (if defined)
    // 3. [else] false (default value)
    getValidatePristine = () => {
      if (typeof this.props.validatePristine === 'boolean') {
        return this.props.validatePristine;
      }
      return this.context.validatePristine || false;
    };

    // Use the following value for validateOnSubmit:
    // 1. validateOnSubmit prop (if supplied)
    // 2. [else] validateOnSubmit context (if defined)
    // 3. [else] false (default value)
    getValidateOnSubmit = () => {
      if (typeof this.props.validateOnSubmit === 'boolean') {
        return this.props.validateOnSubmit;
      }
      return this.context.validateOnSubmit || false;
    };

    // getId
    // -----
    //
    // The ID is used as an attribute on the form control, and is used to allow
    // associating the label element with the form control.
    //
    // If we don't explicitly pass an `id` prop, we generate one based on the
    // `name` and `label` properties.
    getId = () => {
      const {id, label, name} = this.props;
      if (id !== '') {
        return id;
      }
      return [
        'frc',
        name
          .split('[')
          .join('_')
          .replace(']', ''),
        this.hashString(JSON.stringify(label)),
      ].join('-');
    };

    // Combine a parent context value with a component prop value.
    // This is used for CSS classnames, where the value is passed to `JedWatson/classnames`.
    combineContextWithProp = key => [this.context[key], this.props[key]];

    hashString = string => {
      let hash = 0;
      for (let i = 0; i < string.length; i += 1) {
        // eslint-disable-next-line no-bitwise
        hash = ((hash << 5) - hash + string.charCodeAt(i)) & 0xffffffff;
      }
      return hash;
    };

    // Determine whether to show errors, or not.
    shouldShowErrors = () => {
      if (this.props.isPristine() === true) {
        if (this.getValidatePristine() === false) {
          return false;
        }
      }
      if (this.getValidateOnSubmit() === true) {
        if (this.props.isFormSubmitted() === false) {
          return false;
        }
      }
      return this.props.isValid() === false;
    };

    // We pass through all unknown props, but delete some formsy HOC props
    // that we know we don't need.
    render() {
      const props = {
        ...this.props,
        elementWrapperClassName: this.combineContextWithProp(
          'elementWrapperClassName',
        ),
        labelClassName: this.combineContextWithProp('labelClassName'),
        rowClassName: this.combineContextWithProp('rowClassName'),
        disabled: this.props.isFormDisabled() || this.props.disabled,
        errorMessages: this.props.getErrorMessages(),
        id: this.getId(),
        layout: this.getLayout(),
        ref: this.props.componentRef,
        required: this.props.isRequired(),
        showErrors: this.shouldShowErrors(),
        value: this.props.getValue(),
        onSetValue: this.props.setValue,
      };

      // Props that we don't need to pass to our composed components.
      const unusedPropNames = [
        // From formsy-react HOC...
        'getErrorMessage',
        'getErrorMessages',
        'getValue',
        'hasValue',
        'isFormDisabled',
        'isFormSubmitted',
        'isRequired',
        'isValid',
        'isValidValue',
        'resetValue',
        'setValidations',
        'setValue',
        'showError',
        'showRequired',
        'validationError',
        'validationErrors',
        'validations',
        'innerRef',
        // From formsy-react-component HOC...
        'componentRef',
        'validateOnSubmit',
        'validatePristine',
      ];

      unusedPropNames.forEach(propName => {
        delete props[propName];
      });

      return <ComposedComponent {...props} />;
    }
  }

  ComponentHOC.propTypes = {
    // These are the props that we require from the formsy-react HOC.
    getErrorMessages: PropTypes.func.isRequired,
    getValue: PropTypes.func.isRequired,
    isFormDisabled: PropTypes.func.isRequired,
    isPristine: PropTypes.func.isRequired,
    isRequired: PropTypes.func.isRequired,
    isValid: PropTypes.func.isRequired,
    setValue: PropTypes.func.isRequired,
    // End of formsy-react HOC props.

    ...styleClassNames,

    name: PropTypes.string.isRequired,
    disabled: PropTypes.bool,

    // Composed components expect this to be a string.
    help: PropTypes.string,

    id: PropTypes.string,
    label: PropTypes.string,
    layout: PropTypes.string,

    // * validateOnSubmit
    // * validatePristine
    //
    // Neither of these props actually stop the validations from running,
    // they just determine whether the error messages should be shown on
    // components or not.

    // Whether to hide validation errors on components before the form is
    // submitted.
    validateOnSubmit: PropTypes.bool,

    // Whether to show validation errors on pristine (untouched) components.
    validatePristine: PropTypes.bool,
  };

  ComponentHOC.contextTypes = {
    ...styleClassNames,
    layout: PropTypes.string,
    validateOnSubmit: PropTypes.bool,
    validatePristine: PropTypes.bool,
  };

  // TODO: Should we add default props for the following?:
  // * elementWrapperClassName
  // * labelClassName
  // * rowClassName

  // The following props get their default values by first looking for props in the parent context.
  // * layout (See getLayout, defaults to 'horizontal')
  // * validatePristine: (See getValidatePristine, defaults to 'false'),
  // * validateOnSubmit: (See getValidateOnSubmit, defaults to 'false'),
  ComponentHOC.defaultProps = {
    disabled: false,
    help: '',
    id: '',
    label: '',
    layout: '',
    validateOnSubmit: null,
    validatePristine: null,
  };

  ComponentHOC.displayName = `withFRC(${getDisplayName(ComposedComponent)})`;

  return FormsyHOC(ComponentHOC);
};

export default FormsyReactComponent;
<|endoftext|>


<commit_before>import _ from 'underscore'
const Author = require('api/apps/authors/model.coffee')
const Channel = require('api/apps/channels/model.coffee')
const Curation = require('api/apps/curations/model.coffee')
const Tag = require('api/apps/tags/model.coffee')
const User = require('api/apps/users/model.coffee')
const { promisedMongoFetch, mongoFetch, present, presentCollection, find } = require('api/apps/articles/model/index.js')
const { ObjectId } = require('mongojs')
const { DISPLAY_ID } = process.env
const debug = require('debug')('api')

export const articles = (root, args, req, ast) => {
  const unpublished = !args.published || args.scheduled
  if (unpublished && !args.channel_id) {
    throw new Error('Must pass channel_id to view unpublished articles. Or pass ' +
      'published: true to only view published articles.'
    )
  }

  const unauthorized = !User.hasChannelAccess(req.user, args.channel_id)
  if (unpublished && unauthorized) {
    throw new Error('Must be a member of this channel to view unpublished articles. ' +
      'Pass published: true to only view published articles.'
    )
  }
  return new Promise((resolve, reject) => {
    mongoFetch(args, (err, res) => {
      if (err) {
        reject(new Error('Articles not found.'))
      }
      resolve(presentCollection(res).results)
    })
  })
}

export const article = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    find(args.id, (err, result) => {
      if (err) {
        reject(new Error(err))
      }
      if (result) {
        const unpublished = !result.published || result.scheduled_publish_at
        const unauthorized = !User.hasChannelAccess(req.user, result.channel_id)
        if (unpublished && unauthorized) {
          reject(new Error('Must be a member of the channel to view an unpublished article.'))
        } else {
          resolve(present(result))
        }
      } else {
        reject(new Error('Article not found.'))
      }
    })
  })
}

export const authors = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    Author.mongoFetch(args, (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      resolve(results.results)
    })
  })
}

export const curations = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    Curation.mongoFetch(args, (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      resolve(results.results)
    })
  })
}

export const channels = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    Channel.mongoFetch(args, (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      resolve(results.results)
    })
  })
}

export const display = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    Curation.mongoFetch({ '_id': ObjectId(DISPLAY_ID) }, (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      const outcomes = []
      results.results[0].campaigns.map(campaign => {
        outcomes.push(_.times((campaign.sov * 100), () => campaign.name))
      })
      const result = _.sample(_.flatten(outcomes))
      const data = _.findWhere(results.results[0].campaigns, { name: result })
      resolve(data)
    })
  })
}

export const relatedArticlesPanel = (root) => {
  const omittedIds = [ObjectId(root.id)]
  if (root.related_articles_ids) {
    omittedIds.concat(root.related_article_ids)
  }
  const tags = root.tags || null
  const args = {
    omit: omittedIds,
    published: true,
    featured: true,
    channel_id: ObjectId(root.channel_id),
    tags: tags,
    limit: 3,
    sort: '-published_at'
  }
  const relatedArticleArgs = {
    ids: root.related_article_ids,
    limit: 3,
    published: true
  }

  return new Promise(async (resolve, reject) => {
    let relatedArticles = []

    const articleResults = await promisedMongoFetch(_.pick(args, _.identity))
    .catch((e) => reject(e))

    if (root.related_article_ids && root.related_article_ids.length) {
      const relatedArticleResults = await promisedMongoFetch(relatedArticleArgs)
      .catch((e) => reject(e))
      relatedArticles = _.first(relatedArticleResults.results.concat(articleResults.results), 3)
    } else {
      relatedArticles = articleResults.results
    }

    if (relatedArticles.length) {
      resolve(relatedArticles)
    } else {
      reject(new Error('No Results'))
    }
  })
}

export const relatedArticlesCanvas = (root) => {
  const vertical = root.vertical && root.vertical.id ? ObjectId(root.vertical.id) : null
  const args = {
    omit: [ObjectId(root.id)],
    published: true,
    featured: true,
    channel_id: ObjectId(root.channel_id),
    vertical,
    limit: 4,
    sort: '-published_at'
  }
  return new Promise((resolve, reject) => {
    mongoFetch(_.pick(args, _.identity), (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      resolve(results.results)
    })
  })
}

export const tags = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    Tag.mongoFetch(args, (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      resolve(results.results)
    })
  })
}
<commit_msg>Remove debug<commit_after>import _ from 'underscore'
const Author = require('api/apps/authors/model.coffee')
const Channel = require('api/apps/channels/model.coffee')
const Curation = require('api/apps/curations/model.coffee')
const Tag = require('api/apps/tags/model.coffee')
const User = require('api/apps/users/model.coffee')
const { promisedMongoFetch, mongoFetch, present, presentCollection, find } = require('api/apps/articles/model/index.js')
const { ObjectId } = require('mongojs')
const { DISPLAY_ID } = process.env

export const articles = (root, args, req, ast) => {
  const unpublished = !args.published || args.scheduled
  if (unpublished && !args.channel_id) {
    throw new Error('Must pass channel_id to view unpublished articles. Or pass ' +
      'published: true to only view published articles.'
    )
  }

  const unauthorized = !User.hasChannelAccess(req.user, args.channel_id)
  if (unpublished && unauthorized) {
    throw new Error('Must be a member of this channel to view unpublished articles. ' +
      'Pass published: true to only view published articles.'
    )
  }
  return new Promise((resolve, reject) => {
    mongoFetch(args, (err, res) => {
      if (err) {
        reject(new Error('Articles not found.'))
      }
      resolve(presentCollection(res).results)
    })
  })
}

export const article = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    find(args.id, (err, result) => {
      if (err) {
        reject(new Error(err))
      }
      if (result) {
        const unpublished = !result.published || result.scheduled_publish_at
        const unauthorized = !User.hasChannelAccess(req.user, result.channel_id)
        if (unpublished && unauthorized) {
          reject(new Error('Must be a member of the channel to view an unpublished article.'))
        } else {
          resolve(present(result))
        }
      } else {
        reject(new Error('Article not found.'))
      }
    })
  })
}

export const authors = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    Author.mongoFetch(args, (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      resolve(results.results)
    })
  })
}

export const curations = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    Curation.mongoFetch(args, (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      resolve(results.results)
    })
  })
}

export const channels = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    Channel.mongoFetch(args, (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      resolve(results.results)
    })
  })
}

export const display = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    Curation.mongoFetch({ '_id': ObjectId(DISPLAY_ID) }, (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      const outcomes = []
      results.results[0].campaigns.map(campaign => {
        outcomes.push(_.times((campaign.sov * 100), () => campaign.name))
      })
      const result = _.sample(_.flatten(outcomes))
      const data = _.findWhere(results.results[0].campaigns, { name: result })
      resolve(data)
    })
  })
}

export const relatedArticlesPanel = (root) => {
  const omittedIds = [ObjectId(root.id)]
  if (root.related_articles_ids) {
    omittedIds.concat(root.related_article_ids)
  }
  const tags = root.tags || null
  const args = {
    omit: omittedIds,
    published: true,
    featured: true,
    channel_id: ObjectId(root.channel_id),
    tags: tags,
    limit: 3,
    sort: '-published_at'
  }
  const relatedArticleArgs = {
    ids: root.related_article_ids,
    limit: 3,
    published: true
  }

  return new Promise(async (resolve, reject) => {
    let relatedArticles = []

    const articleResults = await promisedMongoFetch(_.pick(args, _.identity))
    .catch((e) => reject(e))

    if (root.related_article_ids && root.related_article_ids.length) {
      const relatedArticleResults = await promisedMongoFetch(relatedArticleArgs)
      .catch((e) => reject(e))
      relatedArticles = _.first(relatedArticleResults.results.concat(articleResults.results), 3)
    } else {
      relatedArticles = articleResults.results
    }

    if (relatedArticles.length) {
      resolve(relatedArticles)
    } else {
      reject(new Error('No Results'))
    }
  })
}

export const relatedArticlesCanvas = (root) => {
  const vertical = root.vertical && root.vertical.id ? ObjectId(root.vertical.id) : null
  const args = {
    omit: [ObjectId(root.id)],
    published: true,
    featured: true,
    channel_id: ObjectId(root.channel_id),
    vertical,
    limit: 4,
    sort: '-published_at'
  }
  return new Promise((resolve, reject) => {
    mongoFetch(_.pick(args, _.identity), (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      resolve(results.results)
    })
  })
}

export const tags = (root, args, req, ast) => {
  return new Promise((resolve, reject) => {
    Tag.mongoFetch(args, (err, results) => {
      if (err) {
        reject(new Error(err))
      }
      resolve(results.results)
    })
  })
}
<|endoftext|>


<commit_before>'use strict';

var mongoose = require('mongoose'),
  User = mongoose.model('User');

exports.list_all_users = function(req, res) {
  User.find({}, function(err, user) {
    if (err)
      res.send(err);
    res.json(user);
  });
};

exports.create_user = function(req, res) {
  var new_user = new User(req.body);
  new_user.save(function(err, user) {
    if (err)
      res.send(err);
    res.json(user);
  });
};

exports.find_user = function(req, res) {
  var query = {};
  query['username'] = req.params.username;
  User.findOne(query, function(err, user) {
    if (err)
      res.send(err);
    res.json(user);
  });
};

exports.update_user = function(req, res) {
  User.findOneAndUpdate(req.params.taskId, req.body, {new: true}, function(err, user) {
    if (err)
      res.send(err);
    res.json(user);
  });
};

exports.delete_user = function(req, res) {

  User.remove({
    username: req.params.username
  }, function(err, user) {
    if (err)
      res.send(err);
    res.json({ message: 'User successfully deleted' });
  });
};
<commit_msg>Fix for delete user<commit_after>'use strict';

var mongoose = require('mongoose'),
  User = mongoose.model('User');

exports.list_all_users = function(req, res) {
  User.find({}, function(err, user) {
    if (err)
      res.send(err);
    res.json(user);
  });
};

exports.create_user = function(req, res) {
  var new_user = new User(req.body);
  new_user.save(function(err, user) {
    if (err)
      res.send(err);
    res.json(user);
  });
};

exports.find_user = function(req, res) {
  var query = {};
  query['username'] = req.params.username;
  User.findOne(query, function(err, user) {
    if (err)
      res.send(err);
    res.json(user);
  });
};

exports.update_user = function(req, res) {
  User.findOneAndUpdate(req.params.taskId, req.body, {new: true}, function(err, user) {
    if (err)
      res.send(err);
    res.json(user);
  });
};

exports.delete_user = function(req, res) {
  var query = {};
  query['username'] = req.params.username;
  User.findOne(query, function(err, user) {
    if (err)
      res.send(err);
    else{
      if(user != null) {
        User.remove({username: req.params.username}, function(err, user) {
          if (err){
            res.send(err);
          }
          res.json({ message: 'User successfully deleted' });
        });
      }
      else {
        res.json({message: 'User does not exist'});
      }
    }
  });
};
<|endoftext|>