<commit_before>var animationEnd = "animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd";
var transitionEnd = "transitionend webkitTransitionEnd oTransitionEnd otransitionend";

var CHADEV = CHADEV || {};
var IS_VOTING_DAY = Date.today().is().thursday();

CHADEV.votingBooth = {
  init: function(mode) {
    switch(mode) {
      case "demo":
        this.mode = "demo"
        this.db = "demo"
        this.multipleVotes = true;
        this.closeResults = true;
        this.thanksDelay = 1400;
        $.cookie('mode', this.mode, { expires: 1 });
        break;
      case "kiosk":
        this.mode = "kiosk"
        this.multipleVotes = true;
        this.closeResults = false;
        this.thanksDelay = 800;
        $.cookie('mode', this.mode, { expires: 5 });
        break;
      default:
        this.mode = "individual"
        this.multipleVotes = false;
        this.closeResults = false;
        this.thanksDelay = 1400;
    }

    this.firebaseRef = new Firebase("https://chadev-voting-"+ this.db +".firebaseio.com/");
    console.log("using " + this.db + " firebase db")

    console.log("Initializing voting booth ("+ this.mode +" mode)")
    $('.voting-booth').addClass('voting-booth-mode-' + this.mode);

    // Forcing to go online - sometimes app gets disconnected
    Firebase.goOnline();
    this.votesRef = this.firebaseRef.child("votes");

    var startEventType = 'mousedown';
    var endEventType   = 'mouseup';

    if (Modernizr.touch === true) {
      startEventType = 'touchstart';
      endEventType   = 'touchend';
    }

    console.log('CHADEV.votingBooth.mode',CHADEV.votingBooth.mode)
    if(!IS_VOTING_DAY && CHADEV.votingBooth.db == 'prod') {
      this.changeState('closed');
    } else {
      this.changeState('voting');
    }

    // Handle vote tap down
    $('button.voting-booth-item-action').on(startEventType, function() {
      $(this).parent().addClass('has-mousedown');
    });

    $(document).on(endEventType, function() {
      $('.voting-booth-item').removeClass('has-mousedown');
    });

    // Handle vote tap release
    $('button.voting-booth-item-action').on(endEventType, function() {

      // Disable button to prevent multiple votes from individual
      $('button.voting-booth-item-action').prop("disabled", true);

      // Send data to Firebase
      var voteItem = $(this).parent();
      CHADEV.votingBooth.votesRef.push({
        ended_at: Firebase.ServerValue.TIMESTAMP,
        vote: voteItem.data('vote')
      }, function(error) {
        if(error) {
          alert("Data could not be saved :( Jordan has failed you.");
          console.log("Error code: " + error.code);

        } else {
          if(!CHADEV.votingBooth.multipleVotes) {
            $.cookie('voted', true, { expires: 5 });
          };

          // After button is done transitioning, show thanks prompt
          voteItem.addClass('has-mouseup').bind(transitionEnd, function() {
            CHADEV.votingBooth.changeState('thanks');

            var thanksPrompt = $('.voting-booth-thanks-prompt[data-vote='+ voteItem.data('vote') +']');
            thanksPrompt.addClass('is-active');

            voteItem.unbind(transitionEnd);

            setTimeout(function() {
              // After showing thanks message for a bit, reset states and show the results
              CHADEV.votingBooth.changeState('seen-thanks');

              thanksPrompt.bind(animationEnd, function() {
                thanksPrompt
                .removeClass('is-active')
                .unbind(animationEnd);
                voteItem
                .removeClass('has-mouseup has-mousedown')
                .unbind(transitionEnd);

                if(CHADEV.votingBooth.multipleVotes) {
                  console.log('In kiosk mode, skipping results');
                  CHADEV.votingBooth.changeState('voting');
                } else {
                  CHADEV.votingBooth.changeState('results');

                  $('.bar-chart').bind(animationEnd, function() {
                    CHADEV.votingBooth.populateResults();
                    $('.bar-chart').unbind(animationEnd);
                  });
                }
              });
            }, CHADEV.votingBooth.thanksDelay);

          });

          $('button.voting-booth-item-action').prop("disabled", false);
        }
      });
    });
  },

  populateResults: function() {
    var ref = CHADEV.votingBooth.votesRef;
    var sixDays = 6 * 24 * 60 * 60 * 1000;
    var startAt = new Date().getTime() - sixDays;

    ref.orderByChild('ended_at').startAt(startAt).on("value", function(snapshot) {
      var totalVotes = snapshot.numChildren();
      var dislikeVotes = 0;
      var neutralVotes = 0;
      var likeVotes = 0;

      snapshot.forEach(function(voteSnapshot) {
        switch(voteSnapshot.child('vote').val()) {
          case "dislike":
            dislikeVotes += 1;
            break;
          case "neutral":
            neutralVotes += 1;
            break;
          case "like":
            likeVotes += 1;
            break;
        }
      });

      console.log('Populating results');

      CHADEV.votingBooth.vote($('.bar-chart-item.is-dislike'), dislikeVotes, totalVotes);
      CHADEV.votingBooth.vote($('.bar-chart-item.is-neutral'), neutralVotes, totalVotes);
      CHADEV.votingBooth.vote($('.bar-chart-item.is-like'), likeVotes, totalVotes);

      $('.bar-chart-item').bind(transitionEnd, function(){
        CHADEV.votingBooth.changeState('seen-results');
        $('.bar-chart-item').unbind(transitionEnd);
      });

    }, function (errorObject) {
      console.log("The read failed: " + errorObject.code);
    });
  },

  vote: function(barChartItem, itemVotes, totalVotes) {
    var percentage = (itemVotes / totalVotes) * 100;

    barChartItem
      .find('.bar-chart-item-count').text(itemVotes).end()
      .find('.bar-chart-item-bar').css('height', percentage + "%");

    if($('.voting-booth').hasClass('has-seen-results')) {
      console.log('Voting')
      barChartItem.addClass('has-new-vote');
      setTimeout(function() {
        barChartItem.removeClass('has-new-vote');
      }, 1000);
    }
  },

  changeState: function(state) {
    // Remove all modifiers
    $('.voting-booth').removeClass (function (index, css) {
      return (css.match (/(?:is-|has-)\S+/g) || []).join(' ');
    });

    switch(state) {
      case "closed":
        $('.voting-booth').addClass('is-closed');
        break;
      case "voting":
        $('.voting-booth').addClass('is-voting');
        break;
      case "seen-thanks":
        $('.voting-booth').addClass('has-seen-thanks');
        break;
      case "thanks":
        $('.voting-booth').addClass('is-viewing-thanks');
        break;
      case "results":
        $('.voting-booth').addClass('is-viewing-results');
        break;
      case "seen-results":
        $('.voting-booth').addClass('has-seen-results');
        break;
    }
  }
}

function getUrlParameter(sParam)
{
  var sPageURL = window.location.search.substring(1);
  var sURLVariables = sPageURL.split('&');
  for (var i = 0; i < sURLVariables.length; i++)
  {
    var sParameterName = sURLVariables[i].split('=');
    if (sParameterName[0] == sParam)
    {
      return sParameterName[1];
    }
  }
}

$(function() {
  FastClick.attach(document.body);
});

$(window).load(function() {
  if($.cookie('mode') !== undefined) {
    var mode = $.cookie('mode');$.cookie('mode');
    console.log('Initiating with cookie: ' + mode)
  } else {
    var mode = getUrlParameter('mode');
  }

  CHADEV.votingBooth.init(mode);

  if($.cookie('voted')) {
    console.log('Already voted, showing results')
    CHADEV.votingBooth.changeState('results');
    CHADEV.votingBooth.populateResults();
  }
});
<commit_msg>Cleaning up console messages<commit_after>var animationEnd = "animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd";
var transitionEnd = "transitionend webkitTransitionEnd oTransitionEnd otransitionend";

var CHADEV = CHADEV || {};
var IS_VOTING_DAY = Date.today().is().thursday();

CHADEV.votingBooth = {
  init: function(mode) {
    switch(mode) {
      case "demo":
        this.mode = "demo"
        this.db = "demo"
        this.multipleVotes = true;
        this.closeResults = true;
        this.thanksDelay = 1400;
        $.cookie('mode', this.mode, { expires: 1 });
        break;
      case "kiosk":
        this.mode = "kiosk"
        this.multipleVotes = true;
        this.closeResults = false;
        this.thanksDelay = 800;
        $.cookie('mode', this.mode, { expires: 5 });
        break;
      default:
        this.mode = "individual"
        this.multipleVotes = false;
        this.closeResults = false;
        this.thanksDelay = 1400;
    }

    this.firebaseRef = new Firebase("https://chadev-voting-"+ this.db +".firebaseio.com/");
    console.log("Using Firebase DB", this.db)

    console.log("Initializing voting booth", this.mode)
    $('.voting-booth').addClass('voting-booth-mode-' + this.mode);

    // Forcing to go online - sometimes app gets disconnected
    Firebase.goOnline();
    this.votesRef = this.firebaseRef.child("votes");

    var startEventType = 'mousedown';
    var endEventType   = 'mouseup';

    if (Modernizr.touch === true) {
      startEventType = 'touchstart';
      endEventType   = 'touchend';
    }

    if(!IS_VOTING_DAY && CHADEV.votingBooth.db == 'prod') {
      this.changeState('closed');
    } else {
      this.changeState('voting');
    }

    // Handle vote tap down
    $('button.voting-booth-item-action').on(startEventType, function() {
      $(this).parent().addClass('has-mousedown');
    });

    $(document).on(endEventType, function() {
      $('.voting-booth-item').removeClass('has-mousedown');
    });

    // Handle vote tap release
    $('button.voting-booth-item-action').on(endEventType, function() {

      // Disable button to prevent multiple votes from individual
      $('button.voting-booth-item-action').prop("disabled", true);

      // Send data to Firebase
      var voteItem = $(this).parent();
      CHADEV.votingBooth.votesRef.push({
        ended_at: Firebase.ServerValue.TIMESTAMP,
        vote: voteItem.data('vote')
      }, function(error) {
        if(error) {
          alert("Data could not be saved :( Jordan has failed you.");
          console.log("Error code: " + error.code);

        } else {
          if(!CHADEV.votingBooth.multipleVotes) {
            $.cookie('voted', true, { expires: 5 });
          };

          // After button is done transitioning, show thanks prompt
          voteItem.addClass('has-mouseup').bind(transitionEnd, function() {
            CHADEV.votingBooth.changeState('thanks');

            var thanksPrompt = $('.voting-booth-thanks-prompt[data-vote='+ voteItem.data('vote') +']');
            thanksPrompt.addClass('is-active');

            voteItem.unbind(transitionEnd);

            setTimeout(function() {
              // After showing thanks message for a bit, reset states and show the results
              CHADEV.votingBooth.changeState('seen-thanks');

              thanksPrompt.bind(animationEnd, function() {
                thanksPrompt
                .removeClass('is-active')
                .unbind(animationEnd);
                voteItem
                .removeClass('has-mouseup has-mousedown')
                .unbind(transitionEnd);

                if(CHADEV.votingBooth.multipleVotes) {
                  console.log('In kiosk mode, skipping results');
                  CHADEV.votingBooth.changeState('voting');
                } else {
                  CHADEV.votingBooth.changeState('results');

                  $('.bar-chart').bind(animationEnd, function() {
                    CHADEV.votingBooth.populateResults();
                    $('.bar-chart').unbind(animationEnd);
                  });
                }
              });
            }, CHADEV.votingBooth.thanksDelay);

          });

          $('button.voting-booth-item-action').prop("disabled", false);
        }
      });
    });
  },

  populateResults: function() {
    var ref = CHADEV.votingBooth.votesRef;
    var sixDays = 6 * 24 * 60 * 60 * 1000;
    var startAt = new Date().getTime() - sixDays;

    ref.orderByChild('ended_at').startAt(startAt).on("value", function(snapshot) {
      var totalVotes = snapshot.numChildren();
      var dislikeVotes = 0;
      var neutralVotes = 0;
      var likeVotes = 0;

      snapshot.forEach(function(voteSnapshot) {
        switch(voteSnapshot.child('vote').val()) {
          case "dislike":
            dislikeVotes += 1;
            break;
          case "neutral":
            neutralVotes += 1;
            break;
          case "like":
            likeVotes += 1;
            break;
        }
      });

      console.log('Populating results');

      CHADEV.votingBooth.vote($('.bar-chart-item.is-dislike'), dislikeVotes, totalVotes);
      CHADEV.votingBooth.vote($('.bar-chart-item.is-neutral'), neutralVotes, totalVotes);
      CHADEV.votingBooth.vote($('.bar-chart-item.is-like'), likeVotes, totalVotes);

      $('.bar-chart-item').bind(transitionEnd, function(){
        CHADEV.votingBooth.changeState('seen-results');
        $('.bar-chart-item').unbind(transitionEnd);
      });

    }, function (errorObject) {
      console.log("The read failed: " + errorObject.code);
    });
  },

  vote: function(barChartItem, itemVotes, totalVotes) {
    var percentage = (itemVotes / totalVotes) * 100;

    barChartItem
      .find('.bar-chart-item-count').text(itemVotes).end()
      .find('.bar-chart-item-bar').css('height', percentage + "%");

    if($('.voting-booth').hasClass('has-seen-results')) {
      console.log('Voting')
      barChartItem.addClass('has-new-vote');
      setTimeout(function() {
        barChartItem.removeClass('has-new-vote');
      }, 1000);
    }
  },

  changeState: function(state) {
    // Remove all modifiers
    $('.voting-booth').removeClass (function (index, css) {
      return (css.match (/(?:is-|has-)\S+/g) || []).join(' ');
    });

    switch(state) {
      case "closed":
        $('.voting-booth').addClass('is-closed');
        break;
      case "voting":
        $('.voting-booth').addClass('is-voting');
        break;
      case "seen-thanks":
        $('.voting-booth').addClass('has-seen-thanks');
        break;
      case "thanks":
        $('.voting-booth').addClass('is-viewing-thanks');
        break;
      case "results":
        $('.voting-booth').addClass('is-viewing-results');
        break;
      case "seen-results":
        $('.voting-booth').addClass('has-seen-results');
        break;
    }
  }
}

function getUrlParameter(sParam)
{
  var sPageURL = window.location.search.substring(1);
  var sURLVariables = sPageURL.split('&');
  for (var i = 0; i < sURLVariables.length; i++)
  {
    var sParameterName = sURLVariables[i].split('=');
    if (sParameterName[0] == sParam)
    {
      return sParameterName[1];
    }
  }
}

$(function() {
  FastClick.attach(document.body);
});

$(window).load(function() {
  if($.cookie('mode') !== undefined) {
    var mode = $.cookie('mode');$.cookie('mode');
    console.log('Initiating with cookie: ' + mode)
  } else {
    var mode = getUrlParameter('mode');
  }

  CHADEV.votingBooth.init(mode);

  if($.cookie('voted')) {
    console.log('Already voted, showing results')
    CHADEV.votingBooth.changeState('results');
    CHADEV.votingBooth.populateResults();
  }
});
<|endoftext|>


<commit_before>/* eslint-env mocha, jest */

import getDefault from '../../shared/testUtils';
import EditIdeaDialog from '../EditIdeaDialog';

const defaultProps = {
  open: false,
  idea: '',
  onRequestClose() {},
  onRequestEdit() {},
};
const getActualDialog = getDefault(EditIdeaDialog, defaultProps);

it('should render', () => {
  getActualDialog();
});
it('should be a <div />', () => {
  const wrapper = getActualDialog();
  expect(wrapper.is('div.EditIdeaDialog')).toBe(true);
});
it('should have a <Dialog />', () => {
  const wrapper = getActualDialog();
  expect(wrapper.find('Dialog').length).toBe(1);
});
it('should show/hide <Dialog /> based on props', () => {
  const wrapper = getActualDialog({
    open: true,
  });
  expect(wrapper.find('Dialog').prop('open')).toBe(true);
});
it('should set text field default value based on props', () => {
  const wrapper = getActualDialog({
    idea: 'a cool idea',
  });
  expect(wrapper.find('TextField').prop('defaultValue')).toBe('a cool idea');
});
it('should call onRequestClose in handling close request', (done) => {
  const wrapper = getActualDialog({
    onRequestClose() {
      done();
    },
  });
  wrapper.instance().handleRequestClose();
});
it('should call onRequestEdit in handling edit request', (done) => {
  const wrapper = getActualDialog({
    onRequestEdit() {
      done();
    },
  });
  wrapper.instance().handleRequestEdit();
});
<commit_msg>Add EditIdeaDialog state unit test<commit_after>/* eslint-env mocha, jest */

import getDefault from '../../shared/testUtils';
import EditIdeaDialog from '../EditIdeaDialog';

const defaultProps = {
  open: false,
  idea: '',
  onRequestClose() {},
  onRequestEdit() {},
};
const getActualDialog = getDefault(EditIdeaDialog, defaultProps);

it('should render', () => {
  getActualDialog();
});
it('should be a <div />', () => {
  const wrapper = getActualDialog();
  expect(wrapper.is('div.EditIdeaDialog')).toBe(true);
});
it('should have a <Dialog />', () => {
  const wrapper = getActualDialog();
  expect(wrapper.find('Dialog').length).toBe(1);
});
it('should show/hide <Dialog /> based on props', () => {
  const wrapper = getActualDialog({
    open: true,
  });
  expect(wrapper.find('Dialog').prop('open')).toBe(true);
});
it('should set text field default value based on props', () => {
  const wrapper = getActualDialog({
    idea: 'a cool idea',
  });
  expect(wrapper.find('TextField').prop('defaultValue')).toBe('a cool idea');
});
it('should call onRequestClose in handling close request', (done) => {
  const wrapper = getActualDialog({
    onRequestClose() {
      done();
    },
  });
  wrapper.instance().handleRequestClose();
});
it('should call onRequestEdit in handling edit request', (done) => {
  const wrapper = getActualDialog({
    onRequestEdit() {
      done();
    },
  });
  wrapper.instance().handleRequestEdit();
});

it('should set FlatButton disabled based on state', () => {
  const wrapper = getActualDialog();
  wrapper.find('TextField').props().onChange({ target: { value: 'a cool idea' } });
  expect(wrapper.find('Dialog').prop('actions')[0].props.disabled).toBe(false);
});
<|endoftext|>


<commit_before>var _ = require('underscore');
var backbone = require('backbone');
var backboneBase = require('backbone-base');
var Goodtables = require('goodtables');
var navigation = require('./navigation');
var validationErrorRowTpl = require('./templates/validation-error-row.hbs');
var validator = require('validator');

module.exports = {
  // Render reource data file validation error
  ListView: backbone.BaseListView.extend({
    // Hide newly added results if they are for another tab
    addItemView: function(view, container) {
      this.$('#ok-message').prop('hidden', true);
      view.activate(view.model.get('resource_id') === this.parent.activeResource);
      backbone.BaseListView.prototype.addItemView.call(this, view);
      return this;
    },

    clear: function() {
      backbone.BaseListView.prototype.clear.call(this);
      this.$('#ok-message').prop('hidden', false);
      this.parent.layout.tabs.clear();
      return this;
    },

    ItemView: backbone.BaseView.extend({
      attributes: {class: 'result panel panel-default'},

      render: function() {
        this.$el.html(this.template(_.extend(this.model.toJSON(), {
          isheader: this.model.get('row_index') === 0
        })));

        return this;
      },

      template: validationErrorRowTpl
    }),

    reset: function(collection) {
      backbone.BaseListView.prototype.reset.call(this, collection);
      this.collection.on('add', this.add, this);
      return this;
    }
  }),

  // Errors list with tabs for navigating between errors groupped by resource
  ValidationResultsView: backbone.BaseView.extend({
    events: {'click [data-id=back]': function() { window.ROUTER.navigate('/', {trigger: true}); return false; }},

    render: function() {
      this.layout.tabs = new navigation.TabsView({el: this.$('[data-id=tabs]')});
      this.layout.list = new module.exports.ListView({el: this.$('[data-id=errors-list]'), parent: this});
      return this;
    },

    validateResources: function(resourcesRows) {
      var goodTables = new Goodtables({method: 'post', report_type: 'grouped'});

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

      this.layout.list.reset(new backbone.Collection());

      _.each(resourcesRows, function(R) {
        var that = this;

        // Conditional promises
        (function() {
          // Resource was downloaded by user
          if(R.dataSource)
            return goodTables.run(R.dataSource.data, JSON.stringify(R.dataSource.schema));

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

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

          // Default fall back
          return new Promise(function(RS, RJ) { RS(false); });
        })()

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

            // Validation completed
            that.layout.list.collection

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

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

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

            navigateToResults(R.key);
          })

          .catch(console.log);
      }, this);
    },

    // Show certain resource validation errors
    setActive: function(id) {
      this.activeResource = id;
      this.layout.list.layout.items.forEach(function(I) { I.activate(I.model.get('resource_id') === id); });
      return this;
    }
  })
};
<commit_msg>More detailed comment<commit_after>var _ = require('underscore');
var backbone = require('backbone');
var backboneBase = require('backbone-base');
var Goodtables = require('goodtables');
var navigation = require('./navigation');
var validationErrorRowTpl = require('./templates/validation-error-row.hbs');
var validator = require('validator');

module.exports = {
  // Render reource data file validation error
  ListView: backbone.BaseListView.extend({
    // Hide newly added results if they are for another tab
    addItemView: function(view, container) {
      this.$('#ok-message').prop('hidden', true);
      view.activate(view.model.get('resource_id') === this.parent.activeResource);
      backbone.BaseListView.prototype.addItemView.call(this, view);
      return this;
    },

    clear: function() {
      backbone.BaseListView.prototype.clear.call(this);
      this.$('#ok-message').prop('hidden', false);
      this.parent.layout.tabs.clear();
      return this;
    },

    ItemView: backbone.BaseView.extend({
      attributes: {class: 'result panel panel-default'},

      render: function() {
        this.$el.html(this.template(_.extend(this.model.toJSON(), {
          isheader: this.model.get('row_index') === 0
        })));

        return this;
      },

      template: validationErrorRowTpl
    }),

    reset: function(collection) {
      backbone.BaseListView.prototype.reset.call(this, collection);
      this.collection.on('add', this.add, this);
      return this;
    }
  }),

  // Errors list with tabs for navigating between errors groupped by resource
  ValidationResultsView: backbone.BaseView.extend({
    events: {'click [data-id=back]': function() { window.ROUTER.navigate('/', {trigger: true}); return false; }},

    render: function() {
      this.layout.tabs = new navigation.TabsView({el: this.$('[data-id=tabs]')});
      this.layout.list = new module.exports.ListView({el: this.$('[data-id=errors-list]'), parent: this});
      return this;
    },

    validateResources: function(resourcesRows) {
      var goodTables = new Goodtables({method: 'post', report_type: 'grouped'});

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

      this.layout.list.reset(new backbone.Collection());

      // Validate each row, one by one, render errors after each row validated
      _.each(resourcesRows, function(R) {
        var that = this;

        // Conditional promises
        (function() {
          // Resource was downloaded by user
          if(R.dataSource)
            return goodTables.run(R.dataSource.data, JSON.stringify(R.dataSource.schema));

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

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

          // Default fall back
          return new Promise(function(RS, RJ) { RS(false); });
        })()

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

            // Validation completed, render errors list
            that.layout.list.collection

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

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

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

            navigateToResults(R.key);
          })

          .catch(console.log);
      }, this);
    },

    // Show certain resource validation errors
    setActive: function(id) {
      this.activeResource = id;
      this.layout.list.layout.items.forEach(function(I) { I.activate(I.model.get('resource_id') === id); });
      return this;
    }
  })
};
<|endoftext|>


<commit_before>/* eslint-env mocha, jest */

import getDefault from '../../shared/testUtils';
import EditTaskDialog from '../EditTaskDialog';

const defaultProps = {
  open: false,
  task: '',
  onRequestClose() {},
  onRequestEdit() {},
};
const getActualDialog = getDefault(EditTaskDialog, defaultProps);

it('should render', () => {
  getActualDialog();
});
it('should be a <div />', () => {
  const wrapper = getActualDialog();
  expect(wrapper.is('div.EditTaskDialog')).toBe(true);
});
it('should have a <Dialog />', () => {
  const wrapper = getActualDialog();
  expect(wrapper.find('Dialog').length).toBe(1);
});
it('should show/hide <Dialog /> based on props', () => {
  const wrapper = getActualDialog({ open: true });
  expect(wrapper.find('Dialog').prop('open')).toBe(true);
});
it('should set text field default value based on props', () => {
  const wrapper = getActualDialog({
    task: 'a cool task',
  });
  expect(wrapper.find('TextField').prop('defaultValue')).toBe('a cool task');
});
it('should call onRequestClose in handling close request', (done) => {
  const wrapper = getActualDialog({
    onRequestClose() {
      done();
    },
  });
  wrapper.instance().handleRequestClose();
});
it('should call onRequestEdit in handling edit request', (done) => {
  const wrapper = getActualDialog({
    onRequestEdit() {
      done();
    },
  });
  wrapper.instance().handleRequestEdit();
});
<commit_msg>Add EditTaskDialog state unit test<commit_after>/* eslint-env mocha, jest */

import getDefault from '../../shared/testUtils';
import EditTaskDialog from '../EditTaskDialog';

const defaultProps = {
  open: false,
  task: '',
  onRequestClose() {},
  onRequestEdit() {},
};
const getActualDialog = getDefault(EditTaskDialog, defaultProps);

it('should render', () => {
  getActualDialog();
});
it('should be a <div />', () => {
  const wrapper = getActualDialog();
  expect(wrapper.is('div.EditTaskDialog')).toBe(true);
});
it('should have a <Dialog />', () => {
  const wrapper = getActualDialog();
  expect(wrapper.find('Dialog').length).toBe(1);
});
it('should show/hide <Dialog /> based on props', () => {
  const wrapper = getActualDialog({ open: true });
  expect(wrapper.find('Dialog').prop('open')).toBe(true);
});
it('should set text field default value based on props', () => {
  const wrapper = getActualDialog({
    task: 'a cool task',
  });
  expect(wrapper.find('TextField').prop('defaultValue')).toBe('a cool task');
});
it('should call onRequestClose in handling close request', (done) => {
  const wrapper = getActualDialog({
    onRequestClose() {
      done();
    },
  });
  wrapper.instance().handleRequestClose();
});
it('should call onRequestEdit in handling edit request', (done) => {
  const wrapper = getActualDialog({
    onRequestEdit() {
      done();
    },
  });
  wrapper.instance().handleRequestEdit();
});

it('should set FlatButton disabled based on state', () => {
  const wrapper = getActualDialog();
  wrapper.find('TextField').props().onChange({ target: { value: 'a cool task' } });
  expect(wrapper.find('Dialog').prop('actions')[0].props.disabled).toBe(false);
});
<|endoftext|>


<commit_before>(function ($) {
	var root = this;

	var RowAction = function (grid) {
		this.grid = grid;
	};
    RowAction.extend = function (props) {
        var parent = this;
        var child;

        child = function () {
            return parent.apply(this, arguments);
        };

        var Surrogate = function () {
            this.constructor = child;
        };
        Surrogate.prototype = parent.prototype;
        child.prototype = new Surrogate();

        if (props) {
            _.extend(child.prototype, props);
        }

        child.__super__ = parent.prototype;

        return child;
    };

    root.BasicRowActions = RowAction.extend({
        name: "BasicRowActions",
        render: function () {
            if (!this.el) {
                this.el = document.createElement("div");
                this.el.className = "sensei-grid-row-action sensei-grid-basic-row-actions";
                this.grid.$el.append(this.el);
            }
        }
    });

    // export
    root.RowAction = RowAction;

})(jQuery);<commit_msg>Create element with jQuery.<commit_after>(function ($) {
	var root = this;

	var RowAction = function (grid) {
		this.grid = grid;
	};
    RowAction.extend = function (props) {
        var parent = this;
        var child;

        child = function () {
            return parent.apply(this, arguments);
        };

        var Surrogate = function () {
            this.constructor = child;
        };
        Surrogate.prototype = parent.prototype;
        child.prototype = new Surrogate();

        if (props) {
            _.extend(child.prototype, props);
        }

        child.__super__ = parent.prototype;

        return child;
    };

    root.BasicRowActions = RowAction.extend({
        name: "BasicRowActions",
        render: function () {
            if (!this.el) {
            	var className = "sensei-grid-row-action sensei-grid-basic-row-actions";
                this.el = $("<div>").addClass(className);
                this.grid.$el.append(this.el);
            }
        }
    });

    // export
    root.RowAction = RowAction;

})(jQuery);<|endoftext|>


<commit_before>var logicalGroupDS = isc.DataSource.create({
  dataFormat: 'custom',
  dataURL: settings.logicalgroups_url,
  requestProperties: {
    params: {
      management: true,
      page_size: 1000
    }
  },
  defaultsNewNodesToRoot: true,
  fields:[
    {name: 'id', title: 'Id', type: 'text', canEdit: false},
    {name: 'url', title: 'Url', type: 'text', canEdit: false},
    {name: 'parents', title: 'Parent', type: 'text', foreignKey: 'url', rootValue: 'root'},
    {name: 'name', title: 'Naam'},
    {name: 'owner', title: 'Eigenaar'},
    {name: 'description', title: 'Beschrijving'}
  ],
  transformResponse: function(dsResponse) {
    var json_data = isc.JSON.decode(dsResponse.data);
    var result = [];

    //process data, to put nodes under multiple parent nodes
    for (var i = 0; i < json_data.results.length; i++ ) {
      var rec = json_data.results[i];
      rec.isFolder = true;

      if (rec.parents.length > 0) {
        for (var ii = 0; ii < rec.parents.length; ii++ ) {
          var sub_rec = isc.clone(rec);
          sub_rec._url = sub_rec.url;
          if (ii > 0) {
            sub_rec.id = null;
            sub_rec.url = null;
          }
          sub_rec.parents = rec.parents[ii];
          result.push(sub_rec);

        }
        //result.push(rec);
      } else {
        rec.parents = 'root';
        rec._url = rec.url;
        result.push(rec);
      }
    }
    dsResponse.data = result;
  }
});

var setLogicalGroupFormData = function(data) {

  timeseriesSelectionGrid.setData(data.timeseries);

  delete data['timeseries'];
  delete data['childs'];

  var parent_ids = []
  for (var i=0; i<data.parents.length; i++) {
    parent_ids.push(data.parents[i].parent_id);
  }
  data.parents = parent_ids;
  logicalGroupForm.setData(data);
  logicalGroupForm.setErrors([]);
}

var logicalGroupTree = isc.TreeGrid.create({
  dataSource: logicalGroupDS,
  width: 300,
  canReorderRecords: true,
  canAcceptDroppedRecords: true,
  autoFetchData:true,
  loadDataOnDemand:false,
  dataProperties:{
    dataArrived:function (parentNode) {
      this.openAll();
    },
    disableCacheSync: true
  },
  fields:[
    { name: 'name', formatCellValue: "return value + '  (' + record.owner + ')'" }
  ],
  rowClick: function(record) {
    RPCManager.sendRequest({
      actionURL: record._url,
      httpMethod: 'GET',
      callback: function(rpcResponse, data, rpcRequest) {
        var data = isc.JSON.decode(rpcResponse.data);
        setLogicalGroupFormData(data);
      }
    });
  }
});

//#####################################################################################################################

var logicalGroupForm = isc.DynamicForm.create({
  dataSource: logicalGroupDS,
  numCols: 2,
  colWidths: [100, 300],
  fields: [
    {type: 'header', defaultValue: "Logische Groep", width: "*"},
    {name: "id", title:"id", type: 'integer', canEdit: false},
    {name: "name", width: "*"},
    {
      name: "owner", type: "combo",
      width: "*",
      displayField: "name",
      valueField: "name",
      optionDataSource: isc.DataSource.create({
        dataFormat: 'json',
        recordXPath: "results",
        requestProperties: {
          params: {
            page_size: 1000,
            management: true
          }
        },
        dataURL: settings.dataowners_url,
        fields:[
          {name: 'id', title: 'iD', primaryKey: true},
          {name: 'name', title: 'Naam'}
        ]
      })
    },
    {name: "description", title: 'Beschrijving', type: 'textArea', width: "*"},
    {
      name: "parents",
      title: "Parents",
      editorType: "MultiComboBoxItem",
      defaultValue: [],
      optionDataSource: isc.DataSource.create({
        dataFormat: 'json',
        recordXPath: "results",
        requestProperties: {
          params: {
            page_size: 1000,
            management: true
          }
        },
        dataURL: settings.logicalgroups_url,
        fields:[
          {name: 'id', title: 'iD', primaryKey: true},
          {name: 'name', title: 'Naam'}
        ]
      }),
      displayField: "name",
      valueField: "id"
     // autoFetchData: true,
      //layoutStyle: initialLayoutStyle
    }
  ]
});

var timeseriesSelectionGrid = isc.ListGrid.create({
  width: 400,
  alternateRecordStyles:true,
  canReorderRecords: true,
  canAcceptDroppedRecords: true,
  preventDuplicates: true,
  fields:[
    {name:"id", title:"id", showIf: "return false"},
    {name:"url", title:"Url", showIf: "return false"},
    {name:"name", title:"Gselecteerde tijdseries - Naam"}
  ]
});

//#####################################################################################################################

var lgTimeseriesDS = isc.FilterPaginatedDataSource.create({
  autoFetchData: false,
  dataURL: settings.timeseries_url,
  requestProperties: {
    params: {
      management: true
    }
  },
  fields:[
    {name: 'id', title: 'id', hidden: true},
    {name: 'uuid', title: 'UUID'},
    {name: 'name', title: 'Naam'},
    {
      name: 'value_type', title: 'Waarde type', valueMap: ['integer', 'float', 'text', 'image',
      'georeferenced remote sensing', 'movie', 'file'], canFilter: false
    },
    {name: 'owner', title: 'Data eigenaar'},
    {name: 'location.name', title: 'Locatie'},
    {name: 'parameter', title: 'Parameter'},
    {name: 'unit', title: 'Eenheid'}
  ]
});

var lgTimeseries = isc.DefaultListGrid.create({
  //width:700,
  dataSource: lgTimeseriesDS,
  canDragRecordsOut: true,
  dragDataAction: 'copy',
  dataProperties:{
    disableCacheSync: true
  },
  canReorderFields: true
});

//#####################################################################################################################

var saveLogicalGroup = function(saveAsNew) {
  var data = logicalGroupForm.getData();
  var timeseries = timeseriesSelectionGrid.getData();

  data.parents = logicalGroupForm.getField('parents').getValue();
  var parents = [];
  for (var i=0; i<data.parents.length; i++) {
    parents.push({parent: data.parents[i]});
  }
  data.parents = parents;

  var timeseries_ids = [];
  for (var i=0; i<timeseries.length; i++) {
    timeseries_ids.push(timeseries[i].url);
  }
  data.timeseries = timeseries_ids;

  saveObject(logicalGroupForm, data, settings.logicalgroups_url, {
    saveAsNew: saveAsNew,
    reloadList: logicalGroupTree,
    setFormData: setLogicalGroupFormData
  });
}

logicalGroupPage = isc.HLayout.create({
  members: [
    logicalGroupTree,
    isc.VLayout.create({
      width: 400,
      padding: 10,
      membersMargin: 10,
      members: [
        logicalGroupForm,
        timeseriesSelectionGrid,
        isc.HLayout.create({
          height: 20,
          members: [
            isc.IButton.create({
              title: 'Annuleren',
              click: function() {
                logicalGroupForm.setData([]);
                logicalGroupForm.getField('parents').setValue([]); //reset this field manual
                logicalGroupForm.setErrors([]);
                timeseriesSelectionGrid.setData([]);
              }
            }),
            isc.IButton.create({
              title: 'Nieuw',
              click: function() {
                logicalGroupForm.setData([]);
                logicalGroupForm.getField('parents').setValue([]); //reset this field manual
                logicalGroupForm.setErrors([]);
                timeseriesSelectionGrid.setData([]);
              }
            }),
            isc.IButton.create({
              title: 'Opslaan',
              click: function() {
                saveLogicalGroup(false);
              }
            }),
            isc.IButton.create({
              title: 'Verwijderen',
              click: function() {
                var id = logicalGroupForm.getValue('id');
                if (id) {
                  RPCManager.sendRequest({
                    actionURL: logicalGroupForm.getData()['url'],
                    httpMethod: 'DELETE',
                    httpHeaders: {
                      'X-CSRFToken': document.cookie.split('=')[1]
                    },
                    callback: function(rpcResponse, data, rpcRequest) {
                      console.log('verwijderen gelukt');
                      logicalGroupForm.setData([]);
                      logicalGroupForm.setErrors([]);
                      timeseriesSelectionGrid.setData([]);
                      logicalGroupTree.fetchData({test: timestamp()}); //force new fetch with timestamp
                    }
                  });
                }
              }
            })
          ]
        })
      ]
    }),
    isc.VStack.create({width:32, height:74, layoutAlign:"center", membersMargin:10, members:[
      isc.Img.create({src: static_media_root + "ddsc_api/management/images/arrow_left.png", width:32, height:32,
        click: function() {
          timeseriesSelectionGrid.transferSelectedData(lgTimeseries);
        }
      }),
      isc.Img.create({src: static_media_root + "ddsc_api/management/images/arrow_right.png", width:32, height:32,
        click: function() {
          if (timeseriesSelectionGrid.getSelectedRecords()) {
            timeseriesSelectionGrid.data.removeAll(timeseriesSelectionGrid.getSelectedRecords());
          }

        }
      })
    ]}),
    lgTimeseries
  ]
});<commit_msg>fix api returning HTML on instead of JSON for logicalgroup management screen<commit_after>var logicalGroupDS = isc.DataSource.create({
  dataFormat: 'custom',
  dataURL: settings.logicalgroups_url,
  requestProperties: {
    params: {
      management: true,
      page_size: 1000,
      format: 'json'
    }
  },
  defaultsNewNodesToRoot: true,
  fields:[
    {name: 'id', title: 'Id', type: 'text', canEdit: false},
    {name: 'url', title: 'Url', type: 'text', canEdit: false},
    {name: 'parents', title: 'Parent', type: 'text', foreignKey: 'url', rootValue: 'root'},
    {name: 'name', title: 'Naam'},
    {name: 'owner', title: 'Eigenaar'},
    {name: 'description', title: 'Beschrijving'}
  ],
  transformResponse: function(dsResponse) {
    var json_data = isc.JSON.decode(dsResponse.data);
    var result = [];

    //process data, to put nodes under multiple parent nodes
    for (var i = 0; i < json_data.results.length; i++ ) {
      var rec = json_data.results[i];
      rec.isFolder = true;

      if (rec.parents.length > 0) {
        for (var ii = 0; ii < rec.parents.length; ii++ ) {
          var sub_rec = isc.clone(rec);
          sub_rec._url = sub_rec.url;
          if (ii > 0) {
            sub_rec.id = null;
            sub_rec.url = null;
          }
          sub_rec.parents = rec.parents[ii];
          result.push(sub_rec);

        }
        //result.push(rec);
      } else {
        rec.parents = 'root';
        rec._url = rec.url;
        result.push(rec);
      }
    }
    dsResponse.data = result;
  }
});

var setLogicalGroupFormData = function(data) {

  timeseriesSelectionGrid.setData(data.timeseries);

  delete data['timeseries'];
  delete data['childs'];

  var parent_ids = []
  for (var i=0; i<data.parents.length; i++) {
    parent_ids.push(data.parents[i].parent_id);
  }
  data.parents = parent_ids;
  logicalGroupForm.setData(data);
  logicalGroupForm.setErrors([]);
}

var logicalGroupTree = isc.TreeGrid.create({
  dataSource: logicalGroupDS,
  width: 300,
  canReorderRecords: true,
  canAcceptDroppedRecords: true,
  autoFetchData:true,
  loadDataOnDemand:false,
  dataProperties:{
    dataArrived:function (parentNode) {
      this.openAll();
    },
    disableCacheSync: true
  },
  fields:[
    { name: 'name', formatCellValue: "return value + '  (' + record.owner + ')'" }
  ],
  rowClick: function(record) {
    RPCManager.sendRequest({
      httpHeaders: {
        'Accept': 'application/json'
      },
      actionURL: record._url,
      httpMethod: 'GET',
      callback: function(rpcResponse, data, rpcRequest) {
        var data = isc.JSON.decode(rpcResponse.data);
        setLogicalGroupFormData(data);
      }
    });
  }
});

//#####################################################################################################################

var logicalGroupForm = isc.DynamicForm.create({
  dataSource: logicalGroupDS,
  numCols: 2,
  colWidths: [100, 300],
  fields: [
    {type: 'header', defaultValue: "Logische Groep", width: "*"},
    {name: "id", title:"id", type: 'integer', canEdit: false},
    {name: "name", width: "*"},
    {
      name: "owner", type: "combo",
      width: "*",
      displayField: "name",
      valueField: "name",
      optionDataSource: isc.DataSource.create({
        dataFormat: 'json',
        recordXPath: "results",
        requestProperties: {
          params: {
            page_size: 1000,
            management: true
          }
        },
        dataURL: settings.dataowners_url,
        fields:[
          {name: 'id', title: 'iD', primaryKey: true},
          {name: 'name', title: 'Naam'}
        ]
      })
    },
    {name: "description", title: 'Beschrijving', type: 'textArea', width: "*"},
    {
      name: "parents",
      title: "Parents",
      editorType: "MultiComboBoxItem",
      defaultValue: [],
      optionDataSource: isc.DataSource.create({
        dataFormat: 'json',
        recordXPath: "results",
        requestProperties: {
          params: {
            page_size: 1000,
            management: true
          }
        },
        dataURL: settings.logicalgroups_url,
        fields:[
          {name: 'id', title: 'iD', primaryKey: true},
          {name: 'name', title: 'Naam'}
        ]
      }),
      displayField: "name",
      valueField: "id"
     // autoFetchData: true,
      //layoutStyle: initialLayoutStyle
    }
  ]
});

var timeseriesSelectionGrid = isc.ListGrid.create({
  width: 400,
  alternateRecordStyles:true,
  canReorderRecords: true,
  canAcceptDroppedRecords: true,
  preventDuplicates: true,
  fields:[
    {name:"id", title:"id", showIf: "return false"},
    {name:"url", title:"Url", showIf: "return false"},
    {name:"name", title:"Gselecteerde tijdseries - Naam"}
  ]
});

//#####################################################################################################################

var lgTimeseriesDS = isc.FilterPaginatedDataSource.create({
  autoFetchData: false,
  dataURL: settings.timeseries_url,
  requestProperties: {
    params: {
      management: true
    }
  },
  fields:[
    {name: 'id', title: 'id', hidden: true},
    {name: 'uuid', title: 'UUID'},
    {name: 'name', title: 'Naam'},
    {
      name: 'value_type', title: 'Waarde type', valueMap: ['integer', 'float', 'text', 'image',
      'georeferenced remote sensing', 'movie', 'file'], canFilter: false
    },
    {name: 'owner', title: 'Data eigenaar'},
    {name: 'location.name', title: 'Locatie'},
    {name: 'parameter', title: 'Parameter'},
    {name: 'unit', title: 'Eenheid'}
  ]
});

var lgTimeseries = isc.DefaultListGrid.create({
  //width:700,
  dataSource: lgTimeseriesDS,
  canDragRecordsOut: true,
  dragDataAction: 'copy',
  dataProperties:{
    disableCacheSync: true
  },
  canReorderFields: true
});

//#####################################################################################################################

var saveLogicalGroup = function(saveAsNew) {
  var data = logicalGroupForm.getData();
  var timeseries = timeseriesSelectionGrid.getData();

  data.parents = logicalGroupForm.getField('parents').getValue();
  var parents = [];
  for (var i=0; i<data.parents.length; i++) {
    parents.push({parent: data.parents[i]});
  }
  data.parents = parents;

  var timeseries_ids = [];
  for (var i=0; i<timeseries.length; i++) {
    timeseries_ids.push(timeseries[i].url);
  }
  data.timeseries = timeseries_ids;

  saveObject(logicalGroupForm, data, settings.logicalgroups_url, {
    saveAsNew: saveAsNew,
    reloadList: logicalGroupTree,
    setFormData: setLogicalGroupFormData
  });
}

logicalGroupPage = isc.HLayout.create({
  members: [
    logicalGroupTree,
    isc.VLayout.create({
      width: 400,
      padding: 10,
      membersMargin: 10,
      members: [
        logicalGroupForm,
        timeseriesSelectionGrid,
        isc.HLayout.create({
          height: 20,
          members: [
            isc.IButton.create({
              title: 'Annuleren',
              click: function() {
                logicalGroupForm.setData([]);
                logicalGroupForm.getField('parents').setValue([]); //reset this field manual
                logicalGroupForm.setErrors([]);
                timeseriesSelectionGrid.setData([]);
              }
            }),
            isc.IButton.create({
              title: 'Nieuw',
              click: function() {
                logicalGroupForm.setData([]);
                logicalGroupForm.getField('parents').setValue([]); //reset this field manual
                logicalGroupForm.setErrors([]);
                timeseriesSelectionGrid.setData([]);
              }
            }),
            isc.IButton.create({
              title: 'Opslaan',
              click: function() {
                saveLogicalGroup(false);
              }
            }),
            isc.IButton.create({
              title: 'Verwijderen',
              click: function() {
                var id = logicalGroupForm.getValue('id');
                if (id) {
                  RPCManager.sendRequest({
                    actionURL: logicalGroupForm.getData()['url'],
                    httpMethod: 'DELETE',
                    httpHeaders: {
                      'X-CSRFToken': document.cookie.split('=')[1]
                    },
                    callback: function(rpcResponse, data, rpcRequest) {
                      console.log('verwijderen gelukt');
                      logicalGroupForm.setData([]);
                      logicalGroupForm.setErrors([]);
                      timeseriesSelectionGrid.setData([]);
                      logicalGroupTree.fetchData({test: timestamp()}); //force new fetch with timestamp
                    }
                  });
                }
              }
            })
          ]
        })
      ]
    }),
    isc.VStack.create({width:32, height:74, layoutAlign:"center", membersMargin:10, members:[
      isc.Img.create({src: static_media_root + "ddsc_api/management/images/arrow_left.png", width:32, height:32,
        click: function() {
          timeseriesSelectionGrid.transferSelectedData(lgTimeseries);
        }
      }),
      isc.Img.create({src: static_media_root + "ddsc_api/management/images/arrow_right.png", width:32, height:32,
        click: function() {
          if (timeseriesSelectionGrid.getSelectedRecords()) {
            timeseriesSelectionGrid.data.removeAll(timeseriesSelectionGrid.getSelectedRecords());
          }

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


<commit_before>// Licensed to Cloudera, Inc. under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  Cloudera, Inc. licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
 * jHue notify plugin
 *
 */
;
(function ($, window, document, undefined) {

  var pluginName = "jHueNotify",
    TYPES = {
      INFO: "INFO",
      ERROR: "ERROR",
      GENERAL: "GENERAL"
    },
    defaults = {
      level: TYPES.GENERAL,
      message: "",
      sticky: false,
      css: null
    };

  function Plugin(options) {
    this.options = $.extend({}, defaults, options);
    this._defaults = defaults;
    this._name = pluginName;
    this.show();
  }

  Plugin.prototype.setOptions = function (options) {
    this.options = $.extend({}, defaults, options);
  };

  Plugin.prototype.show = function () {
    var _this = this;
    var MARGIN = 4;

    _this.options.message = $.trim($("").text(_this.options.message).html()); // escape HTML messages

    if (_this.options.message !== '' && $(".jHueNotify .message").last().text() !== _this.options.message) {

      var el = $("#jHueNotify").clone();
      el.removeAttr("id");

      // stops all the current animations and resets the style
      el.stop(true);
      el.attr("class", "alert jHueNotify");
      el.find(".close").hide();

      if ($(".jHueNotify").last().position() != null) {
        el.css("top", $(".jHueNotify").last().position().top + $(".jHueNotify").last().outerHeight() + MARGIN);
      }

      var scrollColor = '#f0c36d';

      if (_this.options.level == TYPES.ERROR) {
        el.addClass("alert-error");
        scrollColor = '#b94a48';
      }
      else if (_this.options.level == TYPES.INFO) {
        el.addClass("alert-info");
        scrollColor = '#0B7FAD';
      }
      el.find(".message").html("" + _this.options.message + "");

      if (_this.options.css != null) {
        el.attr("style", _this.options.css);
      }

      el.on('dblclick', function () {
        el.toggleClass('expanded');
      });

      if (_this.options.sticky) {
        el.find(".close").click(function () {
          el.fadeOut();
          el.nextAll(".jHueNotify").animate({
            top: '-=' + (el.outerHeight() + MARGIN)
          }, 200);
          el.remove();
        }).show();
        el.show();
      }
      else {
        var t = window.setTimeout(function () {
          el.fadeOut();
          el.nextAll(".jHueNotify").animate({
            top: '-=' + (el.outerHeight() + MARGIN)
          }, 200);
          el.remove();

        }, 3000);
        el.click(function () {
          window.clearTimeout(t);
          $(this).stop(true);
          $(this).fadeOut();
          $(this).nextAll(".jHueNotify").animate({
            top: '-=' + ($(this).outerHeight() + MARGIN)
          }, 200);
        });
        el.show();
      }
      el.appendTo(HUE_CONTAINER);
    }
  };

  $[pluginName] = function () {
  };

  $[pluginName].info = function (message) {
    new Plugin({level: TYPES.INFO, message: message});
  };

  $[pluginName].warn = function (message) {
    new Plugin({level: TYPES.GENERAL, message: message, sticky: true});
  };

  $[pluginName].error = function (message) {
    new Plugin({level: TYPES.ERROR, message: message, sticky: true});
  };

  $[pluginName].notify = function (options) {
    new Plugin(options);
  };

})(jQuery, window, document);
<commit_msg>HUE-7889 [frontend] Remove html page source from the notifications<commit_after>// Licensed to Cloudera, Inc. under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  Cloudera, Inc. licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
 * jHue notify plugin
 *
 */
;
(function ($, window, document, undefined) {

  var pluginName = "jHueNotify",
    TYPES = {
      INFO: "INFO",
      ERROR: "ERROR",
      GENERAL: "GENERAL"
    },
    defaults = {
      level: TYPES.GENERAL,
      message: "",
      sticky: false,
      css: null
    };

  function Plugin(options) {
    this.options = $.extend({}, defaults, options);
    this._defaults = defaults;
    this._name = pluginName;
    this.show();
  }

  Plugin.prototype.setOptions = function (options) {
    this.options = $.extend({}, defaults, options);
  };

  Plugin.prototype.show = function () {
    var _this = this;
    var MARGIN = 4;

    _this.options.message = _this.options.message.replace(/(<([^>]+)>)/ig, ''); // escape HTML messages

    if (_this.options.message !== '' && $(".jHueNotify .message").last().text() !== _this.options.message) {

      var el = $("#jHueNotify").clone();
      el.removeAttr("id");

      // stops all the current animations and resets the style
      el.stop(true);
      el.attr("class", "alert jHueNotify");
      el.find(".close").hide();

      if ($(".jHueNotify").last().position() != null) {
        el.css("top", $(".jHueNotify").last().position().top + $(".jHueNotify").last().outerHeight() + MARGIN);
      }

      var scrollColor = '#f0c36d';

      if (_this.options.level == TYPES.ERROR) {
        el.addClass("alert-error");
        scrollColor = '#b94a48';
      }
      else if (_this.options.level == TYPES.INFO) {
        el.addClass("alert-info");
        scrollColor = '#0B7FAD';
      }
      el.find(".message").html("" + _this.options.message + "");

      if (_this.options.css != null) {
        el.attr("style", _this.options.css);
      }

      el.on('dblclick', function () {
        el.toggleClass('expanded');
      });

      if (_this.options.sticky) {
        el.find(".close").click(function () {
          el.fadeOut();
          el.nextAll(".jHueNotify").animate({
            top: '-=' + (el.outerHeight() + MARGIN)
          }, 200);
          el.remove();
        }).show();
        el.show();
      }
      else {
        var t = window.setTimeout(function () {
          el.fadeOut();
          el.nextAll(".jHueNotify").animate({
            top: '-=' + (el.outerHeight() + MARGIN)
          }, 200);
          el.remove();

        }, 3000);
        el.click(function () {
          window.clearTimeout(t);
          $(this).stop(true);
          $(this).fadeOut();
          $(this).nextAll(".jHueNotify").animate({
            top: '-=' + ($(this).outerHeight() + MARGIN)
          }, 200);
        });
        el.show();
      }
      el.appendTo(HUE_CONTAINER);
    }
  };

  $[pluginName] = function () {
  };

  $[pluginName].info = function (message) {
    new Plugin({level: TYPES.INFO, message: message});
  };

  $[pluginName].warn = function (message) {
    new Plugin({level: TYPES.GENERAL, message: message, sticky: true});
  };

  $[pluginName].error = function (message) {
    new Plugin({level: TYPES.ERROR, message: message, sticky: true});
  };

  $[pluginName].notify = function (options) {
    new Plugin(options);
  };

})(jQuery, window, document);
<|endoftext|>


<commit_before>// Handles related-objects functionality: lookup link for raw_id_admin=True
// and Add Another links.

function showRelatedObjectLookupPopup(triggeringLink) {
    var name = triggeringLink.id.replace(/^lookup_/, '');
    var win = window.open(triggeringLink.href + '?pop=1', name, 'height=500,width=740,resizable=yes,scrollbars=yes');
    win.focus();
    return false;
}

function dismissRelatedLookupPopup(win, chosenId) {
    var elem = document.getElementById(win.name);
    if (elem.className.indexOf('vRawIdAdminField') != -1 && elem.value) {
        elem.value += ',' + chosenId;
    } else {
        document.getElementById(win.name).value = chosenId;
    }
    win.close();
}

function showAddAnotherPopup(triggeringLink) {
    var name = triggeringLink.id.replace(/^add_/, '');
    name = name.replace(/\./g, '___');
    var win = window.open(triggeringLink.href + '?_popup=1', name, 'height=500,width=800,resizable=yes,scrollbars=yes');
    win.focus();
    return false;
}

function dismissAddAnotherPopup(win, newId, newRepr) {
    var name = win.name.replace(/___/g, '.')
    var elem = document.getElementById(name);
    if (elem.nodeName == 'SELECT') {
        var o = new Option(newRepr, newId);
        elem.options[elem.options.length] = o
        elem.selectedIndex = elem.length - 1;
    } else if (elem.nodeName == 'INPUT') {
        elem.value = newId;
    }
    win.close();
}
<commit_msg>Fixed #1404 (thanks, Tom Tobin)<commit_after>// Handles related-objects functionality: lookup link for raw_id_admin=True
// and Add Another links.

function showRelatedObjectLookupPopup(triggeringLink) {
    var name = triggeringLink.id.replace(/^lookup_/, '');
    var win = window.open(triggeringLink.href + '?pop=1', name, 'height=500,width=740,resizable=yes,scrollbars=yes');
    win.focus();
    return false;
}

function dismissRelatedLookupPopup(win, chosenId) {
    var elem = document.getElementById(win.name);
    if (elem.className.indexOf('vRawIdAdminField') != -1 && elem.value) {
        elem.value += ',' + chosenId;
    } else {
        document.getElementById(win.name).value = chosenId;
    }
    win.close();
}

function showAddAnotherPopup(triggeringLink) {
    var name = triggeringLink.id.replace(/^add_/, '');
    name = name.replace(/\./g, '___');
    var win = window.open(triggeringLink.href + '?_popup=1', name, 'height=500,width=800,resizable=yes,scrollbars=yes');
    win.focus();
    return false;
}

function dismissAddAnotherPopup(win, newId, newRepr) {
    var name = win.name.replace(/___/g, '.')
    var elem = document.getElementById(name);
    if (elem) {
        if (elem.nodeName == 'SELECT') {
            var o = new Option(newRepr, newId);
            elem.options[elem.options.length] = o
            elem.selectedIndex = elem.length - 1;
        } else if (elem.nodeName == 'INPUT') {
            elem.value = newId;
        }
    } else {
        var toId = name + "_to";
        elem = document.getElementById(toId);
        var o = new Option(newRepr, newId);
        SelectBox.add_to_cache(toId, o);
        SelectBox.redisplay(toId);
    }
    win.close();
}
<|endoftext|>


<commit_before>var init = require('../main/init');
var upload = require('../main/upload');
var express = require('../main/express');
var rcs = require('../main/rcs');

init.add(function () {

	var app = express.app;

	app.post('/api/upload', function (req, res) {
		req.authorized(function () {
			res.json({
				rc: rcs.SUCCESS,
				files: upload.tmpFiles(req.files.file)
			});
		});
	});

	app.del('/api/upload', function (req, res) {
		req.authorized(function () {
			upload.deleteTmpFiles(req.body.files);
			res.json({ rc: rcs.SUCCESS });
		});
	});

	console.log('upload-api:');
});
<commit_msg>req.authorized(function (r) {<commit_after>var init = require('../main/init');
var upload = require('../main/upload');
var express = require('../main/express');
var rcs = require('../main/rcs');

init.add(function () {

	var app = express.app;

	app.post('/api/upload', function (req, res) {
		req.authorized(function (r) {
			if (r) {
				return res.json(r);
			}
			res.json({
				rc: rcs.SUCCESS,
				files: upload.tmpFiles(req.files.file)
			});
		});
	});

	app.del('/api/upload', function (req, res) {
		req.authorized(function (r) {
			if (r) {
				return res.json(r);
			}
			upload.deleteTmpFiles(req.body.files);
			res.json({ rc: rcs.SUCCESS });
		});
	});

	console.log('upload-api:');

});
<|endoftext|>


<commit_before>/**
 * Url alias Model
 *
 * @module      :: Model
 */

module.exports = function UrlSlugModel(we) {
  return {
    definition: {
      alias: {
        type: we.db.Sequelize.STRING(760),
        allowNull: false,
        formFieldType: 'text',
        unique: true
      },
      target: {
        type: we.db.Sequelize.STRING(760),
        allowNull: false,
        formFieldType: 'text'
      },
      locale: {
        type: we.db.Sequelize.STRING,
        formFieldType: null
      }
    },

    options: {
      // Model tableName will be the same as the model name
      freezeTableName: true,

      hooks: {
        afterCreate: function(record, opts, done) {
          // cache after create a record
          we.router.alias.cache[record.target] = record;
          done();
        },
        afterUpdate: function(record, opts, done) {
          // cache after udate the record
          we.router.alias.cache[record.target] = record;
          done();
        },
        afterDestroy: function(record, opts, done) {
          delete we.router.alias.cache[record.target];
          done();
        }
      }
    }
  }
}<commit_msg>change alias target to be unique<commit_after>/**
 * Url alias Model
 *
 * @module      :: Model
 */

module.exports = function UrlSlugModel(we) {
  return {
    definition: {
      alias: {
        type: we.db.Sequelize.STRING(760),
        allowNull: false,
        formFieldType: 'text',
        unique: true
      },
      target: {
        type: we.db.Sequelize.STRING(760),
        allowNull: false,
        formFieldType: 'text',
        unique: true
      },
      locale: {
        type: we.db.Sequelize.STRING,
        formFieldType: null
      }
    },

    options: {
      // Model tableName will be the same as the model name
      freezeTableName: true,

      hooks: {
        afterCreate: function(record, opts, done) {
          // cache after create a record
          we.router.alias.cache[record.target] = record;
          done();
        },
        afterUpdate: function(record, opts, done) {
          // cache after udate the record
          we.router.alias.cache[record.target] = record;
          done();
        },
        afterDestroy: function(record, opts, done) {
          delete we.router.alias.cache[record.target];
          done();
        }
      }
    }
  }
}<|endoftext|>


<commit_before>const { AppSetting } = require('./app_setting');
const { BagItProfile } = require('../bagit/bagit_profile');
const { Context } = require('./context');
const dateFormat = require('dateformat');
const { PackageOperation } = require('./package_operation');
const path = require('path');
const { PersistentObject } = require('./persistent_object');
const { ValidationOperation } = require('./validation_operation');
const { UploadOperation } = require('./upload_operation');
const { Util } = require('./util');

/**
 * This is a list of BagItProfile tags to check to try to find a
 * meaningful title for this job. DART checks them in order and
 * returns the first one that has a non-empty user-defined value.
 */
const titleTags = [
    "Title",
    "Internal-Sender-Identifier",
    "External-Identifier",
    "Internal-Sender-Description",
    "External-Description",
    "Description"
];

/**
 * Job describes a series of related actions for DART to perform.
 * This typically includes packaging a number of files and sending
 * them across a network to one or more remote repositories, though
 * it does not have to include those actions. A job may consist of
 * a single action, such as validating a bag or uploading a file
 * to an S3 bucket.
 */
class Job extends PersistentObject {
    /**
     * @param {string} opts.id - A UUID in hex-string format. This is
     * the object's unique identifier.
     *
     * @param {boolean} opts.userCanDelete - Indicates whether user is
     * allowed to delete this record.
     *
     * @param {BagItProfile} opts.bagItProfile - A BagItProfile object.
     * This is required only for bagging and validation jobs.
     *
     * @param {PackagingOperation} opts.packageOp - An object describing
     * what this job is supposed to package. The is relevant only to
     * jobs that involving bagging or other forms of packaging.
     *
     * @param {ValidationOperation} opts.validationOp - An object
     * describing what is to be validated. This is relevant only if the
     * job includes a validation step.
     *
     * @param {Array<UploadOperation>} opts.uploadOps - A list of objects
     * describing what should be uploaded, and to where. This is relevant
     * only for jobs that will be uploading materials.
     */
    constructor(opts = {}) {
        super(opts);
        this.bagItProfile = opts.bagItProfile || null;
        this.packageOp = opts.packageOp || new PackageOperation();
        this.validationOp = opts.validationOp || null;
        this.uploadOps = opts.uploadOps || [];
        this.createdAt = opts.createdAt || new Date();
        this.errors = {};
    }

    /**
     * This returns a title for display purposes. It will use the first
     * available non-empty value of: 1) the name of the file that the job
     * packaged, 2) the name of the file that the job uploaded, or 3) a
     * title or description of the bag from within the bag's tag files.
     * If none of those is available, this will return "Job of <timestamp>",
     * where timestamp is date and time the job was created.
     *
     * @returns {string}
     */
    title() {
        // Try to get the name of the file that was created or uploaded.
        var name = null;
        if (!name && this.packageOp && this.packageOp.packageName) {
            name = path.basename(this.packageOp.packageName);
        }
        if (!name && this.uploadOps.length > 0 && this.uploadOps[0].sourceFiles.length > 0) {
            name = path.basename(this.uploadOps[0].sourceFiles[0]);
        }
        // Try to get a title from the bag.
        if (!name && this.bagItProfile) {
            for (let tagName of titleTags) {
                let tag = this.bagItProfile.firstMatchingTag('tagName', tagName);
                if (tag && tag.userValue) {
                    name = tag.userValue;
                    break;
                }
            }
        }
        // If no title or filename, create a generic name.
        if (!name) {
            name = `Job of ${dateFormat(this.createdAt, 'shortDate')} ${dateFormat(this.createdAt, 'shortTime')}`;
        }
        return Util.truncateString(name, 40);
    }

    /**
     * Returns the datetime on which this job's package operation completed.
     *
     * @returns {Date}
     */
    packagedAt() {
        var packagedAt = null;
        if (this.packageOp && this.packageOp.result && this.packageOp.result.completed) {
            packagedAt = this.packageOp.result.completed;
        }
        return packagedAt;
    }

    /**
     * Returns true if DART attempted to execute this job's package
     * operation.
     *
     * @returns {boolean}
     */
    packageAttempted() {
        if (this.packageOp && this.packageOp.result) {
            return this.packageOp.result.attempt > 0;
        }
        return false;
    }

    /**
     * Returns true if DART successfully completed this job's package
     * operation. Note that this will return false if packaging failed
     * and if packaging was never attempted, so check
     * {@link packageAttempted} as well.
     *
     * @returns {boolean}
     */
    packageSucceeded() {
        if (this.packageOp && this.packageOp.result) {
            return this.packageOp.result.succeeded();
        }
        return false;
    }

    /**
     * Returns the datetime on which this job's validation operation completed.
     *
     * @returns {Date}
     */
    validatedAt() {
        var validatedAt = null;
        if (this.validationOp && this.validationOp.result && this.validationOp.result.completed) {
            validatedAt = this.validationOp.result.completed;
        }
        return validatedAt;
    }

    /**
     * Returns true if DART attempted to execute this job's validation
     * operation.
     *
     * @returns {boolean}
     */
    validationAttempted() {
        if (this.validationOp && this.validationOp.result) {
            return this.validationOp.result.attempt > 0;
        }
        return false;
    }

    /**
     * Returns true if DART successfully completed this job's validation
     * operation. See {@link validationAttempted} as well.
     *
     * @returns {boolean}
     */
    validationSucceeded() {
        if (this.validationOp && this.validationOp.result) {
            return this.validationOp.result.succeeded();
        }
        return false;
    }

    /**
     * Returns the datetime on which this job's last upload operation completed.
     *
     * @returns {Date}
     */
    uploadedAt() {
        var uploadedAt = null;
        if (this.uploadOps.length > 0) {
            for (let uploadOp of this.uploadOps) {
                if (uploadOp.result && uploadOp.result.completed) {
                    uploadedAt = uploadOp.result.completed;
                }
            }
        }
        return uploadedAt;
    }

    /**
     * Returns true if DART attempted to execute any of this job's upload
     * operations.
     *
     * @returns {boolean}
     */
    uploadAttempted() {
        if (this.uploadOps) {
            for (let op of this.uploadOps) {
                if (op.result) {
                    if (op.result.attempt > 0) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Returns true if DART successfully completed all of this job's upload
     * operations. See {@link uploadAttempted} as well.
     *
     * @returns {boolean}
     */
    uploadSucceeded() {
        let anyAttempted = false;
        let allSucceeded = true;
        if (this.uploadOps) {
            for (let op of this.uploadOps) {
                if (op.result) {
                    if (op.result.attempt > 0) {
                        anyAttempted = true;
                    }
                    if (!op.result.succeeded()) {
                        allSucceeded = false;
                    }
                }
            }
        }
        return (anyAttempted && allSucceeded);
    }

    /**
     * validate returns true or false, indicating whether this object
     * contains complete and valid data. If it returns false, check
     * the errors property for specific errors.
     *
     * @returns {boolean}
     */
    validate() {
        super.validate();
        if (this.packageOp) {
            this.packageOp.validate();
            Object.assign(this.errors, this.packageOp.errors);
            // TODO: Require BagItProfile if packaging op is BagIt.
            // TODO: Mechanism for signifying this is a BagIt job (as opposed to just tar or zip)
        }
        if (this.validationOp) {
            this.validationOp.validate();
            Object.assign(this.errors, this.validationOp.errors);
            if (!this.bagItProfile) {
                result.errors['Job.bagItProfile'] = 'Validation requires a BagItProfile.';
            }
        }
        var opNum = 0;
        for (var uploadOp of this.uploadOps) {
            uploadOp.validate();
            Object.assign(this.errors, uploadOp.errors);
            opNum++;
        }
        return Object.keys(this.errors).length == 0;
    }

    /**
     * This converts the JSON representation of a job as stored in the DB
     * to a full-fledged Job object with all of the expected methods.
     *
     * @param {Object} data - A JavaScript hash.
     *
     * @returns {Job}
     */
    static inflateFrom(data) {
        let job = new Job();
        Object.assign(job, data);
        if (data.bagItProfile) {
            job.bagItProfile = BagItProfile.inflateFrom(data.bagItProfile);
        }
        if (data.packageOp) {
            job.packageOp = PackageOperation.inflateFrom(data.packageOp);
        }
        if (data.validationOp) {
            job.validationOp = ValidationOperation.inflateFrom(data.validationOp);
        }
        if (data.uploadOps) {
            job.uploadOps = [];
            for (let op of data.uploadOps) {
                job.uploadOps.push(UploadOperation.inflateFrom(op));
            }
        }
        return job;
    }

    /**
     * find finds the Job with the specified id in the datastore
     * and returns it. Returns undefined if the object is not in the datastore.
     *
     * This overrides the find() method of the PersistentObject to return
     * a correctly constructed Job object.
     *
     * @param {string} id - The id (UUID) of the job you want to find.
     *
     * @returns {Job}
     */
    static find(id) {
        let data = Context.db('Job').get(id);
        if (data) {
            return Job.inflateFrom(data);
        }
        return undefined;
    }
}

// Get static methods from base.
Object.assign(Job, PersistentObject);

module.exports.Job = Job;
<commit_msg>Added dirCount, fileCount and byteCount to Job<commit_after>const { AppSetting } = require('./app_setting');
const { BagItProfile } = require('../bagit/bagit_profile');
const { Context } = require('./context');
const dateFormat = require('dateformat');
const { PackageOperation } = require('./package_operation');
const path = require('path');
const { PersistentObject } = require('./persistent_object');
const { ValidationOperation } = require('./validation_operation');
const { UploadOperation } = require('./upload_operation');
const { Util } = require('./util');

/**
 * This is a list of BagItProfile tags to check to try to find a
 * meaningful title for this job. DART checks them in order and
 * returns the first one that has a non-empty user-defined value.
 */
const titleTags = [
    "Title",
    "Internal-Sender-Identifier",
    "External-Identifier",
    "Internal-Sender-Description",
    "External-Description",
    "Description"
];

/**
 * Job describes a series of related actions for DART to perform.
 * This typically includes packaging a number of files and sending
 * them across a network to one or more remote repositories, though
 * it does not have to include those actions. A job may consist of
 * a single action, such as validating a bag or uploading a file
 * to an S3 bucket.
 */
class Job extends PersistentObject {
    /**
     * @param {string} opts.id - A UUID in hex-string format. This is
     * the object's unique identifier.
     *
     * @param {boolean} opts.userCanDelete - Indicates whether user is
     * allowed to delete this record.
     *
     * @param {BagItProfile} opts.bagItProfile - A BagItProfile object.
     * This is required only for bagging and validation jobs.
     *
     * @param {PackagingOperation} opts.packageOp - An object describing
     * what this job is supposed to package. The is relevant only to
     * jobs that involving bagging or other forms of packaging.
     *
     * @param {ValidationOperation} opts.validationOp - An object
     * describing what is to be validated. This is relevant only if the
     * job includes a validation step.
     *
     * @param {Array<UploadOperation>} opts.uploadOps - A list of objects
     * describing what should be uploaded, and to where. This is relevant
     * only for jobs that will be uploading materials.
     */
    constructor(opts = {}) {
        super(opts);
        this.bagItProfile = opts.bagItProfile || null;
        this.packageOp = opts.packageOp || new PackageOperation();
        this.validationOp = opts.validationOp || null;
        this.uploadOps = opts.uploadOps || [];
        this.createdAt = opts.createdAt || new Date();
        this.errors = {};

        /**
         * The total number of files to be packaged and/or uploaded
         * by this job. This value is set when building a Job through
         * the DART UI, but it may not be set by the command-line tools.
         * If DART does not set this value, it remains at the default
         * of -1.
         *
         * @type {number}
         * @default -1
         */
        this.fileCount = -1;

        /**
         * The total number of directories to be packaged and/or uploaded
         * by this job. This value is set when building a Job through
         * the DART UI, but it may not be set by the command-line tools.
         * If DART does not set this value, it remains at the default
         * of -1.
         *
         * @type {number}
         * @default -1
         */
        this.dirCount = -1;

        /**
         * The total number of bytes in the payload to be packaged
         * and/or uploaded by this job. This number may not match
         * to total size of the bag the job produces because the bag
         * may include additiaonal manifests and tag files, and it may
         * be serialized to a format like tar that makes it slightly
         * larger, or to a format like zip or gzip that makes it
         * smaller.
         *
         * This value is set when building a Job through the DART UI,
         * but it may not be set by the command-line tools.
         * If DART does not set this value, it remains at the default
         * of -1.
         *
         * @type {number}
         * @default -1
         */
        this.byteCount = -1;
    }

    /**
     * This returns a title for display purposes. It will use the first
     * available non-empty value of: 1) the name of the file that the job
     * packaged, 2) the name of the file that the job uploaded, or 3) a
     * title or description of the bag from within the bag's tag files.
     * If none of those is available, this will return "Job of <timestamp>",
     * where timestamp is date and time the job was created.
     *
     * @returns {string}
     */
    title() {
        // Try to get the name of the file that was created or uploaded.
        var name = null;
        if (!name && this.packageOp && this.packageOp.packageName) {
            name = path.basename(this.packageOp.packageName);
        }
        if (!name && this.uploadOps.length > 0 && this.uploadOps[0].sourceFiles.length > 0) {
            name = path.basename(this.uploadOps[0].sourceFiles[0]);
        }
        // Try to get a title from the bag.
        if (!name && this.bagItProfile) {
            for (let tagName of titleTags) {
                let tag = this.bagItProfile.firstMatchingTag('tagName', tagName);
                if (tag && tag.userValue) {
                    name = tag.userValue;
                    break;
                }
            }
        }
        // If no title or filename, create a generic name.
        if (!name) {
            name = `Job of ${dateFormat(this.createdAt, 'shortDate')} ${dateFormat(this.createdAt, 'shortTime')}`;
        }
        return Util.truncateString(name, 40);
    }

    /**
     * Returns the datetime on which this job's package operation completed.
     *
     * @returns {Date}
     */
    packagedAt() {
        var packagedAt = null;
        if (this.packageOp && this.packageOp.result && this.packageOp.result.completed) {
            packagedAt = this.packageOp.result.completed;
        }
        return packagedAt;
    }

    /**
     * Returns true if DART attempted to execute this job's package
     * operation.
     *
     * @returns {boolean}
     */
    packageAttempted() {
        if (this.packageOp && this.packageOp.result) {
            return this.packageOp.result.attempt > 0;
        }
        return false;
    }

    /**
     * Returns true if DART successfully completed this job's package
     * operation. Note that this will return false if packaging failed
     * and if packaging was never attempted, so check
     * {@link packageAttempted} as well.
     *
     * @returns {boolean}
     */
    packageSucceeded() {
        if (this.packageOp && this.packageOp.result) {
            return this.packageOp.result.succeeded();
        }
        return false;
    }

    /**
     * Returns the datetime on which this job's validation operation completed.
     *
     * @returns {Date}
     */
    validatedAt() {
        var validatedAt = null;
        if (this.validationOp && this.validationOp.result && this.validationOp.result.completed) {
            validatedAt = this.validationOp.result.completed;
        }
        return validatedAt;
    }

    /**
     * Returns true if DART attempted to execute this job's validation
     * operation.
     *
     * @returns {boolean}
     */
    validationAttempted() {
        if (this.validationOp && this.validationOp.result) {
            return this.validationOp.result.attempt > 0;
        }
        return false;
    }

    /**
     * Returns true if DART successfully completed this job's validation
     * operation. See {@link validationAttempted} as well.
     *
     * @returns {boolean}
     */
    validationSucceeded() {
        if (this.validationOp && this.validationOp.result) {
            return this.validationOp.result.succeeded();
        }
        return false;
    }

    /**
     * Returns the datetime on which this job's last upload operation completed.
     *
     * @returns {Date}
     */
    uploadedAt() {
        var uploadedAt = null;
        if (this.uploadOps.length > 0) {
            for (let uploadOp of this.uploadOps) {
                if (uploadOp.result && uploadOp.result.completed) {
                    uploadedAt = uploadOp.result.completed;
                }
            }
        }
        return uploadedAt;
    }

    /**
     * Returns true if DART attempted to execute any of this job's upload
     * operations.
     *
     * @returns {boolean}
     */
    uploadAttempted() {
        if (this.uploadOps) {
            for (let op of this.uploadOps) {
                if (op.result) {
                    if (op.result.attempt > 0) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Returns true if DART successfully completed all of this job's upload
     * operations. See {@link uploadAttempted} as well.
     *
     * @returns {boolean}
     */
    uploadSucceeded() {
        let anyAttempted = false;
        let allSucceeded = true;
        if (this.uploadOps) {
            for (let op of this.uploadOps) {
                if (op.result) {
                    if (op.result.attempt > 0) {
                        anyAttempted = true;
                    }
                    if (!op.result.succeeded()) {
                        allSucceeded = false;
                    }
                }
            }
        }
        return (anyAttempted && allSucceeded);
    }

    /**
     * validate returns true or false, indicating whether this object
     * contains complete and valid data. If it returns false, check
     * the errors property for specific errors.
     *
     * @returns {boolean}
     */
    validate() {
        super.validate();
        if (this.packageOp) {
            this.packageOp.validate();
            Object.assign(this.errors, this.packageOp.errors);
            // TODO: Require BagItProfile if packaging op is BagIt.
            // TODO: Mechanism for signifying this is a BagIt job (as opposed to just tar or zip)
        }
        if (this.validationOp) {
            this.validationOp.validate();
            Object.assign(this.errors, this.validationOp.errors);
            if (!this.bagItProfile) {
                result.errors['Job.bagItProfile'] = 'Validation requires a BagItProfile.';
            }
        }
        var opNum = 0;
        for (var uploadOp of this.uploadOps) {
            uploadOp.validate();
            Object.assign(this.errors, uploadOp.errors);
            opNum++;
        }
        return Object.keys(this.errors).length == 0;
    }

    /**
     * This converts the JSON representation of a job as stored in the DB
     * to a full-fledged Job object with all of the expected methods.
     *
     * @param {Object} data - A JavaScript hash.
     *
     * @returns {Job}
     */
    static inflateFrom(data) {
        let job = new Job();
        Object.assign(job, data);
        if (data.bagItProfile) {
            job.bagItProfile = BagItProfile.inflateFrom(data.bagItProfile);
        }
        if (data.packageOp) {
            job.packageOp = PackageOperation.inflateFrom(data.packageOp);
        }
        if (data.validationOp) {
            job.validationOp = ValidationOperation.inflateFrom(data.validationOp);
        }
        if (data.uploadOps) {
            job.uploadOps = [];
            for (let op of data.uploadOps) {
                job.uploadOps.push(UploadOperation.inflateFrom(op));
            }
        }
        return job;
    }

    /**
     * find finds the Job with the specified id in the datastore
     * and returns it. Returns undefined if the object is not in the datastore.
     *
     * This overrides the find() method of the PersistentObject to return
     * a correctly constructed Job object.
     *
     * @param {string} id - The id (UUID) of the job you want to find.
     *
     * @returns {Job}
     */
    static find(id) {
        let data = Context.db('Job').get(id);
        if (data) {
            return Job.inflateFrom(data);
        }
        return undefined;
    }
}

// Get static methods from base.
Object.assign(Job, PersistentObject);

module.exports.Job = Job;
<|endoftext|>


<commit_before>if (Movements.find().count() === 0) {
  Movements.insert({
    name: 'Back Squat',
    field1: {
      label: 'Reps',
      type: 'number',
    },
    field2: {
      label: 'Weight',
      type: 'number'
    }
  });

  Movements.insert({
    name: 'Front Squat',
    field1: {
      label: 'Reps',
      type: 'number',
    },
    field2: {
      label: 'Weight',
      type: 'number'
    }
  });

  Movements.insert({
    name: 'Pull-Ups',
    field1: {
      label: 'Reps',
      type: 'number',
    },
    field2: {
      label: 'Scale',
      type: 'select',
      options: [
        'Butterfly',
        'Kipping',
        'Strict',
        'Black Band',
        'Green Band',
        'Blue Band',
        'Red Band',
        'Purple Band',
        'Negatives',
        'Jumping'
        ]
    }
  });

  Movements.insert({
    name: 'Push-Ups',
    field1: {
      label: 'Reps',
      type: 'number',
    },
    field2: {
      label: 'Scale',
      type: 'select',
      options: [
        'Box',
        'Racked Bar'
        ]
    }
  });

  Movements.insert({
    name: 'Kettle Bell Swings',
    field1: {
      label: 'Reps',
      type: 'number'
    },
    field2: {
      label: 'Weight',
      type: 'number'
    }
  });
}<commit_msg>Added thrusters to movementFixture.js. Closes #1<commit_after>if (Movements.find().count() === 0) {
  Movements.insert({
    name: 'Back Squat',
    field1: {
      label: 'Reps',
      type: 'number',
    },
    field2: {
      label: 'Weight',
      type: 'number'
    }
  });

  Movements.insert({
    name: 'Front Squat',
    field1: {
      label: 'Reps',
      type: 'number',
    },
    field2: {
      label: 'Weight',
      type: 'number'
    }
  });

  Movements.insert({
    name: 'Pull-Ups',
    field1: {
      label: 'Reps',
      type: 'number',
    },
    field2: {
      label: 'Scale',
      type: 'select',
      options: [
        'Butterfly',
        'Kipping',
        'Strict',
        'Black Band',
        'Green Band',
        'Blue Band',
        'Red Band',
        'Purple Band',
        'Negatives',
        'Jumping'
        ]
    }
  });

  Movements.insert({
    name: 'Push-Ups',
    field1: {
      label: 'Reps',
      type: 'number',
    },
    field2: {
      label: 'Scale',
      type: 'select',
      options: [
        'Box',
        'Racked Bar'
        ]
    }
  });

  Movements.insert({
    name: 'Kettle Bell Swings',
    field1: {
      label: 'Reps',
      type: 'number'
    },
    field2: {
      label: 'Weight',
      type: 'number'
    }
  });

    Movements.insert({
    name: 'Thrusters',
    field1: {
      label: 'Reps',
      type: 'number'
    },
    field2: {
      label: 'Weight',
      type: 'number'
    }
  });
}<|endoftext|>


<commit_before>var rest = require('restler');

function dining_stats(chatId, bot, when, where) {
    var statsURL = 'https://script.google.com/macros/s/AKfycbw22JUY0XVktavbywTQ7z--mTe7CFbL8X-Bgb6fX-JVNcjGBbeA/exec?';
    statsURL += 'when=' + when;
    statsURL += '&where=' + where;

    function callback(data) {
        var msg = "Avg rating for " + where + " stall at " + when + " is: " + data;
        bot.sendMessage(chatId, msg);
    }
    rest.get(statsURL).on('complete', callback);
}

function dining_feedback(eatingPeriod, stall, rating) {
    var feedbackURL = "https://docs.google.com/forms/d/17IQ-KQCiDWPlJ992yIQIFxocPbBvvqKJTXmzoxOUPJQ/formResponse?entry.1834728229=" + eatingPeriod + "&entry.385772714=" + rating;

    if (eatingPeriod === "Dinner") {
        feedbackURL += "&entry.1055773284=" + stall;
    } else if (eatingPeriod === "Breakfast") {
        feedbackURL += "&entry.1929069273=" + stall;
    }

    rest.get(feedbackURL).on('complete', function(data) {});
}

function ask_when_dining_feedback(chatId, bot) {
    var opts = {
        reply_markup: JSON.stringify({
            keyboard: [
                ['Breakfast', 'Dinner'],
            ],
            one_time_keyboard: true
        })
    };
    bot.sendMessage(chatId, "When did you eat?", opts);
}

function ask_where_dining_feedback(chatId, bot, when) {
    var keyboard = [];
    if (when === "Breakfast") {
        keyboard = [
            ['Asian', 'Western'],
            ['Muslim', 'Toast'],
            ['Other']
        ];
    } else if (when === "Dinner") {
        keyboard = [
            ['Noodle', 'Asian'],
            ['Western - Main Course'],
            ['Western - Panini'],
            ['Indian', 'Malay', 'Late Plate']
        ];
    }
    var opts = {
        reply_markup: JSON.stringify({
            keyboard: keyboard,
            one_time_keyboard: true
        })
    };
    bot.sendMessage(chatId, "Where did you eat?", opts);
}

function ask_how_dining_feedback(chatId, bot) {
    var opts = {
        reply_markup: JSON.stringify({
            keyboard: [
                ['👍', '👍👍', '👍👍👍'],
                ['👍👍👍👍', '👍👍👍👍👍']
            ],
            one_time_keyboard: true
        })
    };
    bot.sendMessage(chatId, "How was it?", opts);
}

module.exports = {
    "dining_feedback": dining_feedback,
    "dining_stats": dining_stats,
    "ask_where_dining_feedback": ask_where_dining_feedback,
    "ask_when_dining_feedback": ask_when_dining_feedback,
    "ask_how_dining_feedback": ask_how_dining_feedback
};
<commit_msg>Fix rounding errors in avg values.<commit_after>var rest = require('restler');

function dining_stats(chatId, bot, when, where) {
    var statsURL = 'https://script.google.com/macros/s/AKfycbw22JUY0XVktavbywTQ7z--mTe7CFbL8X-Bgb6fX-JVNcjGBbeA/exec?';
    statsURL += 'when=' + when;
    statsURL += '&where=' + where;

    function callback(data) {
        var avgRating = parseFloat(data);
        var roundedAvgRating = Math.round(avgRating * 100) / 100;
        var msg = "Avg rating for " + where + " stall at " + when + " is: " + roundedAvgRating;
        bot.sendMessage(chatId, msg);
    }
    rest.get(statsURL).on('complete', callback);
}

function dining_feedback(eatingPeriod, stall, rating) {
    var feedbackURL = "https://docs.google.com/forms/d/17IQ-KQCiDWPlJ992yIQIFxocPbBvvqKJTXmzoxOUPJQ/formResponse?entry.1834728229=" + eatingPeriod + "&entry.385772714=" + rating;

    if (eatingPeriod === "Dinner") {
        feedbackURL += "&entry.1055773284=" + stall;
    } else if (eatingPeriod === "Breakfast") {
        feedbackURL += "&entry.1929069273=" + stall;
    }

    rest.get(feedbackURL).on('complete', function(data) {});
}

function ask_when_dining_feedback(chatId, bot) {
    var opts = {
        reply_markup: JSON.stringify({
            keyboard: [
                ['Breakfast', 'Dinner'],
            ],
            one_time_keyboard: true
        })
    };
    bot.sendMessage(chatId, "When did you eat?", opts);
}

function ask_where_dining_feedback(chatId, bot, when) {
    var keyboard = [];
    if (when === "Breakfast") {
        keyboard = [
            ['Asian', 'Western'],
            ['Muslim', 'Toast'],
            ['Other']
        ];
    } else if (when === "Dinner") {
        keyboard = [
            ['Noodle', 'Asian'],
            ['Western - Main Course'],
            ['Western - Panini'],
            ['Indian', 'Malay', 'Late Plate']
        ];
    }
    var opts = {
        reply_markup: JSON.stringify({
            keyboard: keyboard,
            one_time_keyboard: true
        })
    };
    bot.sendMessage(chatId, "Where did you eat?", opts);
}

function ask_how_dining_feedback(chatId, bot) {
    var opts = {
        reply_markup: JSON.stringify({
            keyboard: [
                ['👍', '👍👍', '👍👍👍'],
                ['👍👍👍👍', '👍👍👍👍👍']
            ],
            one_time_keyboard: true
        })
    };
    bot.sendMessage(chatId, "How was it?", opts);
}

module.exports = {
    "dining_feedback": dining_feedback,
    "dining_stats": dining_stats,
    "ask_where_dining_feedback": ask_where_dining_feedback,
    "ask_when_dining_feedback": ask_when_dining_feedback,
    "ask_how_dining_feedback": ask_how_dining_feedback
};
<|endoftext|>