<commit_before>var Vue = require('vue');
var Color = require('color');
var insertCss = require('insert-css');
var bind = require('component-bind');
var escape = require('escape-html');
var is = require('is');
var dom = require('vue/src/util/dom');

var MESSAGES = require('./messages');

insertCss(require('./index.scss'));

var COLORS = {
  gray: '#666',
  pink: '#ff4981',
  green: '#4CD964',
  blue: '#007AFF',
  red: '#FF3A2D',
  yellow: '#FFCC00',
  orange: '#FF9500',
  violet: '#C643FC',
  lightBlue: '#3FA2D9',
  darkGreen: '#2FB12C'
};

var RATING_STATE = 'rating';
var FEEDBACK_STATE = 'feedback';
var THANKS_STATE = 'thanks';
var FILLED_STATE = 'filled';

var DIALOG_SKIN = 'dialog';
var PANEL_SKIN = 'panel';
var BAR_SKIN = 'bar';

var Survey = Vue.extend({
  template: require('./survey.html'),
  partials: {
    rating: require('./rating.html'),
    feedback: require('./feedback.html'),
    thanks: require('./thanks.html'),
    filled: require('./filled.html'),
    'powered-by': require('./powered-by.html'),
    panel: require('./panel.html'),
    dialog: require('./dialog.html'),
    bar: require('./bar.html')
  },
  components: {
    'nps-textarea': require('./components/textarea'),
    'nps-button': require('./components/button'),
    'nps-link': require('./components/link'),
    'nps-scale': require('./components/scale'),
  },
  replace: true,
  data: function() {
    return {
      // model
      rating: null,
      feedback: '',
      reason: '',
      answers: [],

      // state
      visible: false,
      state: RATING_STATE,
      translation: null,

      // settings
      serviceName: null,
      poweredBy: true,
      skin: DIALOG_SKIN,
      preview: false, // preview mode - positioned inside a preview div
      position: 'cr', // tl (top-right), tr, bl, br
      test: false,
      showNumbers: false,
      colors: {
        background: '#FDFDFD',
        foreground: '#333',
        primary: '#ff4981',
      }
    };
  },
  computed: {
    questions: function() {
      return this.t('QUESTIONS') || [];
    },
    showCloseIcon: function() {
      return this.state === FEEDBACK_STATE || this.state === RATING_STATE;
    },
    showFeedbackText: function() {
      return this.state === FEEDBACK_STATE;
    },
    ratings: function() {
      return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(bind(this, function(rating) {
        var isHighlighted = is.number(this.visibleRating) && rating <= this.visibleRating;
        return {
          rating: rating,
          color: (isHighlighted) ? c('primary') : c('light')
        };
      }));
    },
    likelyHtml: function() {
      var serviceName = is.string(this.serviceName) ? this.serviceName.trim() : null;
      var howLikelyUs = this.t('HOW_LIKELY_US');
      var howLikely = this.t('HOW_LIKELY');

      if (!serviceName && howLikelyUs) {
        return escape(howLikelyUs);
      }

      var serviceHtml = serviceName ? '' + escape(serviceName) + '' : this.t('US');
      return '' + escape(howLikely).replace('%s', serviceHtml) + '';
    },

    poweredByHtml: function() {
      var linkHtml = 'SatisMeter';
      return escape(this.t('POWERED_BY')).replace('%s', linkHtml);
    },

    hasReasons: function() {
      var reasons = this.t('REASONS');
      return reasons && reasons.length > 0;
    },
    hasQuestions: function() {
      var questions = this.t('QUESTIONS');
      return questions && questions.length > 0;
    },
    vertical: function() {
      switch (this.position[0]) {
        case 'b':
          return 'bottom';
        case 't':
          return 'top';
        default:
          return 'middle';
      }
    },
    horizontal: function() {
      switch (this.position[1]) {
        case 'l':
          return 'left';
        case 'r':
          return 'right';
        default:
          return 'center';
      }
    },
    previewClass: function() {
      if (this.preview) {
        return 'nps-preview';
      }
      return '';
    },
    category: function() {
      if (!is.number(this.rating)) {
        return null;
      }
      if (this.rating <= 6) {
        return 'detractor';
      }
      if (this.rating <= 8) {
        return 'passive';
      }
      return 'promoter'
    },
    direction: function() {
      return this._t('DIRECTION') || 'ltr';
    }
  },
  ready: function() {
      this.initAnswers();
  },
  watch: {
    questions: function() {
      this.initAnswers();
    }
  },
  methods: {
    initAnswers: function() {
      this.answers = this.questions.map(function(question) {
        return {
          name: question.name,
          label: question.label,
          value: null
        };
      });
    },
    inState: function() {
      var states = Array.prototype.slice.call(arguments);
      return states.indexOf(this.state) !== -1;
    },
    nextTick: function(fn) {
      Vue.nextTick(bind(this, function() {
        if (this._isDestroyed) {
          return;
        }
        fn.call(this);
      }));
    },
    setTimeout: function(fn, timeout) {
      setTimeout(bind(this, function() {
        if (this._isDestroyed) {
          return;
        }
        fn.call(this);
      }), timeout);
    },
    _t: function(key, param) {
      if (this.translation) {
        if (this.translation[key]) {
          return this.translation[key];
        }
      }
      return MESSAGES[key];
    },
    t: function(key, param) {
      var value;
      if (key === 'FOLLOWUP') {
        value = this.t('IMPROVE');
        if (value) {
          return value;
        }
        value = this.t('THANKS_IMPROVE');
        if (value) {
          return value;
        }
      }
      if (this.category) {
        value = this._t(key + '_' + this.category.toUpperCase());
        if (value) {
          return value;
        }
      }
      return this._t(key, value);
    },
    _c: function(type) {
      if (this.colors[type]) {
        return this.colors[type];
      }
      if (type === 'light') {
        return Color(this.colors.primary).mix(Color(this.colors.background), 0.4).hexString();
      }
      if (type === 'background-light') {
        return Color(this.colors.primary).mix(Color(this.colors.background), 0.04).hexString();
      }
      if (type === 'foreground-light') {
        return Color(this.colors.foreground).mix(Color(this.colors.background), 0.6).hexString();
      }
      if (type === 'shadow') {
        return Color(this.colors.foreground).mix(Color(this.colors.background), 0.1).hexString();
      }
      if (type === 'border') {
        return Color(this.colors.foreground).mix(Color(this.colors.background), 0.15).hexString();
      }
    },
    c: function(type) {
      var color = this._c(type);
      if (color && COLORS[color]) {
        return COLORS[color];
      }
      return color;
    },
    show: function() {
      this.visible = true;
    },
    hide: function() {
      this.visible = false;
    },
    stopPropagation: function(e) {
      e.stopPropagation();
    },
    legend(section, index) {
      var question = this.questions[index];
      if (section === 'low') {
        return (question && question.lowLegend) || this.t('LOW_LEGEND');
      }
      else {
        return (question && question.highLegend) || this.t('HIGH_LEGEND');
      }
    }
  },
  events: {
    submit: function() {
      this.$dispatch('submit');
      this.state = THANKS_STATE;
      if (this.skin === DIALOG_SKIN || this.skin === BAR_SKIN) {
        this.setTimeout(function() {
          this.hide();
        }, 800);
      }
    },
    selectRating: function (rating) {
      this.rating = rating;
      this.state = FEEDBACK_STATE;
      this.$emit('ratingSelect');
      this.setTimeout(function() {
        if (this.hasReasons) {
          this.$$.reasons[0].focus();
        }
        else if (this.hasQuestions) {
          // do nothing
        }
        else {
          this.$.feedback.focus();
        }
      }, 400);
    },
    close: function() {
      this.hide();
      this.$emit('dismiss');
    },
  },
  transitions: {
    next: {
      leave: function(el, done) {
        if (this.test) {
          return done();
        }
        if (!this.visible) {
          return done();
        }
        this.leave = el;
        this.setTimeout(function() {
          done();
          delete this.leave;
        }, 600);
      },
      enter: function(enter, done) {
        if (this.test) {
          return done();
        }
        if (!this.visible) {
          return done();
        }
        var content = enter.parentNode;
        var bounding = content.parentNode;
        var leave = this.leave;

        bounding.style.height = getComputedStyle(leave || enter).height;
        content.style.top = 0;
        if (leave) {
          leave.style.opacity = 1;
        }

        this.setTimeout(function() {
          dom.addClass(bounding, 'nps-next');
          this.setTimeout(function() {
            content.style.top = '-' + bounding.style.height;
            bounding.style.height = getComputedStyle(enter).height;
            if (leave) {
              leave.style.opacity = 0;
            }

            this.setTimeout(function() {
              dom.removeClass(bounding, 'nps-next');
              content.style.top = '';
              if (leave) {
                leave.style.display = 'none';
              }
              bounding.style.height = '';
              done();
            }, 500);
          }, 0);
        }, 0);
      }
    }
  }
});

module.exports = Survey;
<commit_msg>remove redundant param<commit_after>var Vue = require('vue');
var Color = require('color');
var insertCss = require('insert-css');
var bind = require('component-bind');
var escape = require('escape-html');
var is = require('is');
var dom = require('vue/src/util/dom');

var MESSAGES = require('./messages');

insertCss(require('./index.scss'));

var COLORS = {
  gray: '#666',
  pink: '#ff4981',
  green: '#4CD964',
  blue: '#007AFF',
  red: '#FF3A2D',
  yellow: '#FFCC00',
  orange: '#FF9500',
  violet: '#C643FC',
  lightBlue: '#3FA2D9',
  darkGreen: '#2FB12C'
};

var RATING_STATE = 'rating';
var FEEDBACK_STATE = 'feedback';
var THANKS_STATE = 'thanks';
var FILLED_STATE = 'filled';

var DIALOG_SKIN = 'dialog';
var PANEL_SKIN = 'panel';
var BAR_SKIN = 'bar';

var Survey = Vue.extend({
  template: require('./survey.html'),
  partials: {
    rating: require('./rating.html'),
    feedback: require('./feedback.html'),
    thanks: require('./thanks.html'),
    filled: require('./filled.html'),
    'powered-by': require('./powered-by.html'),
    panel: require('./panel.html'),
    dialog: require('./dialog.html'),
    bar: require('./bar.html')
  },
  components: {
    'nps-textarea': require('./components/textarea'),
    'nps-button': require('./components/button'),
    'nps-link': require('./components/link'),
    'nps-scale': require('./components/scale'),
  },
  replace: true,
  data: function() {
    return {
      // model
      rating: null,
      feedback: '',
      reason: '',
      answers: [],

      // state
      visible: false,
      state: RATING_STATE,
      translation: null,

      // settings
      serviceName: null,
      poweredBy: true,
      skin: DIALOG_SKIN,
      preview: false, // preview mode - positioned inside a preview div
      position: 'cr', // tl (top-right), tr, bl, br
      test: false,
      showNumbers: false,
      colors: {
        background: '#FDFDFD',
        foreground: '#333',
        primary: '#ff4981',
      }
    };
  },
  computed: {
    questions: function() {
      return this.t('QUESTIONS') || [];
    },
    showCloseIcon: function() {
      return this.state === FEEDBACK_STATE || this.state === RATING_STATE;
    },
    showFeedbackText: function() {
      return this.state === FEEDBACK_STATE;
    },
    ratings: function() {
      return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(bind(this, function(rating) {
        var isHighlighted = is.number(this.visibleRating) && rating <= this.visibleRating;
        return {
          rating: rating,
          color: (isHighlighted) ? c('primary') : c('light')
        };
      }));
    },
    likelyHtml: function() {
      var serviceName = is.string(this.serviceName) ? this.serviceName.trim() : null;
      var howLikelyUs = this.t('HOW_LIKELY_US');
      var howLikely = this.t('HOW_LIKELY');

      if (!serviceName && howLikelyUs) {
        return escape(howLikelyUs);
      }

      var serviceHtml = serviceName ? '' + escape(serviceName) + '' : this.t('US');
      return '' + escape(howLikely).replace('%s', serviceHtml) + '';
    },

    poweredByHtml: function() {
      var linkHtml = 'SatisMeter';
      return escape(this.t('POWERED_BY')).replace('%s', linkHtml);
    },

    hasReasons: function() {
      var reasons = this.t('REASONS');
      return reasons && reasons.length > 0;
    },
    hasQuestions: function() {
      var questions = this.t('QUESTIONS');
      return questions && questions.length > 0;
    },
    vertical: function() {
      switch (this.position[0]) {
        case 'b':
          return 'bottom';
        case 't':
          return 'top';
        default:
          return 'middle';
      }
    },
    horizontal: function() {
      switch (this.position[1]) {
        case 'l':
          return 'left';
        case 'r':
          return 'right';
        default:
          return 'center';
      }
    },
    previewClass: function() {
      if (this.preview) {
        return 'nps-preview';
      }
      return '';
    },
    category: function() {
      if (!is.number(this.rating)) {
        return null;
      }
      if (this.rating <= 6) {
        return 'detractor';
      }
      if (this.rating <= 8) {
        return 'passive';
      }
      return 'promoter'
    },
    direction: function() {
      return this._t('DIRECTION') || 'ltr';
    }
  },
  ready: function() {
      this.initAnswers();
  },
  watch: {
    questions: function() {
      this.initAnswers();
    }
  },
  methods: {
    initAnswers: function() {
      this.answers = this.questions.map(function(question) {
        return {
          name: question.name,
          label: question.label,
          value: null
        };
      });
    },
    inState: function() {
      var states = Array.prototype.slice.call(arguments);
      return states.indexOf(this.state) !== -1;
    },
    nextTick: function(fn) {
      Vue.nextTick(bind(this, function() {
        if (this._isDestroyed) {
          return;
        }
        fn.call(this);
      }));
    },
    setTimeout: function(fn, timeout) {
      setTimeout(bind(this, function() {
        if (this._isDestroyed) {
          return;
        }
        fn.call(this);
      }), timeout);
    },
    _t: function(key) {
      if (this.translation) {
        if (this.translation[key]) {
          return this.translation[key];
        }
      }
      return MESSAGES[key];
    },
    t: function(key) {
      var value;
      if (key === 'FOLLOWUP') {
        value = this.t('IMPROVE');
        if (value) {
          return value;
        }
        value = this.t('THANKS_IMPROVE');
        if (value) {
          return value;
        }
      }
      if (this.category) {
        value = this._t(key + '_' + this.category.toUpperCase());
        if (value) {
          return value;
        }
      }
      return this._t(key, value);
    },
    _c: function(type) {
      if (this.colors[type]) {
        return this.colors[type];
      }
      if (type === 'light') {
        return Color(this.colors.primary).mix(Color(this.colors.background), 0.4).hexString();
      }
      if (type === 'background-light') {
        return Color(this.colors.primary).mix(Color(this.colors.background), 0.04).hexString();
      }
      if (type === 'foreground-light') {
        return Color(this.colors.foreground).mix(Color(this.colors.background), 0.6).hexString();
      }
      if (type === 'shadow') {
        return Color(this.colors.foreground).mix(Color(this.colors.background), 0.1).hexString();
      }
      if (type === 'border') {
        return Color(this.colors.foreground).mix(Color(this.colors.background), 0.15).hexString();
      }
    },
    c: function(type) {
      var color = this._c(type);
      if (color && COLORS[color]) {
        return COLORS[color];
      }
      return color;
    },
    show: function() {
      this.visible = true;
    },
    hide: function() {
      this.visible = false;
    },
    stopPropagation: function(e) {
      e.stopPropagation();
    },
    legend(section, index) {
      var question = this.questions[index];
      if (section === 'low') {
        return (question && question.lowLegend) || this.t('LOW_LEGEND');
      }
      else {
        return (question && question.highLegend) || this.t('HIGH_LEGEND');
      }
    }
  },
  events: {
    submit: function() {
      this.$dispatch('submit');
      this.state = THANKS_STATE;
      if (this.skin === DIALOG_SKIN || this.skin === BAR_SKIN) {
        this.setTimeout(function() {
          this.hide();
        }, 800);
      }
    },
    selectRating: function (rating) {
      this.rating = rating;
      this.state = FEEDBACK_STATE;
      this.$emit('ratingSelect');
      this.setTimeout(function() {
        if (this.hasReasons) {
          this.$$.reasons[0].focus();
        }
        else if (this.hasQuestions) {
          // do nothing
        }
        else {
          this.$.feedback.focus();
        }
      }, 400);
    },
    close: function() {
      this.hide();
      this.$emit('dismiss');
    },
  },
  transitions: {
    next: {
      leave: function(el, done) {
        if (this.test) {
          return done();
        }
        if (!this.visible) {
          return done();
        }
        this.leave = el;
        this.setTimeout(function() {
          done();
          delete this.leave;
        }, 600);
      },
      enter: function(enter, done) {
        if (this.test) {
          return done();
        }
        if (!this.visible) {
          return done();
        }
        var content = enter.parentNode;
        var bounding = content.parentNode;
        var leave = this.leave;

        bounding.style.height = getComputedStyle(leave || enter).height;
        content.style.top = 0;
        if (leave) {
          leave.style.opacity = 1;
        }

        this.setTimeout(function() {
          dom.addClass(bounding, 'nps-next');
          this.setTimeout(function() {
            content.style.top = '-' + bounding.style.height;
            bounding.style.height = getComputedStyle(enter).height;
            if (leave) {
              leave.style.opacity = 0;
            }

            this.setTimeout(function() {
              dom.removeClass(bounding, 'nps-next');
              content.style.top = '';
              if (leave) {
                leave.style.display = 'none';
              }
              bounding.style.height = '';
              done();
            }, 500);
          }, 0);
        }, 0);
      }
    }
  }
});

module.exports = Survey;
<|endoftext|>


<commit_before>import _ from 'lodash';

function PlayerListD2Service($q, $translate, BungieLookupD2Service, Constants, SettingsService, UtilsService) {
  'ngInject';

  const service = {
    startGroup: startGroup,
    endGroup: endGroup,
    addPlayer: addPlayer,
    players: []
    // removePlayer: removePlayer
  };
  return service;

  function startGroup(player, unused, id) {
    const p = $q.defer();

    if (UtilsService.isUndefinedOrNullOrEmpty(id)) {
      p.reject(new Error("Invalid group Id"));
      return p.promise;
    }

    const entry = newEntry({ player: player, original: player }, id);
    service.players.push(entry);

    p.resolve(entry.group);
    return p.promise;
  }

  function endGroup(group, error) {
    const parent = findParent(group);
    if (!parent) {
      return $q.reject(new Error("Could not find group"));
    }

    if (error) {
      parent.errorString = error;
      parent.error = true;
    }

    parent.loading = false;

    return $q.resolve();
  }

  function addPlayer(player, group) {
    const original = player.trim();
    player = UtilsService.sanitizeInput(player);
    if (UtilsService.isUndefinedOrNullOrEmpty(player)) {
      return $q.reject(new Error("Gamertag or PSN Id or Battle.net ID input is invalid"));
    }

    const entry = newEntry({ player: player, original: original }, group ? group.id : null);
    if (group) {
      const parent = findParent(group);
      if (!parent) {
        return $q.reject(new Error("Could not find group"));
      }
      parent.group.children.push(entry);
    } else {
      service.players.push(entry);
    }

    // do the async stuff
    return BungieLookupD2Service.lookup(entry)
      .then(function success(response) {
        entry.memberships = response.memberships;
        entry.stats = response.stats;
        buildAliases(entry);
        parseStatsD2(entry);
        entry.loading = false;

        return $q.resolve();
      }, function failure(response) {
        entry.errorString = response;
        entry.error = true;
        entry.loading = false;

        return $q.reject(response);
      });
  }

  function buildAliases(entry) {
    entry.memberships.forEach(function(m) {
      if (m.existsOnPlatform) {
        const platform = Constants.platformsLookup[m.type];
        const alias = {
          name: m.name,
          platform: platform,
          urls: {
            destinyStatus: buildDestinyStatusUrl(platform, m.name),
            destinyTracker: buildDestinyTrackerUrl(platform, m.name),
            raidReport: buildRaidReportUrl(platform, m.name)
          }
        };
        entry.aliases.push(alias);
      }
    });
  }

  function buildDestinyStatusUrl(platform, name) {
    // https://destinystatus.com/pc/<player>
    // https://destinystatus.com/psn/<player>
    // https://destinystatus.com/xbl/<player>
    const alt = $translate.instant('Links.DestinyStatus.Alt');
    const text = $translate.instant('Links.DestinyStatus.Text');
    return "" + text + "";
  }

  function buildDestinyTrackerUrl(platform, name) {
    // for all of these, '#' and ' ' get replaced by '-'
    // https://destinytracker.com/d2/profile/pc/<player>
    // https://destinytracker.com/d2/profile/psn/<player>
    // https://destinytracker.com/d2/profile/xbl/<player>
    const alt = $translate.instant('Links.DestinyTracker.Alt');
    const text = $translate.instant('Links.DestinyTracker.Text');
    return "" + text + "";
  }

  function buildRaidReportUrl(platform, name) {
    // http://raid.report/pc/<player>
    // http://raid.report/ps/<player>
    // http://raid.report/xb/<player>
    const alt = $translate.instant('Links.RaidReport.Alt');
    const text = $translate.instant('Links.RaidReport.Text');
    return "" + text + "";
  }

  function findParent(group) {
    return _.find(service.players, (entry) => { return (group && entry.group) ? (entry.group.id === group.id) : false; });
  }

  function parseStatsD2(entry) {
    entry.l = { nm: 0, g: 0, pm: 0, total: 0 };
    entry.eow = { nm: 0, g: 0, pm: 0, total: 0 };
    entry.sos = { nm: 0, g: 0, pm: 0, total: 0 };
    let offset = 0;

    // caclulate Leviathan normal mode
    for (let i = 0; i < 6; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.l.nm += (entry.stats[hash] || 0);
    }
    offset += 6;

    // caclulate Leviathan guided mode
    for (let i = 0; i < 6; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.l.nm += (entry.stats[hash] || 0);
    }
    offset += 6;

    // calculate Leviathan prestige mode
    for (let i = 0; i < 6; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.l.pm += (entry.stats[hash] || 0);
    }
    offset += 6;

    entry.l.total = entry.l.nm + entry.l.g + entry.l.pm;

    // caclculate Eater of Worlds normal mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.eow.nm += (entry.stats[hash] || 0);
    }
    offset += 1;

    // caclculate Eater of Worlds guided mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.eow.nm += (entry.stats[hash] || 0);
    }
    offset += 1;

    // caclculate Eater of Worlds prestige mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.eow.pm += (entry.stats[hash] || 0);
    }
    offset += 1;

    entry.eow.total = entry.eow.nm + entry.eow.g + entry.eow.pm;

    // caclculate Spire of Stars normal mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.sos.nm += (entry.stats[hash] || 0);
    }
    offset += 1;

    // caclculate Spire of Stars guided mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.sos.nm += (entry.stats[hash] || 0);
    }
    offset += 1;

    // caclculate Spire of Stars prestige mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.sos.pm += (entry.stats[hash] || 0);
    }
    offset += 1;

    entry.sos.total = entry.sos.nm + entry.sos.g + entry.sos.pm;
  }

  function newEntry(player, groupId) {
    const entry = {
      aliases: [],
      error: false,
      loading: true,
      memberships: null,
      original: encodeURIComponent(player.original),
      player: player.player
    };

    if (groupId !== null) {
      entry.group = {};
      entry.group.id = groupId;
      entry.group.children = [];
    }

    return entry;
  }

  // function removePlayer(player) {
    // console.log("[drs] todo");
  // }
}

export default PlayerListD2Service;<commit_msg>Fix comment<commit_after>import _ from 'lodash';

function PlayerListD2Service($q, $translate, BungieLookupD2Service, Constants, SettingsService, UtilsService) {
  'ngInject';

  const service = {
    startGroup: startGroup,
    endGroup: endGroup,
    addPlayer: addPlayer,
    players: []
    // removePlayer: removePlayer
  };
  return service;

  function startGroup(player, unused, id) {
    const p = $q.defer();

    if (UtilsService.isUndefinedOrNullOrEmpty(id)) {
      p.reject(new Error("Invalid group Id"));
      return p.promise;
    }

    const entry = newEntry({ player: player, original: player }, id);
    service.players.push(entry);

    p.resolve(entry.group);
    return p.promise;
  }

  function endGroup(group, error) {
    const parent = findParent(group);
    if (!parent) {
      return $q.reject(new Error("Could not find group"));
    }

    if (error) {
      parent.errorString = error;
      parent.error = true;
    }

    parent.loading = false;

    return $q.resolve();
  }

  function addPlayer(player, group) {
    const original = player.trim();
    player = UtilsService.sanitizeInput(player);
    if (UtilsService.isUndefinedOrNullOrEmpty(player)) {
      return $q.reject(new Error("Gamertag or PSN Id or Battle.net ID input is invalid"));
    }

    const entry = newEntry({ player: player, original: original }, group ? group.id : null);
    if (group) {
      const parent = findParent(group);
      if (!parent) {
        return $q.reject(new Error("Could not find group"));
      }
      parent.group.children.push(entry);
    } else {
      service.players.push(entry);
    }

    // do the async stuff
    return BungieLookupD2Service.lookup(entry)
      .then(function success(response) {
        entry.memberships = response.memberships;
        entry.stats = response.stats;
        buildAliases(entry);
        parseStatsD2(entry);
        entry.loading = false;

        return $q.resolve();
      }, function failure(response) {
        entry.errorString = response;
        entry.error = true;
        entry.loading = false;

        return $q.reject(response);
      });
  }

  function buildAliases(entry) {
    entry.memberships.forEach(function(m) {
      if (m.existsOnPlatform) {
        const platform = Constants.platformsLookup[m.type];
        const alias = {
          name: m.name,
          platform: platform,
          urls: {
            destinyStatus: buildDestinyStatusUrl(platform, m.name),
            destinyTracker: buildDestinyTrackerUrl(platform, m.name),
            raidReport: buildRaidReportUrl(platform, m.name)
          }
        };
        entry.aliases.push(alias);
      }
    });
  }

  function buildDestinyStatusUrl(platform, name) {
    // https://destinystatus.com/pc/<player>
    // https://destinystatus.com/psn/<player>
    // https://destinystatus.com/xbl/<player>
    const alt = $translate.instant('Links.DestinyStatus.Alt');
    const text = $translate.instant('Links.DestinyStatus.Text');
    return "" + text + "";
  }

  function buildDestinyTrackerUrl(platform, name) {
    // for all of these, '#' and ' ' get replaced by '-'
    // https://destinytracker.com/d2/profile/pc/<player>
    // https://destinytracker.com/d2/profile/psn/<player>
    // https://destinytracker.com/d2/profile/xbl/<player>
    const alt = $translate.instant('Links.DestinyTracker.Alt');
    const text = $translate.instant('Links.DestinyTracker.Text');
    return "" + text + "";
  }

  function buildRaidReportUrl(platform, name) {
    // https://raid.report/pc/<player>
    // https://raid.report/ps/<player>
    // https://raid.report/xb/<player>
    const alt = $translate.instant('Links.RaidReport.Alt');
    const text = $translate.instant('Links.RaidReport.Text');
    return "" + text + "";
  }

  function findParent(group) {
    return _.find(service.players, (entry) => { return (group && entry.group) ? (entry.group.id === group.id) : false; });
  }

  function parseStatsD2(entry) {
    entry.l = { nm: 0, g: 0, pm: 0, total: 0 };
    entry.eow = { nm: 0, g: 0, pm: 0, total: 0 };
    entry.sos = { nm: 0, g: 0, pm: 0, total: 0 };
    let offset = 0;

    // caclulate Leviathan normal mode
    for (let i = 0; i < 6; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.l.nm += (entry.stats[hash] || 0);
    }
    offset += 6;

    // caclulate Leviathan guided mode
    for (let i = 0; i < 6; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.l.nm += (entry.stats[hash] || 0);
    }
    offset += 6;

    // calculate Leviathan prestige mode
    for (let i = 0; i < 6; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.l.pm += (entry.stats[hash] || 0);
    }
    offset += 6;

    entry.l.total = entry.l.nm + entry.l.g + entry.l.pm;

    // caclculate Eater of Worlds normal mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.eow.nm += (entry.stats[hash] || 0);
    }
    offset += 1;

    // caclculate Eater of Worlds guided mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.eow.nm += (entry.stats[hash] || 0);
    }
    offset += 1;

    // caclculate Eater of Worlds prestige mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.eow.pm += (entry.stats[hash] || 0);
    }
    offset += 1;

    entry.eow.total = entry.eow.nm + entry.eow.g + entry.eow.pm;

    // caclculate Spire of Stars normal mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.sos.nm += (entry.stats[hash] || 0);
    }
    offset += 1;

    // caclculate Spire of Stars guided mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.sos.nm += (entry.stats[hash] || 0);
    }
    offset += 1;

    // caclculate Spire of Stars prestige mode
    for (let i = 0; i < 1; i++) {
      const hash = Constants.raidsD2[i + offset];
      entry.sos.pm += (entry.stats[hash] || 0);
    }
    offset += 1;

    entry.sos.total = entry.sos.nm + entry.sos.g + entry.sos.pm;
  }

  function newEntry(player, groupId) {
    const entry = {
      aliases: [],
      error: false,
      loading: true,
      memberships: null,
      original: encodeURIComponent(player.original),
      player: player.player
    };

    if (groupId !== null) {
      entry.group = {};
      entry.group.id = groupId;
      entry.group.children = [];
    }

    return entry;
  }

  // function removePlayer(player) {
    // console.log("[drs] todo");
  // }
}

export default PlayerListD2Service;<|endoftext|>


<commit_before>/**
 * The Form Builder Field List Component
 *
 * @module aui-form-builder-field-list
 */

var CSS_FIELD_LIST = A.getClassName('form', 'builder', 'field', 'list'),
    CSS_FIELD_LIST_ADD_BUTTON =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button'),
        CSS_FIELD_LIST_ADD_BUTTON_ICON =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'icon'),
    CSS_FIELD_LIST_ADD_BUTTON_LABEL =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'label'),
        CSS_FIELD_LIST_ADD_BUTTON_PLUS_ICON =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'plus', 'icon'),
        CSS_FIELD_LIST_ADD_BUTTON_PLUS_LABEL =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'plus', 'label'),
    CSS_FIELD_LIST_ADD_BUTTON_VISIBLE =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'visible'),
    CSS_FIELD_LIST_ADD_CONTAINER =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'container'),
    CSS_FIELD_LIST_CONTAINER =
        A.getClassName('form', 'builder', 'field', 'list', 'container'),
    CSS_FIELD_LIST_EMPTY = A.getClassName('form', 'builder', 'field', 'list', 'empty'),
    CSS_FIELD_MOVE_TARGET =
        A.getClassName('form', 'builder', 'field', 'move', 'target'),
    CSS_LIST_MOVE_TARGET =
        A.getClassName('form', 'builder', 'list', 'move', 'target');

/**
 * A base class for `A.FormBuilderFieldList`.
 *
 * @class A.FormBuilderFieldList
 * @extends A.Base
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 */
A.FormBuilderFieldList  = A.Base.create('form-builder-field-list', A.Base, [], {
    TPL_ADD_FIELD: '
' +
        '
' +
        '
' +
        '
+
' +
        '
' +
        '' +
        '+ ADD FIELD' +
        '' +
        '

',
    TPL_FIELD_LIST: '
' +
        '

' +
        '
',
    TPL_FIELD_MOVE_TARGET: '<button type="button" class="' + CSS_FIELD_MOVE_TARGET + ' ' + CSS_LIST_MOVE_TARGET +
        ' layout-builder-move-target layout-builder-move-col-target btn btn-default">' +
        '{pasteHere}</button>',

    /**
     * Construction logic executed during the `A.FormBuilderFieldList`
     * instantiation. Lifecycle.
     *
     * @method initializer
     * @protected
     */
    initializer: function() {
        var content = this.get('content');

        this._uiSetFields(this.get('fields'));

        content.delegate('click', this._onClickAddField, '.' + CSS_FIELD_LIST_ADD_BUTTON, this),
        content.delegate('mouseenter', this._onMouseEnterAddButton, '.' + CSS_FIELD_LIST_ADD_CONTAINER, this),
        content.delegate('mouseleave', this._onMouseLeaveAddButton, '.' + CSS_FIELD_LIST_ADD_CONTAINER, this),

        this.after('fieldsChange', A.bind(this._afterFieldsChange, this));
    },

    /**
     * Adds a new field to the `A.FormBuilderFieldList`.
     *
     * @method addField
     * @param {A.FormBuilderFieldBase} field
     * @param {Number} index
     */
    addField: function(field, index) {
        var fields = this.get('fields');

        if (A.Lang.isNumber(index)) {
            fields.splice(index, 0, field);
        }
        else {
            fields.splice(this._newFieldIndex, 0, field);
        }

        this.set('fields', fields);
    },

    /**
     * Removes the given field from the `A.FormBuilderFieldList`.
     *
     * @method removeField
     * @param {A.FormBuilderFieldBase} field
     */
    removeField: function(field) {
        var fields = this.get('fields'),
            indexOf = fields.indexOf(field);

        fields.splice(indexOf, 1);
        this.set('fields', fields);
    },

    /**
     * Fired after the `fields` attribute is set.
     *
     * @method _afterFieldsChange
     * @protected
     */
    _afterFieldsChange: function() {
        var fields = this.get('fields');

        this._uiSetFields(fields);
        this._updateRemovableLayoutColProperty();
    },

    /**
     * Appends add field on the given container.
     *
     * @method _appendAddFieldNode
     * @param {Node} container
     * @param {Number} index
     * @param {Boolean} visible
     * @protected
     */
    _appendAddFieldNode: function(container, index, visible) {
        var addFieldNode,
            moveTargetNode;

        addFieldNode = A.Node.create(this.TPL_ADD_FIELD);
        moveTargetNode = A.Node.create(A.Lang.sub(this.TPL_FIELD_MOVE_TARGET, {
            pasteHere: this.get('strings').pasteHere
        }));

        if (!visible) {
            addFieldNode.removeClass(CSS_FIELD_LIST_ADD_BUTTON_VISIBLE);
        }

        moveTargetNode.setData('field-list-index', index);

        container.append(addFieldNode);
        container.append(moveTargetNode);
    },

    /**
     * Fired when the button for adding a new field is clicked.
     *
     * @method _onClickAddField
     * @param {EventFacade} event
     * @protected
     */
    _onClickAddField: function(event) {
        var emptyFieldList = this.get('content').all('.' + CSS_FIELD_LIST_ADD_BUTTON);

        this._newFieldIndex = emptyFieldList.indexOf(event.currentTarget);
    },

    /**
     * Fired when mouse enters the button for adding a new field.
     *
     * @method _onMouseEnterAddButton
     * @param {EventFacade} event
     * @protected
     */
    _onMouseEnterAddButton: function(event) {
        var addButtonNode = event.currentTarget;

        if (this.get('fields').length > 0) {
            addButtonNode.addClass(CSS_FIELD_LIST_ADD_BUTTON_VISIBLE);
        }
    },

    /**
     * Fired when mouse leaves the button for adding a new field.
     *
     * @method _onMouseLeaveAddButton
     * @param {EventFacade} event
     * @protected
     */
    _onMouseLeaveAddButton: function(event) {
        var addButtonNode = event.currentTarget;

        if (this.get('fields').length > 0) {
            addButtonNode.removeClass(CSS_FIELD_LIST_ADD_BUTTON_VISIBLE);
        }
    },

    /**
     * Updates the ui according to the value of the `fields` attribute.
     *
     * @method _uiSetFields
     * @param {Array} fields
     * @protected
     */
    _uiSetFields: function(fields) {
        var content = this.get('content'),
            container = content.one('.' + CSS_FIELD_LIST_CONTAINER),
            index;

        container.empty();

        for (index = 0; index < fields.length; index++) {
            this._appendAddFieldNode(container, index, false);
            container.append(fields[index].get('content'));
        }

        this._appendAddFieldNode(container, index, true);

        content.toggleClass(CSS_FIELD_LIST_EMPTY, !fields.length);

        if (fields.length === 0) {
            content.one('.' + CSS_FIELD_LIST_ADD_CONTAINER).addClass(CSS_FIELD_LIST_ADD_BUTTON_VISIBLE);
            content.all('.' + CSS_FIELD_LIST_ADD_BUTTON_ICON).removeClass('hidden');
            content.all('.' + CSS_FIELD_LIST_ADD_BUTTON_PLUS_LABEL).addClass('hidden');
        }
        else {
            content.all('.' + CSS_FIELD_LIST_ADD_BUTTON_ICON).addClass('hidden');
            content.all('.' + CSS_FIELD_LIST_ADD_BUTTON_PLUS_LABEL).removeClass('hidden');
        }
    },

    /**
     * Update removable property for layout cols.
     *
     * @method _updateRemovableLayoutColProperty
     * @protected
     */
    _updateRemovableLayoutColProperty: function() {
        var fields = this.get('fields'),
            content = this.get('content'),
            col = content.ancestor('.col'),
            layoutCol;

        if (col) {
            layoutCol = col.getData('layout-col');
            layoutCol.set('removable', fields.length === 0);
        }
    }
}, {

    /**
     * Static property used to define the default attribute
     * configuration for the `A.FormBuilderFieldList`.
     *
     * @property ATTRS
     * @type Object
     * @static
     */
    ATTRS: {

        /**
         * Node containing the contents of this field list.
         *
         * @attribute content
         * @type Node
         */
        content: {
            validator: function(val) {
                return A.instanceOf(val, A.Node);
            },
            valueFn: function() {
                return A.Node.create(this.TPL_FIELD_LIST);
            },
            writeOnce: 'initOnly'
        },

        /**
         * List of field.
         *
         * @attribute fields
         * @type {Array}
         */
        fields: {
            value: []
        },

        /**
         * Collection of strings used to label elements of the UI.
         *
         * @attribute strings
         * @type {Object}
         */
        strings: {
            value: {
                pasteHere: 'Paste here'
            },
            writeOnce: true
        }
    }
});
<commit_msg>AUI-2056 Source Formating<commit_after>/**
 * The Form Builder Field List Component
 *
 * @module aui-form-builder-field-list
 */

var CSS_FIELD_LIST = A.getClassName('form', 'builder', 'field', 'list'),
    CSS_FIELD_LIST_ADD_BUTTON =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button'),
        CSS_FIELD_LIST_ADD_BUTTON_ICON =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'icon'),
    CSS_FIELD_LIST_ADD_BUTTON_LABEL =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'label'),
        CSS_FIELD_LIST_ADD_BUTTON_PLUS_ICON =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'plus', 'icon'),
        CSS_FIELD_LIST_ADD_BUTTON_PLUS_LABEL =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'plus', 'label'),
    CSS_FIELD_LIST_ADD_BUTTON_VISIBLE =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'visible'),
    CSS_FIELD_LIST_ADD_CONTAINER =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'container'),
    CSS_FIELD_LIST_CONTAINER =
        A.getClassName('form', 'builder', 'field', 'list', 'container'),
    CSS_FIELD_LIST_EMPTY = A.getClassName('form', 'builder', 'field', 'list', 'empty'),
    CSS_FIELD_MOVE_TARGET =
        A.getClassName('form', 'builder', 'field', 'move', 'target'),
    CSS_LIST_MOVE_TARGET =
        A.getClassName('form', 'builder', 'list', 'move', 'target');

/**
 * A base class for `A.FormBuilderFieldList`.
 *
 * @class A.FormBuilderFieldList
 * @extends A.Base
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 */
A.FormBuilderFieldList  = A.Base.create('form-builder-field-list', A.Base, [], {
    TPL_ADD_FIELD: '
' +
        '
' +
        '
' +
        '
+
' +
        '
' +
        '' +
        '+ ADD FIELD' +
        '' +
        '

',
    TPL_FIELD_LIST: '
' +
        '

' +
        '
',
    TPL_FIELD_MOVE_TARGET: '<button type="button" class="' + CSS_FIELD_MOVE_TARGET + ' ' + CSS_LIST_MOVE_TARGET +
        ' layout-builder-move-target layout-builder-move-col-target btn btn-default">' +
        '{pasteHere}</button>',

    /**
     * Construction logic executed during the `A.FormBuilderFieldList`
     * instantiation. Lifecycle.
     *
     * @method initializer
     * @protected
     */
    initializer: function() {
        var content = this.get('content');

        this._uiSetFields(this.get('fields'));

        content.delegate('click', this._onClickAddField, '.' + CSS_FIELD_LIST_ADD_BUTTON, this);
        content.delegate('mouseenter', this._onMouseEnterAddButton, '.' + CSS_FIELD_LIST_ADD_CONTAINER, this);
        content.delegate('mouseleave', this._onMouseLeaveAddButton, '.' + CSS_FIELD_LIST_ADD_CONTAINER, this);

        this.after('fieldsChange', A.bind(this._afterFieldsChange, this));
    },

    /**
     * Adds a new field to the `A.FormBuilderFieldList`.
     *
     * @method addField
     * @param {A.FormBuilderFieldBase} field
     * @param {Number} index
     */
    addField: function(field, index) {
        var fields = this.get('fields');

        if (A.Lang.isNumber(index)) {
            fields.splice(index, 0, field);
        }
        else {
            fields.splice(this._newFieldIndex, 0, field);
        }

        this.set('fields', fields);
    },

    /**
     * Removes the given field from the `A.FormBuilderFieldList`.
     *
     * @method removeField
     * @param {A.FormBuilderFieldBase} field
     */
    removeField: function(field) {
        var fields = this.get('fields'),
            indexOf = fields.indexOf(field);

        fields.splice(indexOf, 1);
        this.set('fields', fields);
    },

    /**
     * Fired after the `fields` attribute is set.
     *
     * @method _afterFieldsChange
     * @protected
     */
    _afterFieldsChange: function() {
        var fields = this.get('fields');

        this._uiSetFields(fields);
        this._updateRemovableLayoutColProperty();
    },

    /**
     * Appends add field on the given container.
     *
     * @method _appendAddFieldNode
     * @param {Node} container
     * @param {Number} index
     * @param {Boolean} visible
     * @protected
     */
    _appendAddFieldNode: function(container, index, visible) {
        var addFieldNode,
            moveTargetNode;

        addFieldNode = A.Node.create(this.TPL_ADD_FIELD);
        moveTargetNode = A.Node.create(A.Lang.sub(this.TPL_FIELD_MOVE_TARGET, {
            pasteHere: this.get('strings').pasteHere
        }));

        if (!visible) {
            addFieldNode.removeClass(CSS_FIELD_LIST_ADD_BUTTON_VISIBLE);
        }

        moveTargetNode.setData('field-list-index', index);

        container.append(addFieldNode);
        container.append(moveTargetNode);
    },

    /**
     * Fired when the button for adding a new field is clicked.
     *
     * @method _onClickAddField
     * @param {EventFacade} event
     * @protected
     */
    _onClickAddField: function(event) {
        var emptyFieldList = this.get('content').all('.' + CSS_FIELD_LIST_ADD_BUTTON);

        this._newFieldIndex = emptyFieldList.indexOf(event.currentTarget);
    },

    /**
     * Fired when mouse enters the button for adding a new field.
     *
     * @method _onMouseEnterAddButton
     * @param {EventFacade} event
     * @protected
     */
    _onMouseEnterAddButton: function(event) {
        var addButtonNode = event.currentTarget;

        if (this.get('fields').length > 0) {
            addButtonNode.addClass(CSS_FIELD_LIST_ADD_BUTTON_VISIBLE);
        }
    },

    /**
     * Fired when mouse leaves the button for adding a new field.
     *
     * @method _onMouseLeaveAddButton
     * @param {EventFacade} event
     * @protected
     */
    _onMouseLeaveAddButton: function(event) {
        var addButtonNode = event.currentTarget;

        if (this.get('fields').length > 0) {
            addButtonNode.removeClass(CSS_FIELD_LIST_ADD_BUTTON_VISIBLE);
        }
    },

    /**
     * Updates the ui according to the value of the `fields` attribute.
     *
     * @method _uiSetFields
     * @param {Array} fields
     * @protected
     */
    _uiSetFields: function(fields) {
        var content = this.get('content'),
            container = content.one('.' + CSS_FIELD_LIST_CONTAINER),
            index;

        container.empty();

        for (index = 0; index < fields.length; index++) {
            this._appendAddFieldNode(container, index, false);
            container.append(fields[index].get('content'));
        }

        this._appendAddFieldNode(container, index, true);

        content.toggleClass(CSS_FIELD_LIST_EMPTY, !fields.length);

        if (fields.length === 0) {
            content.one('.' + CSS_FIELD_LIST_ADD_CONTAINER).addClass(CSS_FIELD_LIST_ADD_BUTTON_VISIBLE);
            content.all('.' + CSS_FIELD_LIST_ADD_BUTTON_ICON).removeClass('hidden');
            content.all('.' + CSS_FIELD_LIST_ADD_BUTTON_PLUS_LABEL).addClass('hidden');
        }
        else {
            content.all('.' + CSS_FIELD_LIST_ADD_BUTTON_ICON).addClass('hidden');
            content.all('.' + CSS_FIELD_LIST_ADD_BUTTON_PLUS_LABEL).removeClass('hidden');
        }
    },

    /**
     * Update removable property for layout cols.
     *
     * @method _updateRemovableLayoutColProperty
     * @protected
     */
    _updateRemovableLayoutColProperty: function() {
        var fields = this.get('fields'),
            content = this.get('content'),
            col = content.ancestor('.col'),
            layoutCol;

        if (col) {
            layoutCol = col.getData('layout-col');
            layoutCol.set('removable', fields.length === 0);
        }
    }
}, {

    /**
     * Static property used to define the default attribute
     * configuration for the `A.FormBuilderFieldList`.
     *
     * @property ATTRS
     * @type Object
     * @static
     */
    ATTRS: {

        /**
         * Node containing the contents of this field list.
         *
         * @attribute content
         * @type Node
         */
        content: {
            validator: function(val) {
                return A.instanceOf(val, A.Node);
            },
            valueFn: function() {
                return A.Node.create(this.TPL_FIELD_LIST);
            },
            writeOnce: 'initOnly'
        },

        /**
         * List of field.
         *
         * @attribute fields
         * @type {Array}
         */
        fields: {
            value: []
        },

        /**
         * Collection of strings used to label elements of the UI.
         *
         * @attribute strings
         * @type {Object}
         */
        strings: {
            value: {
                pasteHere: 'Paste here'
            },
            writeOnce: true
        }
    }
});
<|endoftext|>


<commit_before>const development = !process.env.NODE_ENV || process.env.NODE_ENV === 'development'

class BaseError extends Error {
  constructor(message, statusCode) {
    super(message)
    this.name = this.constructor.name
    this.statusCode = statusCode || 500
    if (typeof Error.captureStackTrace === 'function') {
      Error.captureStackTrace(this, this.constructor)
    } else {
      this.stack = new Error(message).stack
    }
  }
}

class EmptyParseOutputError extends BaseError {}

class EmptyHttpResponseError extends BaseError {}

class InvalidInputError extends BaseError {
  constructor(message, statusCode) {
    super(message, statusCode || 400)
  }
}

class NotFoundError extends BaseError {
  constructor(url) {
    super('Could not find feed', 404)
    this.url = url
  }
}

class ParserError extends BaseError {
  constructor(cause, parser, statusCode) {
    super(cause.message, statusCode)
    this.cause = cause
    this.parser = parser
  }
}

class NotAFeedError extends BaseError {
  constructor() {
    super('Not a feed', 400)
  }
}

class ConnectionFailedError extends BaseError {
  constructor(url) {
    super('Could not connect', 404)
    this.url = url
  }
}

function createErrorFormatter(Raven) {
  return function formatError(error) {
    if (Raven) {
      if (error.path || error.name !== 'GraphQLError') {
        Raven.captureException(error, {
          tags: { graphql: 'error' },
          extra: {
            source: error.source && error.source.body,
            positions: error.positions,
            path: error.path,
          },
        })
      } else {
        Raven.captureMessage(`GraphQLWrongQuery: ${error.message}`, {
          tags: { graphql: 'query' },
          extra: {
            source: error.source && error.source.body,
            positions: error.positions,
          },
        })
      }
    }

    const response = {
      message: error.message,
    }
    if (development) {
      response.stack = error.stack.split('\n')
    }
    try {
      response.type = error.stack.split('\n')[0].split(':')[0]
    } catch (error) {
      if (development) {
        return error
      }
    }
    return response
  }
}

module.exports = {
  ConnectionFailedError,
  EmptyHttpResponseError,
  EmptyParseOutputError,
  InvalidInputError,
  ParserError,
  NotAFeedError,
  NotFoundError,
  createErrorFormatter,
}
<commit_msg>fix: Make error handling more robust when missing stack<commit_after>const development = !process.env.NODE_ENV || process.env.NODE_ENV === 'development'

class BaseError extends Error {
  constructor(message, statusCode) {
    super(message)
    this.name = this.constructor.name
    this.statusCode = statusCode || 500
    if (typeof Error.captureStackTrace === 'function') {
      Error.captureStackTrace(this, this.constructor)
    } else {
      this.stack = new Error(message).stack
    }
  }
}

class EmptyParseOutputError extends BaseError {}

class EmptyHttpResponseError extends BaseError {}

class InvalidInputError extends BaseError {
  constructor(message, statusCode) {
    super(message, statusCode || 400)
  }
}

class NotFoundError extends BaseError {
  constructor(url) {
    super('Could not find feed', 404)
    this.url = url
  }
}

class ParserError extends BaseError {
  constructor(cause, parser, statusCode) {
    super(cause.message, statusCode)
    this.cause = cause
    this.parser = parser
  }
}

class NotAFeedError extends BaseError {
  constructor() {
    super('Not a feed', 400)
  }
}

class ConnectionFailedError extends BaseError {
  constructor(url) {
    super('Could not connect', 404)
    this.url = url
  }
}

function createErrorFormatter(Raven) {
  return function formatError(error) {
    if (Raven) {
      if (error.path || error.name !== 'GraphQLError') {
        Raven.captureException(error, {
          tags: { graphql: 'error' },
          extra: {
            source: error.source && error.source.body,
            positions: error.positions,
            path: error.path,
          },
        })
      } else {
        Raven.captureMessage(`GraphQLWrongQuery: ${error.message}`, {
          tags: { graphql: 'query' },
          extra: {
            source: error.source && error.source.body,
            positions: error.positions,
          },
        })
      }
    }

    const response = {
      message: error.message,
    }
    if (error.stack) {
      if (development) {
        response.stack = error.stack.split('\n')
      }
      try {
        response.type = error.stack.split('\n')[0].split(':')[0]
      } catch (error) {
        if (development) {
          return error
        }
      }
    }
    return response
  }
}

module.exports = {
  ConnectionFailedError,
  EmptyHttpResponseError,
  EmptyParseOutputError,
  InvalidInputError,
  ParserError,
  NotAFeedError,
  NotFoundError,
  createErrorFormatter,
}
<|endoftext|>


<commit_before>
'use strict';

export default class HTML {

  static registerButtons(parent) {
    // Just an experiment for having to write lesser code.... which ended up in having more code here ;-) #Jens
    Array.prototype.forEach.call(parent.shadowRoot.querySelectorAll("button"), node => {
      var name = node.id
      var funcName = name.replace(/^./, c => "on"+ c.toUpperCase())
      console.log("register button " + name)
      $(node).click(() => {
        var func = parent[funcName]
        if (func) {
          func.call(parent)
        } else {
          alert("No callback: " +  funcName)
        }
      })
    })
  }

  // static registerInputs(parent) {
  //   Array.prototype.forEach.call(parent.shadowRoot.querySelectorAll("input"), node => {
  //     var name = node.id
  //     var funcName = name.replace(/^./, function (c) {
  //           return "on" + c.toUpperCase() ;
  //         }) + "Changed";
  //     console.log("register input " + name)
  //       node.addEventListener("input", function(evt) {
  //         var value = node.value
  //         var func = parent[funcName];
  //         if (func) {
  //           func.call(parent, value);
  //         } else {
  //           alert("No callback: " + funcName);
  //         }
  //       });
  //     })
  // }

  static fixLinks(nodes, dir, followPath) {
    if (! followPath) {
      throw new Error("argument followPath missing");
    }
    if (! nodes) return;

    Array.prototype.forEach.call(nodes, node => {
      if (node.getAttribute) {
        var href = node.getAttribute("href")
        if (href) {
          // #TODO load inplace....
          var path;
          var m
          if (m = href.match(/javascript:visitPath\('webwerkstatt\/(.*)'\)/)) {
            path = "/Thesis/" + m[1]
          } else if (href.match(/([A-Za-z]+):\/\/.+/)) {
            // console.log("ignore "  + href);
            path = href;
          } else if (href.match(/^\//)) {
            path = href; // ABSOLTUE paths
          } else {
            path = dir + href // that leaves us RELATIVE paths

            if(!path.match(/((\.[A-Za-z]+)|(\/))$/)) {
              // no ending?
              // we could check, or assume md for the moment
              path += ".md"
              console.log("assume Markdown for "+ path)
            }
          }
          if (path) {

            // console.log("fix "  + href + " to " + path + "(dir " + dir + ")")
            $(node).click(() => { followPath(path); return false; });

            // ALTERNATIVE to navigate it inline, but the link will not be followed....
            // var link = lively4url + "/draft/start.html?load=" + path
            // node.setAttribute("href", link)
          } else {
            // console.log("ignore " + href)
          }
        } else if (node.getAttribute('src')) {
          // image tag
          let src = node.getAttribute('src'),
              // TODO: remove duplicate
              swAwareBasePath = 'https://lively4/',
              path;
          // TODO: remove duplucated logic
          if (src.match(/([A-Za-z]+):\/\/.+/)) {
            // ignore FULL URLS
            // console.log("ignore "  + src);
          } else if (src.match(/^\//)) {
            path = src; // ABSOLTUE paths
          } else {
            path = swAwareBasePath + dir + src // that leaves us RELATIVE paths
          }
          if (path) {
            node.setAttribute('src', path);
          } else {
            // console.log("ignore image " + href)
          }
        }
        this.fixLinks(node.childNodes, dir, followPath)
      }
    })
}

}
console.log("loaded html.js")
<commit_msg>Update file src/client/html.js with webclient file backend<commit_after>
'use strict';

export default class HTML {

  static registerButtons(parent) {
    // Just an experiment for having to write lesser code.... which ended up in having more code here ;-) #Jens
    Array.prototype.forEach.call(parent.shadowRoot.querySelectorAll("button"), node => {
      var name = node.id
      var funcName = name.replace(/^./, c => "on"+ c.toUpperCase())
      console.log("register button " + name)
      $(node).click(() => {
        var func = parent[funcName]
        if (func) {
          func.call(parent)
        } else {
          alert("No callback: " +  funcName)
        }
      })
    })
  }

  // static registerInputs(parent) {
  //   Array.prototype.forEach.call(parent.shadowRoot.querySelectorAll("input"), node => {
  //     var name = node.id
  //     var funcName = name.replace(/^./, function (c) {
  //           return "on" + c.toUpperCase() ;
  //         }) + "Changed";
  //     console.log("register input " + name)
  //       node.addEventListener("input", function(evt) {
  //         var value = node.value
  //         var func = parent[funcName];
  //         if (func) {
  //           func.call(parent, value);
  //         } else {
  //           alert("No callback: " + funcName);
  //         }
  //       });
  //     })
  // }

  static fixLinks(nodes, dir, followPath) {
    if (! followPath) {
      throw new Error("argument followPath missing");
    }
    if (! nodes) return;

    Array.prototype.forEach.call(nodes, node => {
      if (node.getAttribute) {
        var href = node.getAttribute("href")
        if (href) {
          // #TODO load inplace....
          var path;
          var m
          if (m = href.match(/javascript:visitPath\('webwerkstatt\/(.*)'\)/)) {
            path = "/Thesis/" + m[1]
          } else if (href.match(/([A-Za-z]+):\/\/.+/)) {
            // console.log("ignore "  + href);
            path = href;
          } else if (href.match(/^\//)) {
            path = href; // ABSOLTUE paths
          } else {
            path = dir + href // that leaves us RELATIVE paths

            if(!path.match(/((\.[A-Za-z]+)|(\/))$/)) {
              // no ending?
              // we could check, or assume md for the moment
              path += ".md"
              console.log("assume Markdown for "+ path)
            }
          }
          if (path) {

            // console.log("fix "  + href + " to " + path + "(dir " + dir + ")")
            $(node).click(() => { followPath(path); return false; });

            // ALTERNATIVE to navigate it inline, but the link will not be followed....
            // var link = lively4url + "/draft/start.html?load=" + path
            // node.setAttribute("href", link)
          } else {
            // console.log("ignore " + href)
          }
        } else if (node.getAttribute('src')) {
          // image tag
          let src = node.getAttribute('src'),
              // TODO: remove duplicate
              swAwareBasePath = 'https://lively4/',
              path;
          // TODO: remove duplucated logic
          if (src.match(/([A-Za-z]+):\/\/.+/)) {
            // ignore FULL URLS
            // console.log("ignore "  + src);
          } else if (src.match(/^\//)) {
            path = src; // ABSOLTUE paths
          } else {
            path = swAwareBasePath + dir + src // that leaves us RELATIVE paths
          }
          if (path) {
            node.setAttribute('src', path);
          } else {
            // console.log("ignore image " + href)
          }
        }
        this.fixLinks(node.childNodes, dir, followPath)
      }
    })
}

}
console.log("loaded html.js")
<|endoftext|>


<commit_before>angular.
  module('Cadastrar').
  component('registrarDepartamento', {
    templateUrl: '/app/Cadastrar/cadastrar.template.html',
    controller: ['ApiDepartamento','$http','$location', 'MatWebGlobals',function registrarDepartamento(ApiDepartamento,$http,$location,MatWebGlobals) {
      var ctrl = this;
      ctrl.registrar = registrar;
      this.formulario = {'depName':'','idNumber':''};
 function.registrar(){
  ctrl.mensagem = true;
  ApiDepartamento.Create(ctrl.formulario)
  .then(function (data){
    if(data.success){
MatWebGlobals.Success('registro feito com sucesso', true);
$http.path('/Cadastrar');
} else{
  MatWebGlobals.Error(data.messagem);
ctrl.mensagem = false;
}
});

    }]
}
<commit_msg>lol 2017-05-17<commit_after>angular.
  module('Cadastrar').
  component('registrarDepartamento', {
    templateUrl: '/app/Cadastrar/cadastrar.template.html',
    controller: ['ApiDepartamento','$http','$location', 'MatWebGlobals',function registrarDepartamento(ApiDepartamento,$http,$location,MatWebGlobals) {
      var ctrl = this;
      ctrl.registrar = registrar;
      this.formulario = {'depName':'','idNumber':''};
 function.registrar(){}
  ctrl.mensagem = true;
  ApiDepartamento.Create(ctrl.formulario)
  .then(function (data){
    if(data.success){
MatWebGlobals.Success('registro feito com sucesso', true);
$http.path('/Cadastrar');
} else{
  MatWebGlobals.Error(data.messagem);
ctrl.mensagem = false;
}
});

    }]
}
<|endoftext|>


<commit_before>import { exec } from 'child_process';
import sq from 'shell-quote';

/**
 * Customizable MeCab connector.
 */
export default class MeCab {
  /**
   * @param {string} command a command string to be executed via spawn.
   */
  constructor({ command = 'mecab' }) {
    this._command = command;
  }

  _getCommandStr(text) {
    const echoCommand = sq.quote(['echo', text]);
    return `${echoCommand} | ${this._command}`;
  }

  /**
   * Analyze a given text with MeCab.
   * @param {string} text a text string to be parsed.
   * @param {Function} [callback] a callback function.
   * @return {Promise<Array<Array<string>>}
   * @note The user can receive a result via a callback function
   *       and a promise object.
   */
  parse(text, callback) {
    return new Promise((resolve, reject) => {
      exec(this._getCommandStr(text), (err, result) => {
        if (err) {
          reject(err);
          if (callback) {
            callback(err);
          }
          return;
        }

        const parsed = result.split('\n')
          .map((line) => line.replace(/\t/g, ',').split(','))
          .filter((line) => line.length >= 6);

        resolve(parsed);

        if (callback) {
          callback(err, parsed);
        }
      });
    });
  }
}
<commit_msg>Remove callback support from Mecab#parse<commit_after>import { exec } from 'child_process';
import sq from 'shell-quote';

/**
 * Customizable MeCab connector.
 */
export default class MeCab {
  /**
   * @param {string} command a command string to be executed via spawn.
   */
  constructor({ command = 'mecab' }) {
    this._command = command;
  }

  _getCommandStr(text) {
    const echoCommand = sq.quote(['echo', text]);
    return `${echoCommand} | ${this._command}`;
  }

  /**
   * Analyze a given text with MeCab.
   * @param {string} text a text string to be parsed.
   * @return {Promise<Array<Array<string>>}
   */
  parse(text) {
    return new Promise((resolve, reject) => {
      exec(this._getCommandStr(text), (err, result) => {
        /* istanbul ignore if */
        if (err) {
          return reject(err);
        }

        const parsed = result.split('\n')
          .map((line) => line.replace(/\t/g, ',').split(','))
          .filter((line) => line.length >= 6);

        return resolve(parsed);
      });
    });
  }
}
<|endoftext|>


<commit_before>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactNativeFeatureFlags
 */

'use strict';

var ReactNativeFeatureFlags = {
  useFiber: false,
};

module.exports = ReactNativeFeatureFlags;
<commit_msg>Added MobileConfig for ReactNative use-fiber<commit_after>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactNativeFeatureFlags
 * @flow
 */

'use strict';

var ReactNativeFeatureFlags = {
  useFiber: false,
};

module.exports = ReactNativeFeatureFlags;
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const url = require('url');
const formidable = require('formidable');
const fse = require('fs-extra');
const ObjectID = require('mongodb').ObjectID;
const settings = require('../../lib/settings');
const SettingsService = require('../settings/settings');
const mongo = require('../../lib/mongo');
const utils = require('../../lib/utils');
const parse = require('../../lib/parse');

class ProductCategoriesService {
  constructor() {}

  getFilter(params = {}) {
    let filter = {};
    const enabled = parse.getBooleanIfValid(params.enabled);
    if (enabled !== null) {
      filter.enabled = enabled;
    }
    const id = parse.getObjectIDIfValid(params.id);
    if (id) {
      filter._id = id;
    }
    return filter;
  }

  async getCategories(params = {}) {
    const filter = this.getFilter(params);
    const projection = utils.getProjectionFromFields(params.fields);
    const generalSettings = await SettingsService.getSettings();
    const domain = generalSettings.domain;
    const items = await mongo.db.collection('productCategories').find(filter, { projection: projection }).sort({position: 1}).toArray();
    const result = items.map(category => this.changeProperties(category, domain));
    return result;
  }

  getSingleCategory(id) {
    if (!ObjectID.isValid(id)) {
      return Promise.reject('Invalid identifier');
    }
    return this.getCategories({id: id}).then(categories => {
      return categories.length > 0
        ? categories[0]
        : null;
    })
  }

  addCategory(data) {
    return mongo.db.collection('productCategories').find().sort({position:-1}).limit(1).nextObject()
    .then(item => {
      const newPosition = (item && item.position > 0) ? item.position + 1 : 1;

      return this.getValidDocumentForInsert(data, newPosition).then(dataToInsert =>
        mongo.db.collection('productCategories')
          .insertMany([dataToInsert])
          .then(res => this.getSingleCategory(res.ops[0]._id.toString())));
    });
  }

  updateCategory(id, data) {
    if(!ObjectID.isValid(id)) {
      return Promise.reject('Invalid identifier');
    }
    let categoryObjectID = new ObjectID(id);

    return this.getValidDocumentForUpdate(id, data)
      .then(dataToSet => mongo.db.collection('productCategories').updateOne({ _id: categoryObjectID }, {$set: dataToSet}))
      .then(res => res.modifiedCount > 0 ? this.getSingleCategory(id) : null)
  }

  findAllChildren(items, id, result) {
    if(id && ObjectID.isValid(id)) {
      result.push(new ObjectID(id));
      let finded = items.filter(item => ((item.parent_id || '').toString() === id.toString()));
      if(finded.length > 0) {
        for(let item of finded) {
          this.findAllChildren(items, item.id, result);
        }
      }
    }

    return result;
  }

  deleteCategory(id) {
    if(!ObjectID.isValid(id)) {
      return Promise.reject('Invalid identifier');
    }

    // 1. get all categories
    return this.getCategories()
    .then(items => {
      // 2. find category and children
      let idsToDelete = [];
      this.findAllChildren(items, id, idsToDelete);
      return idsToDelete;
    })
    .then(idsToDelete => {
      // 3. delete categories
      let objectsToDelete = idsToDelete.map((id) => ( new ObjectID(id) ));
      // return mongo.db.collection('productCategories').deleteMany({_id: { $in: objectsToDelete}}).then(() => idsToDelete);
      return mongo.db.collection('productCategories').deleteMany({_id: { $in: objectsToDelete}}).then(deleteResponse => deleteResponse.deletedCount > 0 ? idsToDelete : null);
    })
    .then(idsToDelete => {
      // 4. update category_id for products
      return idsToDelete ? mongo.db.collection('products').updateMany({ category_id: { $in: idsToDelete}}, { $set: { category_id: null }}).then(() => idsToDelete) : null;
    })
    .then(idsToDelete => {
      // 5. delete directories with images
      if(idsToDelete) {
        for(let categoryId of idsToDelete) {
          let deleteDir = path.resolve(settings.categoriesUploadPath + '/' + categoryId);
          fse.remove(deleteDir, err => {});
        }
        return Promise.resolve(true);
      } else {
        return Promise.resolve(false);
      }
    });
  }

  getErrorMessage(err) {
    return { 'error': true, 'message': err.toString() };
  }

  getValidDocumentForInsert(data, newPosition) {
      //  Allow empty category to create draft

      let category = {
        'date_created': new Date(),
        'date_updated': null,
        'image': ''
      };

      category.name = parse.getString(data.name);
      category.description = parse.getString(data.description);
      category.meta_description = parse.getString(data.meta_description);
      category.meta_title = parse.getString(data.meta_title);
      category.enabled = parse.getBooleanIfValid(data.enabled, true);
      category.sort = parse.getString(data.sort);
      category.parent_id = parse.getObjectIDIfValid(data.parent_id);
      category.position = parse.getNumberIfValid(data.position) || newPosition;

      let slug = (!data.slug || data.slug.length === 0) ? data.name : data.slug;
      if(!slug || slug.length === 0) {
        return Promise.resolve(category);
      } else {
        return utils.getAvailableSlug(slug).then(newSlug => {
          category.slug = newSlug;
          return category;
        });
      }
  }

  getValidDocumentForUpdate(id, data) {
    return new Promise((resolve, reject) => {
      if(!ObjectID.isValid(id)) {
        reject('Invalid identifier');
      }
      if (Object.keys(data).length === 0) {
        reject('Required fields are missing');
      }

      let category = {
        'date_updated': new Date()
      };

      if(data.name !== undefined) {
        category.name = parse.getString(data.name);
      }

      if(data.description !== undefined) {
        category.description = parse.getString(data.description);
      }

      if(data.meta_description !== undefined) {
        category.meta_description = parse.getString(data.meta_description);
      }

      if(data.meta_title !== undefined) {
        category.meta_title = parse.getString(data.meta_title);
      }

      if(data.enabled !== undefined) {
        category.enabled = parse.getBooleanIfValid(data.enabled, true);
      }

      if(data.image !== undefined) {
        category.image = data.image;
      }

      if(data.position >= 0) {
        category.position = data.position;
      }

      if(data.sort !== undefined) {
        category.sort = data.sort;
      }

      if(data.parent_id !== undefined) {
        category.parent_id = parse.getObjectIDIfValid(data.parent_id);
      }

      if(data.slug !== undefined){
        let slug = data.slug;
        if(!slug || slug.length === 0) {
          slug = data.name;
        }

        utils.getAvailableSlug(slug, id)
        .then((newSlug) => {
          category.slug = newSlug;
          resolve(category);
        })
        .catch((err) => {
          reject(err);
        });

      } else {
        resolve(category);
      }
    });
  }

  changeProperties(item, domain) {
    if(item) {
      item.id = item._id.toString();
      item._id = undefined;

      if(item.parent_id) {
        item.parent_id = item.parent_id.toString();
      }

      if(item.slug) {
        item.url = url.resolve(domain, item.slug || '');
        item.path = url.resolve('/', item.slug || '');
      }

      if(item.image) {
        item.image = url.resolve(domain, settings.categoriesUploadUrl + '/' + item.id + '/' + item.image);
      }
    }

    return item;
  }

  deleteCategoryImage(id) {
    let dir = path.resolve(settings.categoriesUploadPath + '/' + id);
    fse.emptyDirSync(dir);
    this.updateCategory(id, { 'image': '' });
  }

  uploadCategoryImage(req, res) {
    let categoryId = req.params.id;
    let form = new formidable.IncomingForm(),
        file_name = null,
        file_size = 0;

    form
      .on('fileBegin', (name, file) => {
        // Emitted whenever a field / value pair has been received.
        let dir = path.resolve(settings.categoriesUploadPath + '/' + categoryId);
        fse.emptyDirSync(dir);
        file.name = utils.getCorrectFileName(file.name);
        file.path = dir + '/' + file.name;
      })
      .on('file', function(field, file) {
        // every time a file has been uploaded successfully,
        file_name = file.name;
        file_size = file.size;
      })
      .on('error', (err) => {
        res.status(500).send(this.getErrorMessage(err));
      })
      .on('end', () => {
        //Emitted when the entire request has been received, and all contained files have finished flushing to disk.
        if(file_name) {
          this.updateCategory(categoryId, { 'image': file_name });
          res.send({ 'file': file_name, 'size': file_size });
        } else {
          res.status(400).send(this.getErrorMessage('Required fields are missing'));
        }
      });

    form.parse(req);
  }

}

module.exports = new ProductCategoriesService();
<commit_msg>Remove mongodb nextObject<commit_after>'use strict';

const path = require('path');
const url = require('url');
const formidable = require('formidable');
const fse = require('fs-extra');
const ObjectID = require('mongodb').ObjectID;
const settings = require('../../lib/settings');
const SettingsService = require('../settings/settings');
const mongo = require('../../lib/mongo');
const utils = require('../../lib/utils');
const parse = require('../../lib/parse');

class ProductCategoriesService {
  constructor() {}

  getFilter(params = {}) {
    let filter = {};
    const enabled = parse.getBooleanIfValid(params.enabled);
    if (enabled !== null) {
      filter.enabled = enabled;
    }
    const id = parse.getObjectIDIfValid(params.id);
    if (id) {
      filter._id = id;
    }
    return filter;
  }

  async getCategories(params = {}) {
    const filter = this.getFilter(params);
    const projection = utils.getProjectionFromFields(params.fields);
    const generalSettings = await SettingsService.getSettings();
    const domain = generalSettings.domain;
    const items = await mongo.db.collection('productCategories').find(filter, { projection: projection }).sort({position: 1}).toArray();
    const result = items.map(category => this.changeProperties(category, domain));
    return result;
  }

  getSingleCategory(id) {
    if (!ObjectID.isValid(id)) {
      return Promise.reject('Invalid identifier');
    }
    return this.getCategories({id: id}).then(categories => {
      return categories.length > 0
        ? categories[0]
        : null;
    })
  }

  async addCategory(data) {
    const lastCategory = await mongo.db.collection('productCategories').findOne({}, { sort: {position: -1} });
    const newPosition = (lastCategory && lastCategory.position > 0) ? lastCategory.position + 1 : 1;
    const dataToInsert = await this.getValidDocumentForInsert(data, newPosition);
    const insertResult = await mongo.db.collection('productCategories').insertMany([dataToInsert]);
    return this.getSingleCategory(insertResult.ops[0]._id.toString());
  }

  updateCategory(id, data) {
    if(!ObjectID.isValid(id)) {
      return Promise.reject('Invalid identifier');
    }
    let categoryObjectID = new ObjectID(id);

    return this.getValidDocumentForUpdate(id, data)
      .then(dataToSet => mongo.db.collection('productCategories').updateOne({ _id: categoryObjectID }, {$set: dataToSet}))
      .then(res => res.modifiedCount > 0 ? this.getSingleCategory(id) : null)
  }

  findAllChildren(items, id, result) {
    if(id && ObjectID.isValid(id)) {
      result.push(new ObjectID(id));
      let finded = items.filter(item => ((item.parent_id || '').toString() === id.toString()));
      if(finded.length > 0) {
        for(let item of finded) {
          this.findAllChildren(items, item.id, result);
        }
      }
    }

    return result;
  }

  deleteCategory(id) {
    if(!ObjectID.isValid(id)) {
      return Promise.reject('Invalid identifier');
    }

    // 1. get all categories
    return this.getCategories()
    .then(items => {
      // 2. find category and children
      let idsToDelete = [];
      this.findAllChildren(items, id, idsToDelete);
      return idsToDelete;
    })
    .then(idsToDelete => {
      // 3. delete categories
      let objectsToDelete = idsToDelete.map((id) => ( new ObjectID(id) ));
      // return mongo.db.collection('productCategories').deleteMany({_id: { $in: objectsToDelete}}).then(() => idsToDelete);
      return mongo.db.collection('productCategories').deleteMany({_id: { $in: objectsToDelete}}).then(deleteResponse => deleteResponse.deletedCount > 0 ? idsToDelete : null);
    })
    .then(idsToDelete => {
      // 4. update category_id for products
      return idsToDelete ? mongo.db.collection('products').updateMany({ category_id: { $in: idsToDelete}}, { $set: { category_id: null }}).then(() => idsToDelete) : null;
    })
    .then(idsToDelete => {
      // 5. delete directories with images
      if(idsToDelete) {
        for(let categoryId of idsToDelete) {
          let deleteDir = path.resolve(settings.categoriesUploadPath + '/' + categoryId);
          fse.remove(deleteDir, err => {});
        }
        return Promise.resolve(true);
      } else {
        return Promise.resolve(false);
      }
    });
  }

  getErrorMessage(err) {
    return { 'error': true, 'message': err.toString() };
  }

  getValidDocumentForInsert(data, newPosition) {
      //  Allow empty category to create draft

      let category = {
        'date_created': new Date(),
        'date_updated': null,
        'image': ''
      };

      category.name = parse.getString(data.name);
      category.description = parse.getString(data.description);
      category.meta_description = parse.getString(data.meta_description);
      category.meta_title = parse.getString(data.meta_title);
      category.enabled = parse.getBooleanIfValid(data.enabled, true);
      category.sort = parse.getString(data.sort);
      category.parent_id = parse.getObjectIDIfValid(data.parent_id);
      category.position = parse.getNumberIfValid(data.position) || newPosition;

      let slug = (!data.slug || data.slug.length === 0) ? data.name : data.slug;
      if(!slug || slug.length === 0) {
        return Promise.resolve(category);
      } else {
        return utils.getAvailableSlug(slug).then(newSlug => {
          category.slug = newSlug;
          return category;
        });
      }
  }

  getValidDocumentForUpdate(id, data) {
    return new Promise((resolve, reject) => {
      if(!ObjectID.isValid(id)) {
        reject('Invalid identifier');
      }
      if (Object.keys(data).length === 0) {
        reject('Required fields are missing');
      }

      let category = {
        'date_updated': new Date()
      };

      if(data.name !== undefined) {
        category.name = parse.getString(data.name);
      }

      if(data.description !== undefined) {
        category.description = parse.getString(data.description);
      }

      if(data.meta_description !== undefined) {
        category.meta_description = parse.getString(data.meta_description);
      }

      if(data.meta_title !== undefined) {
        category.meta_title = parse.getString(data.meta_title);
      }

      if(data.enabled !== undefined) {
        category.enabled = parse.getBooleanIfValid(data.enabled, true);
      }

      if(data.image !== undefined) {
        category.image = data.image;
      }

      if(data.position >= 0) {
        category.position = data.position;
      }

      if(data.sort !== undefined) {
        category.sort = data.sort;
      }

      if(data.parent_id !== undefined) {
        category.parent_id = parse.getObjectIDIfValid(data.parent_id);
      }

      if(data.slug !== undefined){
        let slug = data.slug;
        if(!slug || slug.length === 0) {
          slug = data.name;
        }

        utils.getAvailableSlug(slug, id)
        .then((newSlug) => {
          category.slug = newSlug;
          resolve(category);
        })
        .catch((err) => {
          reject(err);
        });

      } else {
        resolve(category);
      }
    });
  }

  changeProperties(item, domain) {
    if(item) {
      item.id = item._id.toString();
      item._id = undefined;

      if(item.parent_id) {
        item.parent_id = item.parent_id.toString();
      }

      if(item.slug) {
        item.url = url.resolve(domain, item.slug || '');
        item.path = url.resolve('/', item.slug || '');
      }

      if(item.image) {
        item.image = url.resolve(domain, settings.categoriesUploadUrl + '/' + item.id + '/' + item.image);
      }
    }

    return item;
  }

  deleteCategoryImage(id) {
    let dir = path.resolve(settings.categoriesUploadPath + '/' + id);
    fse.emptyDirSync(dir);
    this.updateCategory(id, { 'image': '' });
  }

  uploadCategoryImage(req, res) {
    let categoryId = req.params.id;
    let form = new formidable.IncomingForm(),
        file_name = null,
        file_size = 0;

    form
      .on('fileBegin', (name, file) => {
        // Emitted whenever a field / value pair has been received.
        let dir = path.resolve(settings.categoriesUploadPath + '/' + categoryId);
        fse.emptyDirSync(dir);
        file.name = utils.getCorrectFileName(file.name);
        file.path = dir + '/' + file.name;
      })
      .on('file', function(field, file) {
        // every time a file has been uploaded successfully,
        file_name = file.name;
        file_size = file.size;
      })
      .on('error', (err) => {
        res.status(500).send(this.getErrorMessage(err));
      })
      .on('end', () => {
        //Emitted when the entire request has been received, and all contained files have finished flushing to disk.
        if(file_name) {
          this.updateCategory(categoryId, { 'image': file_name });
          res.send({ 'file': file_name, 'size': file_size });
        } else {
          res.status(400).send(this.getErrorMessage('Required fields are missing'));
        }
      });

    form.parse(req);
  }

}

module.exports = new ProductCategoriesService();
<|endoftext|>


<commit_before><commit_msg>Moved getView logic inside select component<commit_after><|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var request = require('request');
var config = require('config.json');

router.get('/', function (req, res) {
    res.render('register');
});

router.post('/', function (req, res) {
    // register using api to maintain clean separation between layers
    request.post({
        url: process.env.PORT + '/users/register',
        form: req.body,
        json: true
    }, function (error, response, body) {
        if (error) {
            console.log(error);
            return res.render('register', { error: 'Brah' });
        }

        if (response.statusCode !== 200) {
            return res.render('register', {
                error: response.body,
                firstName: req.body.firstName,
                lastName: req.body.lastName,
                username: req.body.username
            });
        }

        // return to login page with success message
        req.session.success = 'Registration successful';
        return res.redirect('/login');
    });
});

module.exports = router;<commit_msg>update2<commit_after>var express = require('express');
var router = express.Router();
var request = require('request');
var config = require('config.json');

router.get('/', function (req, res) {
    res.render('register');
});

router.post('/', function (req, res) {
    // register using api to maintain clean separation between layers
    request.post({
        url: process.env.PORT + '127.0.0.01' + '/users/register',
        form: req.body,
        json: true
    }, function (error, response, body) {
        if (error) {
            console.log(error);
            return res.render('register', { error: 'Brah' });
        }

        if (response.statusCode !== 200) {
            return res.render('register', {
                error: response.body,
                firstName: req.body.firstName,
                lastName: req.body.lastName,
                username: req.body.username
            });
        }

        // return to login page with success message
        req.session.success = 'Registration successful';
        return res.redirect('/login');
    });
});

module.exports = router;<|endoftext|>