<commit_before>/*!
 * Connect - Tedious
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var tedious=require('tedious');
var tediousPool=require('tedious-connection-pool');
var debug={
    connection: require('debug')('connect-tedious:connection'),
    sql: require('debug')('connect-tedious:sql')
};

/**
 * One day in seconds.
 */
var oneDay = 86400;

function initConnection(c) {
    if (!c)
        return;

    c.on('errorMessage', function(error) {
      console.error('ERROR '+error.message);
    }).on('infoMessage', function(info) {
      debug.connection('INFO '+info.message);
    }).on('debug', function(messageText) {
      debug.connection('DEBUG '+messageText);
    });
}

function debugSql(r) {
    if (!r)
        return;

    debug.sql('Executing '+r.sqlTextOrProcedure);

    var _i, _len;
    for (_i=0, _len=r.parameters.length; _i<_len; _i++) {
        var p=r.parameters[_i];
        debug.sql('@'+p.name+': '+p.value);
    }
}

/**
 * Return the `TediousStore` extending `connect`'s session Store.
 *
 * @param {object} connect
 * @return {Function}
 * @api public
 */
module.exports = function(connect){

  /**
   * Connect's Store.
   */

  var Store = connect.session.Store;

  /**
   * Initialize TediousStore with the given `options`.
   *
   * @param {Object} options
   * @api public
   */

  function TediousStore(options) {
    options = options || {};
    Store.call(this, options);

    this.tableName=options.tableName || '[dbo].[Sessions]';
    this.sidColumnName=options.sidColumnName || '[Sid]';
    this.sessColumnName=options.sessColumnName || '[Sess]';
    this.expiresColumnName=options.expiresColumnName || '[Expires]';

    this.pool=new tediousPool(
        {
            name: 'connect-tedious',
            min: options.minConnections || 0,
            max: options.maxConnections || 100,
            idleTimeout: options.idleTimeout || 30000
        },
        options.config
     );
  };

  /**
   * Inherit from `Store`.
   */

  TediousStore.prototype.__proto__ = Store.prototype;

  /**
   * Attempt to fetch session by the given `sid`.
   *
   * @param {String} sid
   * @param {Function} fn
   * @api public
   */

  TediousStore.prototype.get = function(sid, fn) {
    var self=this;
    self.pool.requestConnection(function(err, db) {
        if (err)
          return fn(err);
        initConnection(db);

        var r = new tedious.Request(
          'SELECT s.' + self.sessColumnName + ' FROM ' + self.tableName + ' s WHERE s.' + self.sidColumnName + '=@sid AND s.' + self.expiresColumnName + '>=SYSUTCDATETIME()',
          function(err, rowCount) {
            debug.sql("Executed SELECT");
            db.close();
            if (err)
              return fn(err);
            if (!rowCount || rowCount!==1)
              return  fn();
          }
        );
        r.on('row', function(columns) {
          if (!columns || columns.length!==1)
            return fn();

          var v=columns[0].value;
          debug.sql("Returning "+v);
          return fn(null, JSON.parse(v));
        });
        r.addParameter('sid', tedious.TYPES.VarChar, sid);

        debugSql(r);
        db.execSql(r);
    });
  };

  /**
   * Commit the given `sess` object associated with the given `sid`.
   *
   * @param {String} sid
   * @param {Session} sess
   * @param {Function} fn
   * @api public
   */

  TediousStore.prototype.set = function(sid, sess, fn){
    var self=this;
    self.pool.requestConnection(function(err, db) {
        if (err)
          return fn(err);
        initConnection(db);

        var duration = sess.cookie.maxAge || oneDay;
        var r = new tedious.Request(
          'MERGE INTO ' + self.tableName + ' WITH (HOLDLOCK) s' +
          '  USING (VALUES(@sid, @sess)) ns(' + self.sidColumnName + ', ' + self.sessColumnName + ') ON (s.' + self.sidColumnName + '=ns.' + self.sidColumnName + ')' +
          '  WHEN MATCHED THEN UPDATE SET s.' + self.sessColumnName + '=@sess, s.' + self.expiresColumnName + '=DATEADD(ss, @duration, SYSUTCDATETIME())' +
          '  WHEN NOT MATCHED THEN INSERT (' + self.sidColumnName + ', ' + self.sessColumnName + ', ' + self.expiresColumnName + ') VALUES (@sid, @sess, DATEADD(ss, @duration, SYSUTCDATETIME()));',
          function(err) {
            debug.sql("Executed MERGE");
            db.close();
            fn.apply(self, arguments);
          }
        );
        r.addParameter('sid', tedious.TYPES.VarChar, sid);
        r.addParameter('sess', tedious.TYPES.NVarChar, JSON.stringify(sess));
        r.addParameter('duration', tedious.TYPES.Int, duration);

        debugSql(r);
        db.execSql(r);
    });
  };

  /**
   * Destroy the session associated with the given `sid`.
   *
   * @param {String} sid
   * @api public
   */

  TediousStore.prototype.destroy = function(sid, fn){
    var self=this;
    self.pool.requestConnection(function(err, db) {
        if (err)
          return fn(err);
        initConnection(db);

        var r = new tedious.Request(
          'DELETE FROM ' + self.tableName + ' s WHERE s.' + self.sidColumnName + '=@sid',
          function(err) {
            debug.sql("Executed DELETE");
            db.close();
            if (err)
              return fn(err);
            return fn(err, true);
          }
        );
        r.addParameter('sid', tedious.TYPES.VarChar, sid);

        debugSql(r);
        db.execSql(r);
    });
  };

  /**
   * Fetch number of sessions.
   *
   * @param {Function} fn
   * @api public
   */

  TediousStore.prototype.length = function(fn){
    var self=this;
    self.pool.requestConnection(function(err, db) {
        if (err)
          return fn(err);
        initConnection(db);

        var r = new tedious.Request(
          'SELECT @count=COUNT(*) FROM ' + self.tableName,
          function(err, rowCount) {
            debug.sql("Executed SELECT");
            db.close();
            if (err)
              return fn(err);
            if (!rowCount || rowCount!==1)
              return  fn();
          }
        );
        r.on('returnValue', function(parameterName, value, metadata) {
          if (!value)
            return fn();
          return fn(null, value);
        });
        request.addOutputParameter('count', tedious.TYPES.Int);

        debugSql(r);
        db.execSql(r);
    });
  };

  /**
   * Clear all sessions.
   *
   * @param {Function} fn
   * @api public
   */

  TediousStore.prototype.clear = function(fn){
    var self=this;
    self.pool.requestConnection(function(err, db) {
        if (err)
          return fn(err);
        initConnection(db);

        var r = new tedious.Request(
          'DELETE FROM ' + self.tableName,
          function(err) {
            debug.sql("Executed DELETE");
            db.close();
            if (err)
              return fn(err);
            fn(null, true);
          }
        );

        debugSql(r);
        db.execSql(r);
    });
  };

  return TediousStore;
};
<commit_msg>Fix #1 Incorrect SQL statement<commit_after>/*!
 * Connect - Tedious
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var tedious=require('tedious');
var tediousPool=require('tedious-connection-pool');
var debug={
    connection: require('debug')('connect-tedious:connection'),
    sql: require('debug')('connect-tedious:sql')
};

/**
 * One day in seconds.
 */
var oneDay = 86400;

function initConnection(c) {
    if (!c)
        return;

    c.on('errorMessage', function(error) {
      console.error('ERROR '+error.message);
    }).on('infoMessage', function(info) {
      debug.connection('INFO '+info.message);
    }).on('debug', function(messageText) {
      debug.connection('DEBUG '+messageText);
    });
}

function debugSql(r) {
    if (!r)
        return;

    debug.sql('Executing '+r.sqlTextOrProcedure);

    var _i, _len;
    for (_i=0, _len=r.parameters.length; _i<_len; _i++) {
        var p=r.parameters[_i];
        debug.sql('@'+p.name+': '+p.value);
    }
}

/**
 * Return the `TediousStore` extending `connect`'s session Store.
 *
 * @param {object} connect
 * @return {Function}
 * @api public
 */
module.exports = function(connect){

  /**
   * Connect's Store.
   */

  var Store = connect.session.Store;

  /**
   * Initialize TediousStore with the given `options`.
   *
   * @param {Object} options
   * @api public
   */

  function TediousStore(options) {
    options = options || {};
    Store.call(this, options);

    this.tableName=options.tableName || '[dbo].[Sessions]';
    this.sidColumnName=options.sidColumnName || '[Sid]';
    this.sessColumnName=options.sessColumnName || '[Sess]';
    this.expiresColumnName=options.expiresColumnName || '[Expires]';

    this.pool=new tediousPool(
        {
            name: 'connect-tedious',
            min: options.minConnections || 0,
            max: options.maxConnections || 100,
            idleTimeout: options.idleTimeout || 30000
        },
        options.config
     );
  };

  /**
   * Inherit from `Store`.
   */

  TediousStore.prototype.__proto__ = Store.prototype;

  /**
   * Attempt to fetch session by the given `sid`.
   *
   * @param {String} sid
   * @param {Function} fn
   * @api public
   */

  TediousStore.prototype.get = function(sid, fn) {
    var self=this;
    self.pool.requestConnection(function(err, db) {
        if (err)
          return fn(err);
        initConnection(db);

        var r = new tedious.Request(
          'SELECT s.' + self.sessColumnName + ' FROM ' + self.tableName + ' s WHERE s.' + self.sidColumnName + '=@sid AND s.' + self.expiresColumnName + '>=SYSUTCDATETIME()',
          function(err, rowCount) {
            debug.sql("Executed SELECT");
            db.close();
            if (err)
              return fn(err);
            if (!rowCount || rowCount!==1)
              return  fn();
          }
        );
        r.on('row', function(columns) {
          if (!columns || columns.length!==1)
            return fn();

          var v=columns[0].value;
          debug.sql("Returning "+v);
          return fn(null, JSON.parse(v));
        });
        r.addParameter('sid', tedious.TYPES.VarChar, sid);

        debugSql(r);
        db.execSql(r);
    });
  };

  /**
   * Commit the given `sess` object associated with the given `sid`.
   *
   * @param {String} sid
   * @param {Session} sess
   * @param {Function} fn
   * @api public
   */

  TediousStore.prototype.set = function(sid, sess, fn){
    var self=this;
    self.pool.requestConnection(function(err, db) {
        if (err)
          return fn(err);
        initConnection(db);

        var duration = sess.cookie.maxAge || oneDay;
        var r = new tedious.Request(
          'MERGE INTO ' + self.tableName + ' WITH (HOLDLOCK) s' +
          '  USING (VALUES(@sid, @sess)) ns(' + self.sidColumnName + ', ' + self.sessColumnName + ') ON (s.' + self.sidColumnName + '=ns.' + self.sidColumnName + ')' +
          '  WHEN MATCHED THEN UPDATE SET s.' + self.sessColumnName + '=@sess, s.' + self.expiresColumnName + '=DATEADD(ss, @duration, SYSUTCDATETIME())' +
          '  WHEN NOT MATCHED THEN INSERT (' + self.sidColumnName + ', ' + self.sessColumnName + ', ' + self.expiresColumnName + ') VALUES (@sid, @sess, DATEADD(ss, @duration, SYSUTCDATETIME()));',
          function(err) {
            debug.sql("Executed MERGE");
            db.close();
            fn.apply(self, arguments);
          }
        );
        r.addParameter('sid', tedious.TYPES.VarChar, sid);
        r.addParameter('sess', tedious.TYPES.NVarChar, JSON.stringify(sess));
        r.addParameter('duration', tedious.TYPES.Int, duration);

        debugSql(r);
        db.execSql(r);
    });
  };

  /**
   * Destroy the session associated with the given `sid`.
   *
   * @param {String} sid
   * @api public
   */

  TediousStore.prototype.destroy = function(sid, fn){
    var self=this;
    self.pool.requestConnection(function(err, db) {
        if (err)
          return fn(err);
        initConnection(db);

        var r = new tedious.Request(
          'DELETE s FROM ' + self.tableName + ' s WHERE s.' + self.sidColumnName + '=@sid',
          function(err) {
            debug.sql("Executed DELETE");
            db.close();
            if (err)
              return fn(err);
            return fn(err, true);
          }
        );
        r.addParameter('sid', tedious.TYPES.VarChar, sid);

        debugSql(r);
        db.execSql(r);
    });
  };

  /**
   * Fetch number of sessions.
   *
   * @param {Function} fn
   * @api public
   */

  TediousStore.prototype.length = function(fn){
    var self=this;
    self.pool.requestConnection(function(err, db) {
        if (err)
          return fn(err);
        initConnection(db);

        var r = new tedious.Request(
          'SELECT @count=COUNT(*) FROM ' + self.tableName,
          function(err, rowCount) {
            debug.sql("Executed SELECT");
            db.close();
            if (err)
              return fn(err);
            if (!rowCount || rowCount!==1)
              return  fn();
          }
        );
        r.on('returnValue', function(parameterName, value, metadata) {
          if (!value)
            return fn();
          return fn(null, value);
        });
        request.addOutputParameter('count', tedious.TYPES.Int);

        debugSql(r);
        db.execSql(r);
    });
  };

  /**
   * Clear all sessions.
   *
   * @param {Function} fn
   * @api public
   */

  TediousStore.prototype.clear = function(fn){
    var self=this;
    self.pool.requestConnection(function(err, db) {
        if (err)
          return fn(err);
        initConnection(db);

        var r = new tedious.Request(
          'DELETE FROM ' + self.tableName,
          function(err) {
            debug.sql("Executed DELETE");
            db.close();
            if (err)
              return fn(err);
            fn(null, true);
          }
        );

        debugSql(r);
        db.execSql(r);
    });
  };

  return TediousStore;
};
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var mongoose = require('mongoose')
  , Proposal = mongoose.model('Proposal')
  , tagApi = require('./tag')
  , commentApi = require('./comment')
  , log = require('debug')('db-api:proposal');

/**
 * Get all proposals
 *
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'proposals' list items found or `undefined`
 * @return {Module} `proposal` module
 * @api public
 */

exports.all = function all(fn) {
  log('Looking for all proposals.')

  Proposal
  .find()
  .populate('author', 'id firstName lastName avatar')
  .populate('tag', 'id hash')
  .populate('participants', 'id firstName lastName avatar')
  .sort('-createdAt')
  .exec(function (err, proposals) {
    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    log('Delivering proposals %j', mapByProperty(proposals, 'id'));
    fn(null, proposals);
  });

  return this;
}

/**
 * Create or retrieve Proposal from `proposal` descriptor
 *
 * @param {Object} proposal object descriptor
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'proposal' single object created or `undefined`
 * @return {Module} `proposal` module
 * @api public
 */

exports.create = function create(proposal, fn) {
  log('Creating new proposal %j', proposal);

  // wrong using tag api within proposal's
  log('Looking for tag %s in database.', proposal.tag);
  tagApi.create(proposal.tag, function (err, tag) {
    if (err) {
      log('Found error from tag creation %j', err);
      return fn(err);
    };

    proposal.tag = tag;
    proposal.participants = [proposal.author];

    (new Proposal(proposal)).save(function (err, saved) {
      if (err) {
        log('Found error %j', err);
        return fn(err);
      };

      log('Delivering proposal %j', saved);
      fn(null, saved);
    });
  })

  return this;
};

/**
 * Get Proposal form `id` string or `ObjectId`
 *
 * @param {String|ObjectId} id Proposal's `id`
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'proposal' single object created or `undefined`
 * @api public
 */

exports.get = function get(id, fn) {
  log('Looking for proposal %s', id);

  Proposal
  .findById(id)
  .populate('author', 'id firstName lastName avatar')
  .populate('tag', 'id hash')
  .populate('participants', 'id firstName lastName avatar')
  .exec(function (err, proposal) {
    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    log('Delivering proposal %j', proposal);
    fn(null, proposal);
  });
};

/**
 * Direct comment to proposal
 *
 * @param {String} id Proposal's `id`
 * @param {Object} comment to attach
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'proposal' single object created or `undefined`
 * @api public
 */

exports.comment = function comment(id, comment, fn) {
  log('Creating comment %j for proposal %s', comment, id);
  commentApi.create(id, comment, function (err, commentDoc) {
    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    log('Delivering comment %j', commentDoc);
    fn(null, commentDoc);
  });
};

/**
 * Vote proposal
 *
 * @param {String} id Proposals `id`
 * @param {String} citizen author of the vote
 * @param {String} value `positive` or `negative` only
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'proposal' single object created or `undefined`
 * @api public
 */

exports.vote = function vote(id, citizen, value, fn) {
  log('Proceding to vote %s at %s by %s', value, id, citizen);

  Proposal.findById(id, function (err, proposal) {
    var voters = [citizen], votes = 0;

    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    // Vote!
    // Maybe for performance it would be better
    // to first ask for the direction of the vote
    // (up|down) and then iterate over the voters
    voters.forEach(function(voter) {
      if ('positive' === value) {
        if (!proposal.upvoted(voter)) {
          votes += 1;
          proposal.upvote(voter);
        };
      } else if ('negative' === value) {
        if (!proposal.downvoted(voter)) {
          votes += 1;
          proposal.downvote(voter);
        };
      };
    });

    log('Counting %d %s votes for proposal %s', votes, value, id);

    // Save vote from proposal.
    proposal.save(function (err, saved) {
      if (err) {
        log('Found error %j', err);
        return fn(err);
      };

      log('Delivering proposal %j', saved);
      fn(null, saved);
    });

  });
};

/**
 * Map array of objects by `property`
 *
 * @param {Array} source array of objects to map
 * @param {String} property to map from objects
 * @return {Array} array of listed properties
 * @api private
 */

function mapByProperty (source, property) {
  return source.map(function (item) { return item[property]; });
}<commit_msg>[db-api:proposal] - Rename `mapByProperty` to `pluck`<commit_after>/**
 * Module dependencies.
 */

var mongoose = require('mongoose')
  , Proposal = mongoose.model('Proposal')
  , tagApi = require('./tag')
  , commentApi = require('./comment')
  , log = require('debug')('db-api:proposal');

/**
 * Get all proposals
 *
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'proposals' list items found or `undefined`
 * @return {Module} `proposal` module
 * @api public
 */

exports.all = function all(fn) {
  log('Looking for all proposals.')

  Proposal
  .find()
  .populate('author', 'id firstName lastName avatar')
  .populate('tag', 'id hash')
  .populate('participants', 'id firstName lastName avatar')
  .sort('-createdAt')
  .exec(function (err, proposals) {
    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    log('Delivering proposals %j', pluck(proposals, 'id'));
    fn(null, proposals);
  });

  return this;
}

/**
 * Create or retrieve Proposal from `proposal` descriptor
 *
 * @param {Object} proposal object descriptor
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'proposal' single object created or `undefined`
 * @return {Module} `proposal` module
 * @api public
 */

exports.create = function create(proposal, fn) {
  log('Creating new proposal %j', proposal);

  // wrong using tag api within proposal's
  log('Looking for tag %s in database.', proposal.tag);
  tagApi.create(proposal.tag, function (err, tag) {
    if (err) {
      log('Found error from tag creation %j', err);
      return fn(err);
    };

    proposal.tag = tag;
    proposal.participants = [proposal.author];

    (new Proposal(proposal)).save(function (err, saved) {
      if (err) {
        log('Found error %j', err);
        return fn(err);
      };

      log('Delivering proposal %j', saved);
      fn(null, saved);
    });
  })

  return this;
};

/**
 * Get Proposal form `id` string or `ObjectId`
 *
 * @param {String|ObjectId} id Proposal's `id`
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'proposal' single object created or `undefined`
 * @api public
 */

exports.get = function get(id, fn) {
  log('Looking for proposal %s', id);

  Proposal
  .findById(id)
  .populate('author', 'id firstName lastName avatar')
  .populate('tag', 'id hash')
  .populate('participants', 'id firstName lastName avatar')
  .exec(function (err, proposal) {
    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    log('Delivering proposal %j', proposal);
    fn(null, proposal);
  });
};

/**
 * Direct comment to proposal
 *
 * @param {String} id Proposal's `id`
 * @param {Object} comment to attach
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'proposal' single object created or `undefined`
 * @api public
 */

exports.comment = function comment(id, comment, fn) {
  log('Creating comment %j for proposal %s', comment, id);
  commentApi.create(id, comment, function (err, commentDoc) {
    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    log('Delivering comment %j', commentDoc);
    fn(null, commentDoc);
  });
};

/**
 * Vote proposal
 *
 * @param {String} id Proposals `id`
 * @param {String} citizen author of the vote
 * @param {String} value `positive` or `negative` only
 * @param {Function} fn callback function
 *   - 'err' error found while process or `null`
 *   - 'proposal' single object created or `undefined`
 * @api public
 */

exports.vote = function vote(id, citizen, value, fn) {
  log('Proceding to vote %s at %s by %s', value, id, citizen);

  Proposal.findById(id, function (err, proposal) {
    var voters = [citizen], votes = 0;

    if (err) {
      log('Found error %j', err);
      return fn(err);
    };

    // Vote!
    // Maybe for performance it would be better
    // to first ask for the direction of the vote
    // (up|down) and then iterate over the voters
    voters.forEach(function(voter) {
      if ('positive' === value) {
        if (!proposal.upvoted(voter)) {
          votes += 1;
          proposal.upvote(voter);
        };
      } else if ('negative' === value) {
        if (!proposal.downvoted(voter)) {
          votes += 1;
          proposal.downvote(voter);
        };
      };
    });

    log('Counting %d %s votes for proposal %s', votes, value, id);

    // Save vote from proposal.
    proposal.save(function (err, saved) {
      if (err) {
        log('Found error %j', err);
        return fn(err);
      };

      log('Delivering proposal %j', saved);
      fn(null, saved);
    });

  });
};

/**
 * Map array of objects by `property`
 *
 * @param {Array} source array of objects to map
 * @param {String} property to map from objects
 * @return {Array} array of listed properties
 * @api private
 */

function pluck (source, property) {
  return source.map(function (item) { return item[property]; });
}<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2014 Google Inc. All rights reserved.
 *
 * Licensed 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.
 */

/**
 * @fileoverview UI Controller.
 * @author tomfitzgerald@google.com (Tom Fitzgerald)
 */
'use strict';

goog.provide('babbage.controllers.UiCtrl');

goog.require('goog.Uri.QueryData');
goog.require('goog.crypt.base64');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.EventHandler');
goog.require('goog.events.EventType');
goog.require('goog.fs.FileReader');
goog.require('goog.fs.FileReader.EventType');

/**
 * UiController
 * @param {!angular.Scope} $scope Angular scope.
 * @param {!angular.Scope} $rootScope Angular root scope.
 * @param {!angular.$location} $location Angular location object.
 * @param {!babbage.services.PluginsService} PluginsService
 * @ngInject
 * @constructor
 */
babbage.controllers.UiCtrl = function(
    $scope,
    $rootScope,
    $location,
    PluginsService) {
  $rootScope['inputFile'] = false;

  /** @private */
  this.scope_ = $scope;

  /** @private */
  this.rootScope_ = $rootScope;

  /** @private */
  this.pluginsService_ = PluginsService;

  /** @private */
  this.outputTextEl_ = goog.dom.getElement(
      babbage.controllers.UiCtrl.IDS_['OUTPUT']);

  /** @private */
  this.fileUploadInputEl_ = goog.dom.getElement(
      babbage.controllers.UiCtrl.IDS_['FILE_UPLOAD_INPUT']);

  /** @private */
  this.handler_ = new goog.events.EventHandler(this);

  this.rootScope_.selectedPlugins = [];

  this.rootScope_.selectedPluginsEl = [];

  goog.exportProperty($rootScope, 'selectedPlugins',
      $rootScope.selectedPlugins);

  goog.exportProperty($rootScope, 'selectedPluginsEl',
      $rootScope.selectedPluginsEl);

  goog.exportProperty($scope, 'ids', babbage.controllers.UiCtrl.IDS_);

  // goog.exportProperty($scope, 'listPlugins',
  //     goog.bind(this.listPlugins, this));

  goog.exportProperty($scope, 'removePlugin',
      goog.bind(this.removePlugin, this));

  goog.exportProperty($scope, 'helpButtonClicked',
      goog.bind(this.helpButtonClicked, this));

  goog.exportProperty($scope, 'selectPlugin',
      goog.bind(this.selectPlugin, this));

  goog.exportProperty($scope, 'clearButtonClicked',
      goog.bind(this.clearButtonClicked, this));

  goog.exportProperty($scope, 'submitButtonClicked',
      goog.bind(this.submitButtonClicked, this));

  goog.exportProperty($scope, 'createUploadListener',
      goog.bind(this.createUploadListener, this));

  goog.exportProperty($scope, 'downloadFile',
      goog.bind(this.downloadFile, this));
};

/**
 * Element ID's.
 * @private
 * @const
 */
babbage.controllers.UiCtrl.IDS_ = {
  'SELECTED_PLUGINS': 'selected-plugin-list',
  'FILE_UPLOAD_INPUT': 'fileUploadInput',
  'INPUT': 'input',
  'OUTPUT': 'output'
};

/**
 * Strings used in UI.
 * @const
 * @private
 */
babbage.controllers.UiCtrl.STRINGS_ = {
  'ERROR_DECODING': 'Oops, something broked. :\'(',
  'NO_PLUGINS_SELECTED': 'No plugins selected.',
  'NO_INPUT': 'No input.'
};

/**
 * URI's.
 * @const
 * @private
 */
babbage.controllers.UiCtrl.URIs_ = {
  'MAIN_PAGE': '/',
  'HELP_PAGE': '/help',
  'ABOUT_PAGE': '/about'
};

babbage.controllers.UiCtrl.HELP_MESSAGE = '- Paste in text in the input ' +
    'text field.\n-Select a plugin on the left by clicking its name. ' +
    'Some plugins have options, hover over a plugin for more details on how ' +
    'they work. Chain together plugins for powerful results.\n-Hit Run ' +
    'to decode your text.';

/**
 * Retrieves lists of available plugins.
 * @export
 */
babbage.controllers.UiCtrl.prototype.listPlugins = function() {
  this.pluginsService_.listPlugins().then(goog.bind(function(response) {
    this.scope_.plugins = response;
  }, this));
};

/**
 * Adds plugin to selected list.
 * @param {!Element} plugin The plugin that was clicked.
 */
babbage.controllers.UiCtrl.prototype.selectPlugin = function(plugin) {
  this.rootScope_['selectedPlugins'].push(plugin);
};

/**
 * Removes plugin from selected list.
 * @param {!goog.events.EventTarget} event Response from click event.
 * @param {!Element} plugin The plugin that was clicked.
 */
babbage.controllers.UiCtrl.prototype.removePlugin = function(event, plugin) {
  if (event.target.tagName != goog.dom.TagName.LI &&
      event.target.getAttribute('type') != 'checkbox') {
    return;
  }
  this.rootScope_['selectedPlugins'].splice(
      this.rootScope_['selectedPlugins'].indexOf(plugin), 1);
};

/**
 * Displays help page.
 */
babbage.controllers.UiCtrl.prototype.helpButtonClicked = function() {
  alert(babbage.controllers.UiCtrl.HELP_MESSAGE);
};

/**
 * Clears input, ouput and plugins.
 */
babbage.controllers.UiCtrl.prototype.clearButtonClicked = function() {
  this.scope_['inputTextArea'] = '';
  this.scope_['outputTextArea'] = '';
  this.fileUploadInputEl_.value = '';
};

/**
 * Sends data to App Engine and handles response.
 */
babbage.controllers.UiCtrl.prototype.submitButtonClicked = function() {
  var plugins = goog.dom.getElement(
      babbage.controllers.UiCtrl.IDS_['SELECTED_PLUGINS']);
  var selectedPlugins = this.pluginsElToObj_(plugins);

  // Are we reading a file or the textarea?
  var inputValue = this.scope_['inputFile'] ? this.scope_['inputFile'] :
      goog.crypt.base64.encodeString(this.scope_['inputTextArea']);

  var postData = {
    'input': inputValue,
    'plugins': selectedPlugins
  };
  this.pluginsService_.convertInput(postData).then(goog.bind(function(output) {
    if (!output.hasOwnProperty('success')) {
      alert(output['failure']);
      return;
    }
    // Save Base64 version in case we want to download.
    this.rootScope_['outputBase64'] = output.success;
    this.scope_['outputTextArea'] = goog.crypt.base64.decodeString(
        output.success);

    // Hacky highlight.
    setTimeout(goog.bind(function() {
      this.outputTextEl_.select();
    }, this), 100);
  }, this));
};

/**
 * Converts selected plugins from DOM elements into an object.
 * @param {!Array.<Element>} pluginEls Elements of selected plugins.
 * @return {Object.<string, string>} Plugins in an object.
 * @private
 */
babbage.controllers.UiCtrl.prototype.pluginsElToObj_ = function(pluginEls) {
  var plugins = [];
  for (var i = 0, plugin; plugin = pluginEls.children[i]; i++) {
    var options = [];
    if (plugin.children) {
      for (var j = 0, pluginOpts; pluginOpts = plugin.children[j]; j++) {
        if (pluginOpts.getAttribute('type') != 'text') {
          continue;
        }
        options.push(encodeURIComponent(pluginOpts.value));
      }
    }
    plugins.push({
      'name': plugin.getAttribute('data-plugin-name'),
      'options': options
    });
  }
  return plugins;
};

/**
 * Creates listeners on file input element.
 */
babbage.controllers.UiCtrl.prototype.createUploadListener = function() {
  var fileUploadEl_ = goog.dom.getElement(
      babbage.controllers.UiCtrl.IDS_['FILE_UPLOAD_INPUT']);
  this.handler_.listen(
      fileUploadEl_,
      goog.events.EventType.CHANGE,
      this.fileUploadChanged_);
};

/**
 * Reads response from file upload input.
 * @private
 * @param {!goog.events.Event} evt Event response.
 */
babbage.controllers.UiCtrl.prototype.fileUploadChanged_ = function(evt) {
  if (!this.fileUploadInputEl_.files.length) {
    return;
  }
  var fileReader = new FileReader();
  this.handler_.listen(
      fileReader,
      goog.fs.FileReader.EventType.LOAD_END,
      this.fileUploadCompleted_);
  fileReader.readAsBinaryString(goog.dom.getElement(
      babbage.controllers.UiCtrl.IDS_['FILE_UPLOAD_INPUT'])
      .files[0]);
};

/**
 * Uses the uploaded file as input.
 * @param {!goog.events.Event} evt Event response.
 * @private
 */
babbage.controllers.UiCtrl.prototype.fileUploadCompleted_ = function(evt) {
  this.scope_['inputFile'] = goog.crypt.base64.encodeString(evt.target.result);
  this.scope_.$digest();
};

/**
 * Downloads output as a file.
 */
babbage.controllers.UiCtrl.prototype.downloadFile = function() {
  window.open('data:application/octet-stream;base64,' +
      this.rootScope_['outputBase64'], 'blank');
};
<commit_msg>Update UiController.js<commit_after>/**
 * @license
 * Copyright 2014 Google Inc. All rights reserved.
 *
 * Licensed 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.
 */

/**
 * @fileoverview UI Controller.
 * @author tomfitzgerald@google.com (Tom Fitzgerald)
 */
'use strict';

goog.provide('babbage.controllers.UiCtrl');

goog.require('goog.Uri.QueryData');
goog.require('goog.crypt.base64');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.EventHandler');
goog.require('goog.events.EventType');
goog.require('goog.fs.FileReader');
goog.require('goog.fs.FileReader.EventType');

/**
 * UiController
 * @param {!angular.Scope} $scope Angular scope.
 * @param {!angular.Scope} $rootScope Angular root scope.
 * @param {!angular.$location} $location Angular location object.
 * @param {!babbage.services.PluginsService} PluginsService
 * @ngInject
 * @constructor
 */
babbage.controllers.UiCtrl = function(
    $scope,
    $rootScope,
    $location,
    PluginsService) {
  $rootScope['inputFile'] = false;

  /** @private */
  this.scope_ = $scope;

  /** @private */
  this.rootScope_ = $rootScope;

  /** @private */
  this.pluginsService_ = PluginsService;

  /** @private */
  this.outputTextEl_ = goog.dom.getElement(
      babbage.controllers.UiCtrl.IDS_['OUTPUT']);

  /** @private */
  this.fileUploadInputEl_ = goog.dom.getElement(
      babbage.controllers.UiCtrl.IDS_['FILE_UPLOAD_INPUT']);

  /** @private */
  this.handler_ = new goog.events.EventHandler(this);

  this.rootScope_.selectedPlugins = [];

  this.rootScope_.selectedPluginsEl = [];

  goog.exportProperty($rootScope, 'selectedPlugins',
      $rootScope.selectedPlugins);

  goog.exportProperty($rootScope, 'selectedPluginsEl',
      $rootScope.selectedPluginsEl);

  goog.exportProperty($scope, 'ids', babbage.controllers.UiCtrl.IDS_);

   goog.exportProperty($scope, 'listPlugins',
       goog.bind(this.listPlugins, this));

  goog.exportProperty($scope, 'removePlugin',
      goog.bind(this.removePlugin, this));

  goog.exportProperty($scope, 'helpButtonClicked',
      goog.bind(this.helpButtonClicked, this));

  goog.exportProperty($scope, 'selectPlugin',
      goog.bind(this.selectPlugin, this));

  goog.exportProperty($scope, 'clearButtonClicked',
      goog.bind(this.clearButtonClicked, this));

  goog.exportProperty($scope, 'submitButtonClicked',
      goog.bind(this.submitButtonClicked, this));

  goog.exportProperty($scope, 'createUploadListener',
      goog.bind(this.createUploadListener, this));

  goog.exportProperty($scope, 'downloadFile',
      goog.bind(this.downloadFile, this));
};

/**
 * Element ID's.
 * @private
 * @const
 */
babbage.controllers.UiCtrl.IDS_ = {
  'SELECTED_PLUGINS': 'selected-plugin-list',
  'FILE_UPLOAD_INPUT': 'fileUploadInput',
  'INPUT': 'input',
  'OUTPUT': 'output'
};

/**
 * Strings used in UI.
 * @const
 * @private
 */
babbage.controllers.UiCtrl.STRINGS_ = {
  'ERROR_DECODING': 'Oops, something broked. :\'(',
  'NO_PLUGINS_SELECTED': 'No plugins selected.',
  'NO_INPUT': 'No input.'
};

/**
 * URI's.
 * @const
 * @private
 */
babbage.controllers.UiCtrl.URIs_ = {
  'MAIN_PAGE': '/',
  'HELP_PAGE': '/help',
  'ABOUT_PAGE': '/about'
};

babbage.controllers.UiCtrl.HELP_MESSAGE = '- Paste in text in the input ' +
    'text field.\n-Select a plugin on the left by clicking its name. ' +
    'Some plugins have options, hover over a plugin for more details on how ' +
    'they work. Chain together plugins for powerful results.\n-Hit Run ' +
    'to decode your text.';

/**
 * Retrieves lists of available plugins.
 * @export
 */
babbage.controllers.UiCtrl.prototype.listPlugins = function() {
  this.pluginsService_.listPlugins().then(goog.bind(function(response) {
    this.scope_.plugins = response;
  }, this));
};

/**
 * Adds plugin to selected list.
 * @param {!Element} plugin The plugin that was clicked.
 */
babbage.controllers.UiCtrl.prototype.selectPlugin = function(plugin) {
  this.rootScope_['selectedPlugins'].push(plugin);
};

/**
 * Removes plugin from selected list.
 * @param {!goog.events.EventTarget} event Response from click event.
 * @param {!Element} plugin The plugin that was clicked.
 */
babbage.controllers.UiCtrl.prototype.removePlugin = function(event, plugin) {
  if (event.target.tagName != goog.dom.TagName.LI &&
      event.target.getAttribute('type') != 'checkbox') {
    return;
  }
  this.rootScope_['selectedPlugins'].splice(
      this.rootScope_['selectedPlugins'].indexOf(plugin), 1);
};

/**
 * Displays help page.
 */
babbage.controllers.UiCtrl.prototype.helpButtonClicked = function() {
  alert(babbage.controllers.UiCtrl.HELP_MESSAGE);
};

/**
 * Clears input, ouput and plugins.
 */
babbage.controllers.UiCtrl.prototype.clearButtonClicked = function() {
  this.scope_['inputTextArea'] = '';
  this.scope_['outputTextArea'] = '';
  this.fileUploadInputEl_.value = '';
};

/**
 * Sends data to App Engine and handles response.
 */
babbage.controllers.UiCtrl.prototype.submitButtonClicked = function() {
  var plugins = goog.dom.getElement(
      babbage.controllers.UiCtrl.IDS_['SELECTED_PLUGINS']);
  var selectedPlugins = this.pluginsElToObj_(plugins);

  // Are we reading a file or the textarea?
  var inputValue = this.scope_['inputFile'] ? this.scope_['inputFile'] :
      goog.crypt.base64.encodeString(this.scope_['inputTextArea']);

  var postData = {
    'input': inputValue,
    'plugins': selectedPlugins
  };
  this.pluginsService_.convertInput(postData).then(goog.bind(function(output) {
    if (!output.hasOwnProperty('success')) {
      alert(output['failure']);
      return;
    }
    // Save Base64 version in case we want to download.
    this.rootScope_['outputBase64'] = output.success;
    this.scope_['outputTextArea'] = goog.crypt.base64.decodeString(
        output.success);

    // Hacky highlight.
    setTimeout(goog.bind(function() {
      this.outputTextEl_.select();
    }, this), 100);
  }, this));
};

/**
 * Converts selected plugins from DOM elements into an object.
 * @param {!Array.<Element>} pluginEls Elements of selected plugins.
 * @return {Object.<string, string>} Plugins in an object.
 * @private
 */
babbage.controllers.UiCtrl.prototype.pluginsElToObj_ = function(pluginEls) {
  var plugins = [];
  for (var i = 0, plugin; plugin = pluginEls.children[i]; i++) {
    var options = [];
    if (plugin.children) {
      for (var j = 0, pluginOpts; pluginOpts = plugin.children[j]; j++) {
        if (pluginOpts.getAttribute('type') != 'text') {
          continue;
        }
        options.push(encodeURIComponent(pluginOpts.value));
      }
    }
    plugins.push({
      'name': plugin.getAttribute('data-plugin-name'),
      'options': options
    });
  }
  return plugins;
};

/**
 * Creates listeners on file input element.
 */
babbage.controllers.UiCtrl.prototype.createUploadListener = function() {
  var fileUploadEl_ = goog.dom.getElement(
      babbage.controllers.UiCtrl.IDS_['FILE_UPLOAD_INPUT']);
  this.handler_.listen(
      fileUploadEl_,
      goog.events.EventType.CHANGE,
      this.fileUploadChanged_);
};

/**
 * Reads response from file upload input.
 * @private
 * @param {!goog.events.Event} evt Event response.
 */
babbage.controllers.UiCtrl.prototype.fileUploadChanged_ = function(evt) {
  if (!this.fileUploadInputEl_.files.length) {
    return;
  }
  var fileReader = new FileReader();
  this.handler_.listen(
      fileReader,
      goog.fs.FileReader.EventType.LOAD_END,
      this.fileUploadCompleted_);
  fileReader.readAsBinaryString(goog.dom.getElement(
      babbage.controllers.UiCtrl.IDS_['FILE_UPLOAD_INPUT'])
      .files[0]);
};

/**
 * Uses the uploaded file as input.
 * @param {!goog.events.Event} evt Event response.
 * @private
 */
babbage.controllers.UiCtrl.prototype.fileUploadCompleted_ = function(evt) {
  this.scope_['inputFile'] = goog.crypt.base64.encodeString(evt.target.result);
  this.scope_.$digest();
};

/**
 * Downloads output as a file.
 */
babbage.controllers.UiCtrl.prototype.downloadFile = function() {
  window.open('data:application/octet-stream;base64,' +
      this.rootScope_['outputBase64'], 'blank');
};
<|endoftext|>


<commit_before>'use strict';

angular.module('confRegistrationWebApp')
  .controller('eventDetailsCtrl', function ($rootScope, $scope, $http, $sce, $timeout, $window, modalMessage, $filter, conference, ConfCache, permissions, permissionConstants, uuid) {
    $rootScope.globalPage = {
      type: 'admin',
      mainClass: 'container event-details',
      bodyClass: '',
      title: conference.name,
      confId: conference.id,
      footer: true
    };
    if (permissions.permissionInt >= permissionConstants.UPDATE) {
      $scope.templateUrl = 'views/eventDetails.html';
    } else {
      $scope.templateUrl = 'views/permissionError.html';
    }

    $scope.tabs = [
      {id: 'eventInfo', name: 'Event Information', view: 'views/eventDetails/eventInformation.html'},
      {id: 'regOptions', name: 'Registration Options', view: 'views/eventDetails/regOptions.html'},
      {id: 'regTypes', name: 'Registration Types', view: 'views/eventDetails/regTypes.html'},
      {id: 'paymentOptions', name: 'Payment Options', view: 'views/eventDetails/paymentOptions.html'},
      {id: 'contactInfo', name: 'Contact Information', view: 'views/eventDetails/contactInfo.html'}
    ];

    $scope.changeTab = function(tab){
      $scope.activeTab = tab;
    };
    $scope.changeTab($scope.tabs[0]);

    $scope.paymentGateways = [
      {id: 'AUTHORIZE_NET', name: 'Authorize.Net'}
    ];

    $scope.conference = angular.copy(conference);

    $scope.addRegType = function(){
      $scope.conference.registrantTypes.push({
        id: uuid(),
        cost: 0,
        earlyRegistrationCutoff: moment().add(7, 'days').format('YYYY-MM-DD HH:mm:ss')
      });
    };

    $scope.deleteRegType = function(id){
      if ($scope.conference.registrantTypes.length > 1) {
        _.remove($scope.conference.registrantTypes, function(type) { return type.id === id; });
      } else {
        $scope.notify = {
          class: 'alert-danger',
          message: $sce.trustAsHtml('You must have at least one registration type per event.')
        };
        $timeout(function() { $scope.notify = {}; }, 3500);
      }
    };

    $scope.saveEvent = function () {
      //validation check
      var validationErrors = [];

      //Event Name
      if (_.isEmpty($scope.conference.name)) {
        validationErrors.push('Please enter an event name.');
      }

      //Event Dates
      if ($scope.conference.eventStartTime > $scope.conference.eventEndTime) {
        validationErrors.push('Event end date/time must be after event start date/time.');
      }

      //Registration Window
      if ($scope.conference.registrationStartTime > $scope.conference.registrationEndTime) {
        validationErrors.push('Registration end date/time must be after registration start date/time.');
      }

      //Registrant Name
      angular.forEach($scope.conference.registrantTypes, function(t) {
        if (_.isEmpty(t.name)) {
          validationErrors.push('Please enter a name for all registration types.');
        }
      });

      //Event Cost
      angular.forEach($scope.conference.registrantTypes, function(t) {
        t.cost = Number(t.cost);
        if ( _.isNaN(t.cost) || t.cost < 0) {
          validationErrors.push('Event cost for \'' + t.name + '\' must be a positive number.');
        }
      });

      //Credit cards
      if (_.isEmpty($scope.conference.paymentGatewayId) && _.some($scope.conference.registrantTypes, 'acceptCreditCards')) {
        validationErrors.push('Please enter a credit card Account ID.');
      }

      //Minimum Deposit
      angular.forEach($scope.conference.registrantTypes, function(t) {
        if ($scope.conference.requireLogin && $scope.anyPaymentMethodAccepted(t) && String(t.minimumDeposit).length > 0 && !_.isNull(t.minimumDeposit)) {
          t.minimumDeposit = Number(t.minimumDeposit);
          if (t.minimumDeposit > t.cost) {
            validationErrors.push('The minimum deposit for \'' + t.name + '\' must be less than the cost.');
          }
        } else {
          t.minimumDeposit = null;
        }
      });

      //Early bird discount
      angular.forEach($scope.conference.registrantTypes, function(t) {
        angular.forEach(t.earlyRegistrationDiscounts, function(d, index){
          if (d.enabled) {
            d.amountOfDiscount = Number(d.amountOfDiscount);
            if (d.amountOfDiscount < 0) {
              validationErrors.push('Early registration discount ' + (index + 1) + ' for \'' + t.name + '\' must be a positive number.');
            }
            if (!d.deadline) {
              validationErrors.push('Early registration discount ' + (index + 1) + ' for \'' + t.name + '\' must include a valid date and time.');
            }
          }
        });
      });

      $window.scrollTo(0, 0);
      if (validationErrors.length > 0) {
        var errorMsg = 'Error! Please fix the following issues:
';
        angular.forEach(validationErrors, function (e) {
          errorMsg = errorMsg + '
' + e + '
';
        });
        errorMsg = errorMsg + '
';
        $scope.notify = {
          class: 'alert-danger',
          message: $sce.trustAsHtml(errorMsg)
        };
      } else {
        $scope.notify = {
          class: 'alert-warning',
          message: $sce.trustAsHtml('Saving...')
        };

        $http(
          {method: 'PUT',
            url: 'conferences/' + conference.id,
            data: $scope.conference
        }).success(function () {
            $scope.notify = {
              class: 'alert-success',
              message: $sce.trustAsHtml('Saved! Your event details have been updated.')
            };

            //Clear cache
            ConfCache.empty();
          }).error(function (data) {
            $scope.notify = {
              class: 'alert-danger',
              message: $sce.trustAsHtml('Error ' + data.errorMessage)
            };
          });
      }
    };

    $scope.anyPaymentMethodAccepted = function(type){
      return type.acceptCreditCards || type.acceptChecks || type.acceptTransfers || type.acceptScholarships;
    };

    $scope.acceptedPaymentMethods = function(){
      var regTypes = $scope.conference.registrantTypes;

      var paymentMethods = {
        acceptCreditCards: _.some(regTypes, 'acceptCreditCards'),
        acceptChecks:_.some(regTypes, 'acceptChecks'),
        acceptTransfers: _.some(regTypes, 'acceptTransfers'),
        acceptScholarships: _.some(regTypes, 'acceptScholarships')
      };
      return paymentMethods;
    };

    $scope.previewEmail = function(reg){
      var cost = $filter('currency')(reg.cost, '$');
      var eventStartTime = moment(conference.eventStartTime).format('dddd, MMMM D YYYY, h:mm a');
      var eventEndTime = moment(conference.eventEndTime).format('dddd, MMMM D YYYY, h:mm a');
      modalMessage.info({
        'title': 'Email Preview',
        'message': '
Hello ' + $rootScope.globalGreetingName + '!

You are registered for ' + $scope.conference.name + '.
' +
        '
Start Time: ' + eventStartTime + '
End Time: ' + eventEndTime + '
' +
        '
Total Cost: ' + cost + '
Total Amount Paid: ' + cost + '
Remaining Balance: $0.00
' +
        reg.customConfirmationEmailText,
        'okString': 'Close'
      });
    };
  });
<commit_msg>Warn admin they have unsaved changes<commit_after>'use strict';

angular.module('confRegistrationWebApp')
  .controller('eventDetailsCtrl', function ($rootScope, $scope, $http, $sce, $timeout, $window, modalMessage, $filter, $location, conference, ConfCache, permissions, permissionConstants, uuid) {
    $rootScope.globalPage = {
      type: 'admin',
      mainClass: 'container event-details',
      bodyClass: '',
      title: conference.name,
      confId: conference.id,
      footer: true
    };
    if (permissions.permissionInt >= permissionConstants.UPDATE) {
      $scope.templateUrl = 'views/eventDetails.html';
    } else {
      $scope.templateUrl = 'views/permissionError.html';
    }

    $scope.tabs = [
      {id: 'eventInfo', name: 'Event Information', view: 'views/eventDetails/eventInformation.html'},
      {id: 'regOptions', name: 'Registration Options', view: 'views/eventDetails/regOptions.html'},
      {id: 'regTypes', name: 'Registration Types', view: 'views/eventDetails/regTypes.html'},
      {id: 'paymentOptions', name: 'Payment Options', view: 'views/eventDetails/paymentOptions.html'},
      {id: 'contactInfo', name: 'Contact Information', view: 'views/eventDetails/contactInfo.html'}
    ];

    $scope.changeTab = function(tab){
      $scope.activeTab = tab;
    };
    $scope.changeTab($scope.tabs[0]);

    $scope.paymentGateways = [
      {id: 'AUTHORIZE_NET', name: 'Authorize.Net'}
    ];

    $scope.conference = angular.copy(conference);

    $scope.$on('$locationChangeStart', function(event, newLocation) {
      if(!angular.equals(conference, $scope.conference)){
        event.preventDefault();
        modalMessage.confirm({
          title: 'Warning',
          question: 'You have some unsaved changes on this page, are you sure you want to leave? Your changes will be lost.',
          normalSize: true
        }).then(function(){
          conference = angular.copy($scope.conference);
          $location.url($location.url(newLocation).hash());
        });
      }
    });

    $scope.addRegType = function(){
      $scope.conference.registrantTypes.push({
        id: uuid(),
        cost: 0,
        earlyRegistrationCutoff: moment().add(7, 'days').format('YYYY-MM-DD HH:mm:ss')
      });
    };

    $scope.deleteRegType = function(id){
      if ($scope.conference.registrantTypes.length > 1) {
        _.remove($scope.conference.registrantTypes, function(type) { return type.id === id; });
      } else {
        $scope.notify = {
          class: 'alert-danger',
          message: $sce.trustAsHtml('You must have at least one registration type per event.')
        };
        $timeout(function() { $scope.notify = {}; }, 3500);
      }
    };

    $scope.saveEvent = function () {
      //validation check
      var validationErrors = [];

      //Event Name
      if (_.isEmpty($scope.conference.name)) {
        validationErrors.push('Please enter an event name.');
      }

      //Event Dates
      if ($scope.conference.eventStartTime > $scope.conference.eventEndTime) {
        validationErrors.push('Event end date/time must be after event start date/time.');
      }

      //Registration Window
      if ($scope.conference.registrationStartTime > $scope.conference.registrationEndTime) {
        validationErrors.push('Registration end date/time must be after registration start date/time.');
      }

      //Registrant Name
      angular.forEach($scope.conference.registrantTypes, function(t) {
        if (_.isEmpty(t.name)) {
          validationErrors.push('Please enter a name for all registration types.');
        }
      });

      //Event Cost
      angular.forEach($scope.conference.registrantTypes, function(t) {
        t.cost = Number(t.cost);
        if ( _.isNaN(t.cost) || t.cost < 0) {
          validationErrors.push('Event cost for \'' + t.name + '\' must be a positive number.');
        }
      });

      //Credit cards
      if (_.isEmpty($scope.conference.paymentGatewayId) && _.some($scope.conference.registrantTypes, 'acceptCreditCards')) {
        validationErrors.push('Please enter a credit card Account ID.');
      }

      //Minimum Deposit
      angular.forEach($scope.conference.registrantTypes, function(t) {
        if ($scope.conference.requireLogin && $scope.anyPaymentMethodAccepted(t) && String(t.minimumDeposit).length > 0 && !_.isNull(t.minimumDeposit)) {
          t.minimumDeposit = Number(t.minimumDeposit);
          if (t.minimumDeposit > t.cost) {
            validationErrors.push('The minimum deposit for \'' + t.name + '\' must be less than the cost.');
          }
        } else {
          t.minimumDeposit = null;
        }
      });

      //Early bird discount
      angular.forEach($scope.conference.registrantTypes, function(t) {
        angular.forEach(t.earlyRegistrationDiscounts, function(d, index){
          if (d.enabled) {
            d.amountOfDiscount = Number(d.amountOfDiscount);
            if (d.amountOfDiscount < 0) {
              validationErrors.push('Early registration discount ' + (index + 1) + ' for \'' + t.name + '\' must be a positive number.');
            }
            if (!d.deadline) {
              validationErrors.push('Early registration discount ' + (index + 1) + ' for \'' + t.name + '\' must include a valid date and time.');
            }
          }
        });
      });

      $window.scrollTo(0, 0);
      if (validationErrors.length > 0) {
        var errorMsg = 'Error! Please fix the following issues:
';
        angular.forEach(validationErrors, function (e) {
          errorMsg = errorMsg + '
' + e + '
';
        });
        errorMsg = errorMsg + '
';
        $scope.notify = {
          class: 'alert-danger',
          message: $sce.trustAsHtml(errorMsg)
        };
      } else {
        $scope.notify = {
          class: 'alert-warning',
          message: $sce.trustAsHtml('Saving...')
        };

        $http(
          {method: 'PUT',
            url: 'conferences/' + conference.id,
            data: $scope.conference
        }).success(function () {
            $scope.notify = {
              class: 'alert-success',
              message: $sce.trustAsHtml('Saved! Your event details have been updated.')
            };

            conference = angular.copy($scope.conference);
            //Clear cache
            ConfCache.empty();
          }).error(function (data) {
            $scope.notify = {
              class: 'alert-danger',
              message: $sce.trustAsHtml('Error ' + data.errorMessage)
            };
          });
      }
    };

    $scope.anyPaymentMethodAccepted = function(type){
      return type.acceptCreditCards || type.acceptChecks || type.acceptTransfers || type.acceptScholarships;
    };

    $scope.acceptedPaymentMethods = function(){
      var regTypes = $scope.conference.registrantTypes;

      var paymentMethods = {
        acceptCreditCards: _.some(regTypes, 'acceptCreditCards'),
        acceptChecks:_.some(regTypes, 'acceptChecks'),
        acceptTransfers: _.some(regTypes, 'acceptTransfers'),
        acceptScholarships: _.some(regTypes, 'acceptScholarships')
      };
      return paymentMethods;
    };

    $scope.previewEmail = function(reg){
      var cost = $filter('currency')(reg.cost, '$');
      var eventStartTime = moment(conference.eventStartTime).format('dddd, MMMM D YYYY, h:mm a');
      var eventEndTime = moment(conference.eventEndTime).format('dddd, MMMM D YYYY, h:mm a');
      modalMessage.info({
        'title': 'Email Preview',
        'message': '
Hello ' + $rootScope.globalGreetingName + '!

You are registered for ' + $scope.conference.name + '.
' +
        '
Start Time: ' + eventStartTime + '
End Time: ' + eventEndTime + '
' +
        '
Total Cost: ' + cost + '
Total Amount Paid: ' + cost + '
Remaining Balance: $0.00
' +
        reg.customConfirmationEmailText,
        'okString': 'Close'
      });
    };
  });
<|endoftext|>


<commit_before>import _ from 'lodash';
import update from 'immutability-helper';
import Convert from 'ansi-to-html';
import history from '../../../common/history';
import initialState from './initialState';
import { reducer as fetchProjectData } from './fetchProjectData';
import { reducer as fetchFileContent } from './fetchFileContent';
import { reducer as showDemoAlertReducer } from './showDemoAlert';
import { reducer as hideDemoAlertReducer } from './hideDemoAlert';
import { reducer as saveFileReducer } from './saveFile';
import { reducer as closeTabReducer } from './closeTab';
import { reducer as moveTabReducer } from './moveTab';
import { CORE_EXEC_CORE_COMMAND_SUCCESS } from '../../core/redux/constants';
import { reducer as codeChangeReducer } from './codeChange';
import { reducer as stickTabReducer } from './stickTab';
import { storage } from '../../common/utils';
import { reducer as updateProjectDataReducer } from './updateProjectData';
import { reducer as showDialogReducer } from './showDialog';
import { reducer as hideDialogReducer } from './hideDialog';
import plugin from '../../../common/plugin';
import { reducer as setViewChangedReducer } from './setViewChanged';
import { reducer as setBottomDrawerVisibleReducer } from './setBottomDrawerVisible';
import { reducer as clearOutputReducer } from './clearOutput';
import { reducer as setBottomDrawerTabReducer } from './setBottomDrawerTab';

const convert = new Convert();

const reducers = [
  fetchProjectData,
  fetchFileContent,
  showDemoAlertReducer,
  hideDemoAlertReducer,
  saveFileReducer,
  closeTabReducer,
  moveTabReducer,
  codeChangeReducer,
  stickTabReducer,
  updateProjectDataReducer,
  showDialogReducer,
  hideDialogReducer,
  setViewChangedReducer,
  setBottomDrawerVisibleReducer,
  clearOutputReducer,
  setBottomDrawerTabReducer,
];

// const pascalCase = _.flow(
//   _.camelCase,
//   _.upperFirst
// );

export default function reducer(state = initialState, action) {
  let newState;
  switch (action.type) {
    // Put global reducers here
    case 'PROJECT_DATA_CHANGED':
    // case CORE_EXEC_CORE_COMMAND_SUCCESS: // For quick project reoload.
      newState = {
        ...state,
        projectDataNeedReload: true,
      };
      break;

    case '@@router/LOCATION_CHANGE': {
      // Open tab or switch tab type while url changes.
      const pathname = action.payload.pathname;
      if (!state.elementById) {
        newState = state;
        break;
      }
      let tab;
      plugin
        .getPlugins('tab.getTab')
        .reverse()
        .some(p => {
          const t = p.tab.getTab(pathname);
          if (!t) return false;
          tab = { ...p.tab.getTab(pathname) };
          return true;
        });
      let { openTabs, historyTabs } = state;

      if (!tab) {
        openTabs = openTabs.map(t => (t.isActive ? { ...t, isActive: false } : t));
        newState = { ...state, openTabs };
        storage.session.setItem('openTabs', openTabs);
        break;
        // tab = {
        //   name: 'No Tab',
        //   key: 'rekit:not-found',
        //   icon: 'not-found',
        //   iconColor: 'red',
        // };
      }
      tab.isTemp = !tab.noPreview;

      openTabs = openTabs.map(t => ({ ...t, isActive: false }));

      let foundTab = _.find(openTabs, { key: tab.key });
      if (!foundTab) {
        if (tab.isTemp) {
          const currentTemp = _.find(openTabs, 'isTemp');
          if (currentTemp) {
            openTabs = _.filter(openTabs, t => !t.isTemp);
            historyTabs = _.without(historyTabs, currentTemp.key);
          }
        }

        tab.urlPath = pathname;
        tab.isActive = true;

        openTabs = [...openTabs, tab];
        foundTab = tab;
      } else {
        foundTab = { ...tab, isTemp: foundTab.isTemp };
      }

      // If current url path doesn't match urlPath of element which has sub tabs,
      // redirect to the default/current url path of the element.
      if (
        foundTab.subTabs &&
        foundTab.subTabs.length &&
        !foundTab.subTabs.some(t => t.urlPath === pathname)
      ) {
        let redirectUrlPath;
        if (foundTab.subTabs.some(t => t.urlPath === foundTab.urlPath))
          redirectUrlPath = foundTab.urlPath;
        else
          redirectUrlPath = (_.find(foundTab.subTabs, 'isDefault') || foundTab.subTabs[0]).urlPath;
        requestAnimationFrame(() => history.replace(redirectUrlPath));
        newState = state;
        break;
      }

      const foundIndex = _.findIndex(openTabs, { key: foundTab.key });
      openTabs = update(openTabs, {
        [foundIndex]: { $set: { ...foundTab, urlPath: pathname, isActive: true } },
      });
      historyTabs = [tab.key, ..._.without(historyTabs, tab.key)];
      newState = { ...state, openTabs, historyTabs };
      storage.session.setItem('openTabs', openTabs);
      storage.session.setItem('historyTabs', historyTabs);
      break;
    }

    case 'REKIT_STUDIO_OUTPUT': {
      let output = state.output.slice(0);
      if (Array.isArray(action.data)) {
        output.push.apply(
          output,
          action.data.map(item => ({
            ...item,
            text: convert
              .toHtml(item.text.replace(/ /g, ' '))
              .replace('#00A', '#1565C0')
              .replace(/color:#555/g, 'color:#777'),
          }))
        );
      }
      if (output.length > 300) output = output.slice(-300);
      newState = {
        ...state,
        output,
      };
      break;
    }

    default:
      newState = state;
      break;
  }
  return reducers.reduce((s, r) => r(s, action), newState);
}
<commit_msg>Escape html tag.<commit_after>import _ from 'lodash';
import update from 'immutability-helper';
import Convert from 'ansi-to-html';
import history from '../../../common/history';
import initialState from './initialState';
import { reducer as fetchProjectData } from './fetchProjectData';
import { reducer as fetchFileContent } from './fetchFileContent';
import { reducer as showDemoAlertReducer } from './showDemoAlert';
import { reducer as hideDemoAlertReducer } from './hideDemoAlert';
import { reducer as saveFileReducer } from './saveFile';
import { reducer as closeTabReducer } from './closeTab';
import { reducer as moveTabReducer } from './moveTab';
import { CORE_EXEC_CORE_COMMAND_SUCCESS } from '../../core/redux/constants';
import { reducer as codeChangeReducer } from './codeChange';
import { reducer as stickTabReducer } from './stickTab';
import { storage } from '../../common/utils';
import { reducer as updateProjectDataReducer } from './updateProjectData';
import { reducer as showDialogReducer } from './showDialog';
import { reducer as hideDialogReducer } from './hideDialog';
import plugin from '../../../common/plugin';
import { reducer as setViewChangedReducer } from './setViewChanged';
import { reducer as setBottomDrawerVisibleReducer } from './setBottomDrawerVisible';
import { reducer as clearOutputReducer } from './clearOutput';
import { reducer as setBottomDrawerTabReducer } from './setBottomDrawerTab';

const convert = new Convert();

const reducers = [
  fetchProjectData,
  fetchFileContent,
  showDemoAlertReducer,
  hideDemoAlertReducer,
  saveFileReducer,
  closeTabReducer,
  moveTabReducer,
  codeChangeReducer,
  stickTabReducer,
  updateProjectDataReducer,
  showDialogReducer,
  hideDialogReducer,
  setViewChangedReducer,
  setBottomDrawerVisibleReducer,
  clearOutputReducer,
  setBottomDrawerTabReducer,
];

// const pascalCase = _.flow(
//   _.camelCase,
//   _.upperFirst
// );

export default function reducer(state = initialState, action) {
  let newState;
  switch (action.type) {
    // Put global reducers here
    case 'PROJECT_DATA_CHANGED':
    // case CORE_EXEC_CORE_COMMAND_SUCCESS: // For quick project reoload.
      newState = {
        ...state,
        projectDataNeedReload: true,
      };
      break;

    case '@@router/LOCATION_CHANGE': {
      // Open tab or switch tab type while url changes.
      const pathname = action.payload.pathname;
      if (!state.elementById) {
        newState = state;
        break;
      }
      let tab;
      plugin
        .getPlugins('tab.getTab')
        .reverse()
        .some(p => {
          const t = p.tab.getTab(pathname);
          if (!t) return false;
          tab = { ...p.tab.getTab(pathname) };
          return true;
        });
      let { openTabs, historyTabs } = state;

      if (!tab) {
        openTabs = openTabs.map(t => (t.isActive ? { ...t, isActive: false } : t));
        newState = { ...state, openTabs };
        storage.session.setItem('openTabs', openTabs);
        break;
        // tab = {
        //   name: 'No Tab',
        //   key: 'rekit:not-found',
        //   icon: 'not-found',
        //   iconColor: 'red',
        // };
      }
      tab.isTemp = !tab.noPreview;

      openTabs = openTabs.map(t => ({ ...t, isActive: false }));

      let foundTab = _.find(openTabs, { key: tab.key });
      if (!foundTab) {
        if (tab.isTemp) {
          const currentTemp = _.find(openTabs, 'isTemp');
          if (currentTemp) {
            openTabs = _.filter(openTabs, t => !t.isTemp);
            historyTabs = _.without(historyTabs, currentTemp.key);
          }
        }

        tab.urlPath = pathname;
        tab.isActive = true;

        openTabs = [...openTabs, tab];
        foundTab = tab;
      } else {
        foundTab = { ...tab, isTemp: foundTab.isTemp };
      }

      // If current url path doesn't match urlPath of element which has sub tabs,
      // redirect to the default/current url path of the element.
      if (
        foundTab.subTabs &&
        foundTab.subTabs.length &&
        !foundTab.subTabs.some(t => t.urlPath === pathname)
      ) {
        let redirectUrlPath;
        if (foundTab.subTabs.some(t => t.urlPath === foundTab.urlPath))
          redirectUrlPath = foundTab.urlPath;
        else
          redirectUrlPath = (_.find(foundTab.subTabs, 'isDefault') || foundTab.subTabs[0]).urlPath;
        requestAnimationFrame(() => history.replace(redirectUrlPath));
        newState = state;
        break;
      }

      const foundIndex = _.findIndex(openTabs, { key: foundTab.key });
      openTabs = update(openTabs, {
        [foundIndex]: { $set: { ...foundTab, urlPath: pathname, isActive: true } },
      });
      historyTabs = [tab.key, ..._.without(historyTabs, tab.key)];
      newState = { ...state, openTabs, historyTabs };
      storage.session.setItem('openTabs', openTabs);
      storage.session.setItem('historyTabs', historyTabs);
      break;
    }

    case 'REKIT_STUDIO_OUTPUT': {
      let output = state.output.slice(0);
      if (Array.isArray(action.data)) {
        output.push.apply(
          output,
          action.data.map(item => ({
            ...item,
            text: convert
              .toHtml(item.text.replace(/</g, '<').replace(/>/g, '>').replace(/ /g, ' '))
              .replace('#00A', '#1565C0')
              .replace(/color:#555/g, 'color:#777'),
          }))
        );
      }
      if (output.length > 300) output = output.slice(-300);
      newState = {
        ...state,
        output,
      };
      break;
    }

    default:
      newState = state;
      break;
  }
  return reducers.reduce((s, r) => r(s, action), newState);
}
<|endoftext|>


<commit_before>'use strict';

angular.module('mapsheetApp')
  .directive('msMapWidget', function () {
    return {
      templateUrl: 'views/map-widget.html',
      scope: {
        'msDocument': '=',
        'msGeoAdapter': '='
      },
      restrict: 'A',
      link: function(scope) {
        scope.lat = 0;
        scope.lon = 0;

        if (!scope.map) {
          scope.map = L.map('map').setView([51.505, -0.09], 13);
          L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            attribution: '© OpenStreetMap contributors'
          }).addTo(scope.map);
        }

        scope.map.on('mousemove', function(evt) {
          scope.$apply(function() {
              scope.lat = evt.latlng.lat;
              scope.lon = evt.latlng.lng;
            });
        });

        var group = null;
        var refreshPoints = function() {
          if (group) {
            group.clearLayers();
          } else {
            group = L.layerGroup([]);
          }

          var points = scope.msGeoAdapter.geoPoints();
          _.each(points, function(point) {
              if (point.type === 'marker') {
                group.addLayer(L.marker([point.lat, point.lng]));
              }
              if (point.type === 'circle') {
                group.addLayer(L.circle([point.lat, point.lng], point.rad * 1000));
              }
            });

          group.addTo(scope.map);
        };

        _.each(['msDocument.table', 'msGeoAdapter.showRows.length', 'msGeoAdapter.latCol',
          'msGeoAdapter.lngCol', 'msGeoAdapter.radCol'], function(prop) {
              scope.$watch(prop, refreshPoints);
            });
      }
    };
  });
<commit_msg>Small twich in map coordinate tracking<commit_after>'use strict';

angular.module('mapsheetApp')
  .directive('msMapWidget', function () {
    return {
      templateUrl: 'views/map-widget.html',
      scope: {
        'msDocument': '=',
        'msGeoAdapter': '='
      },
      restrict: 'A',
      link: function(scope) {
        scope.lat = 0;
        scope.lon = 0;

        if (!scope.map) {
          scope.map = L.map('map').setView([51.505, -0.09], 13);
          L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            attribution: '© OpenStreetMap contributors'
          }).addTo(scope.map);
        }

        scope.map.on('mousemove', function(evt) {
          scope.$apply(function() {
              scope.lat = evt.latlng.lat;
              scope.lon = evt.latlng.lng;
            });
        });

        scope.map.on('mouseout', function(evt) {
          scope.$apply(function() {
              scope.lat = "";
              scope.lon = "";
            });
        });

        var group = null;
        var refreshPoints = function() {
          if (group) {
            group.clearLayers();
          } else {
            group = L.layerGroup([]);
          }

          var points = scope.msGeoAdapter.geoPoints();
          _.each(points, function(point) {
              if (point.type === 'marker') {
                group.addLayer(L.marker([point.lat, point.lng]));
              }
              if (point.type === 'circle') {
                group.addLayer(L.circle([point.lat, point.lng], point.rad * 1000));
              }
            });

          group.addTo(scope.map);
        };

        _.each(['msDocument.table', 'msGeoAdapter.showRows.length', 'msGeoAdapter.latCol',
          'msGeoAdapter.lngCol', 'msGeoAdapter.radCol'], function(prop) {
              scope.$watch(prop, refreshPoints);
            });
      }
    };
  });
<|endoftext|>


<commit_before>import hbs from 'htmlbars-inline-precompile';
import qs from 'qs';
import { render, getContext } from '@ember/test-helpers';
import { htmlSafe } from '@ember/string';
import { pluralize } from 'ember-inflector';

// This is a workaround for https://github.com/intercom/ember-href-to/issues/94
// We use href-to internally in cardstack-url. So if you want to generate a link
// in a rendering test, you need use this.
export function setupURLs(hooks) {
  hooks.beforeEach(function() {
    this.owner.lookup('router:main').setupRouter()
  })
}

export function findCard(type, id, format='isolated') {
  return getContext().owner.lookup('service:cardstackData').load(type, id, format);
}

export function getSpaceForCard(type, id) {
  return getContext().owner.lookup('service:store').findRecord('space', `/${pluralize(type)}/${id}`);
}

export function renderCard(type, id, format, options = {}) {
  return getSpaceForCard(type, id).then(space => {
    let context = getContext();
    let card = space.get('primaryCard');
    let params = space.get('params');
    context.set('card', card);
    context.set('format', format);
    context.set('params', params);

    if (options.width) {
      context.set('widthStyle', htmlSafe(`width: ${options.width}`));
      return render(hbs`

        {{cardstack-content event-isolated content=card format=format params=params }}

`);
    } else {
      return render(hbs`{{cardstack-content event-isolated content=card format=format params=params }}`);
    }
  });
}<commit_msg>remove unsued import<commit_after>import hbs from 'htmlbars-inline-precompile';
import { render, getContext } from '@ember/test-helpers';
import { htmlSafe } from '@ember/string';
import { pluralize } from 'ember-inflector';

// This is a workaround for https://github.com/intercom/ember-href-to/issues/94
// We use href-to internally in cardstack-url. So if you want to generate a link
// in a rendering test, you need use this.
export function setupURLs(hooks) {
  hooks.beforeEach(function() {
    this.owner.lookup('router:main').setupRouter()
  })
}

export function findCard(type, id, format='isolated') {
  return getContext().owner.lookup('service:cardstackData').load(type, id, format);
}

export function getSpaceForCard(type, id) {
  return getContext().owner.lookup('service:store').findRecord('space', `/${pluralize(type)}/${id}`);
}

export function renderCard(type, id, format, options = {}) {
  return getSpaceForCard(type, id).then(space => {
    let context = getContext();
    let card = space.get('primaryCard');
    let params = space.get('params');
    context.set('card', card);
    context.set('format', format);
    context.set('params', params);

    if (options.width) {
      context.set('widthStyle', htmlSafe(`width: ${options.width}`));
      return render(hbs`

        {{cardstack-content event-isolated content=card format=format params=params }}

`);
    } else {
      return render(hbs`{{cardstack-content event-isolated content=card format=format params=params }}`);
    }
  });
}<|endoftext|>


<commit_before>const models       = require('../../models');
const responseUtil = require('./responseUtil');
const middleware   = require('../middleware');
const { check, oneOf } = require('express-validator/check');

module.exports = function(app, baseUrl) {
  var apiUrl = baseUrl + '/events';

  /**

   */
  app.post(
    apiUrl,
    [
      middleware.authenticateDevice,
      middleware.getEventDetailById.optional(),
      oneOf([
        check("eventDetailId").exists(),
        check("type").exists(),
      ], "Either 'eventDetailId' or 'type' must be specified"),
    ],
    middleware.requestWrapper(async (request, response) => {

      var detailsId = request.body.eventDetailId
      if (!detailsId) {
        var existingMatchingDetail = await models.EventDetail.getMatching(request.body.type, request.body.details);
        if (existingMatchingDetail) {
          detailsId = existingMatchingDetail.id;
        }
        else {
          var newDetails = await models.EventDetail.create({
            type: request.body.type,
            details: request.body.details,
          });
          detailsId = newDetails.id;
        }
      }

      newEvent = await models.Event.create({
        DeviceId: request.device.id,
        EventDetailId: detailsId,
        eventDateTime: request.body.eventDateTime
      });

      return responseUtil.send(response, {
        statusCode: 200,
        success: true,
        messages: ['Added event.'],
        eventId: newEvent.id,
        eventDetailId: detailsId,
      });
    })
  );
};<commit_msg>Not can add multiple events at a time.<commit_after>const models       = require('../../models');
const responseUtil = require('./responseUtil');
const middleware   = require('../middleware');
const { check, oneOf } = require('express-validator/check');

module.exports = function(app, baseUrl) {
  var apiUrl = baseUrl + '/events';

  /**

   */
  app.post(
    apiUrl,
    [
      middleware.authenticateDevice,
      middleware.getEventDetailById.optional(),
      check("eventDateTimes", "List of times event happened is required.").exists(),
      oneOf([
        check("eventDetailId").exists(),
        check("type").exists(),
      ], "Either 'eventDetailId' or 'type' must be specified"),
    ],
    middleware.requestWrapper(async (request, response) => {

      var detailsId = request.body.eventDetailId
      if (!detailsId) {
        var existingMatchingDetail = await models.EventDetail.getMatching(request.body.type, request.body.details);
        if (existingMatchingDetail) {
          detailsId = existingMatchingDetail.id;
        }
        else {
          var newDetails = await models.EventDetail.create({
            type: request.body.type,
            details: request.body.details,
          });
          detailsId = newDetails.id;
        }
      }

      var eventList = [];
      var count = 0;

      request.body.eventDateTimes.forEach(function(time) {
        eventList.push({
          DeviceId: request.device.id,
          EventDetailId: detailsId,
          eventDateTime: time,
        });
        count++;
      });

      try {
        await models.Event.bulkCreate(eventList);
      } catch (exception) {
        return responseUtil.send(response, {
          statusCode: 500,
          success: false,
          messages: ["Failed to record events.", exception.message],
        });
      }

      return responseUtil.send(response, {
        statusCode: 200,
        success: true,
        messages: ['Added events.'],
        eventsAdded: count,
        eventDetailId: detailsId,
      });
    })
  );
};<|endoftext|>


<commit_before>// Sample view

enyo.kind({
    name: "moon.SearchResultImageItem",
    classes: "moon-search-result-item",
    spotlight: true,
    published: {
        option: {
            src: "",
            caption: ""
        }
    },
    handlers: {
        onSpotlightFocused: "focused",
        onSpotlightBlur: "released"
    },
    components: [
        {name: "caption", classes: "moon-search-result-item-text"}
    ],
    create: function() {
        this.inherited(arguments);
        this.optionChanged();
    },
    getCaption: function() {
        return this.$.caption;
    },
    optionChanged: function(inOld) {
        this.applyStyle("background-image", 'url(' + this.option.src + ')');
        this.$.caption.setContent(this.option.caption);
    },
    focused: function() {
        this.$.caption.addClass("spotlight");
        return true;
    },
    released: function() {
        this.$.caption.removeClass("spotlight");
        return true;
    }
});

enyo.kind({
    name: "moon.sample.search.RecentSearchHalfSample",
    kind: "moon.Panel",
    titleAbove: "02",
    title: "SEARCH",
    titleBelow: "",
    headerComponents: [
        /* Fixme: moon.Panel needs interface to change Header, Body, Tools area size */
        {kind: "moon.InputDecorator", components: [
            {style: "width: 500px", components: [
                {layoutKind: 'FittableColumnsLayout', components: [
                    {kind: "moon.Input", placeholder: "Search term", fit: true, onchange: "inputChanged"},
                    {kind: "Image", src: "../../samples/assets/search-input-search.png", classes: "moon-search-result-image"}
                ]}
            ]}
        ]}
    ],
    components: [
        {
            /* Fixme: enyo.DataList should be changed to moon.DataGrid to support scroll */
            kind: "moon.DataList",
            name: "resultInfo",
            components: [
                {
                    bindings: [
                        {from: ".model.option", to: ".$.searchResultImageItem.option"}
                    ],
                    components: [{
                        name: "searchResultImageItem",
                        kind: "moon.SearchResultImageItem",
                        ontap: "changeName"
                    }]
                }
            ]
        }
    ],
    bindings: [
        {from: ".controller.result", to: ".$.resultInfo.controller"}
    ]
});

// Sample model

enyo.ready(function(){
    var sampleModel = new enyo.Model({
        result: new enyo.Collection([
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}},
            {option: {src: "../assets/default-movie.png", caption: "Person name"}}
        ])
    });

//  Application to render sample

    new enyo.Application({
        view: {
            classes: "enyo-unselectable moon",
            components: [
                {
                    kind: "moon.sample.search.RecentSearchHalfSample",
                    controller: ".app.controllers.searchController",
                    classes: "enyo-fit"
                }
            ]
        },
        controllers: [
            {
                name: "searchController",
                kind: "enyo.ModelController",
                model: sampleModel,
                changeName: function(inSender, inEvent) {
                    inSender.getCaption().setContent("Selected");
                }
            }
        ]
    });
});<commit_msg>GF-53116: Sample fix, use DataGridList instead of DataList, fix up cruft. DCO-1.1-Signed-Off-By: Kevin Schaaf <kevin.schaaf@lge.com><commit_after>enyo.kind({
    name: "moon.sample.search.RecentSearchHalfSample",
    kind: "moon.Panel",
    titleAbove: "02",
    title: "SEARCH",
    titleBelow: "",
    events: {
        onChangeName:""
    },
    headerComponents: [
        /* Fixme: moon.Panel needs interface to change Header, Body, Tools area size */
        {kind: "moon.InputDecorator", components: [
            {style: "width: 500px", components: [
                {layoutKind: 'FittableColumnsLayout', components: [
                    {kind: "moon.Input", placeholder: "Search term", fit: true, onchange: "inputChanged"},
                    {kind: "Image", src: "../../samples/assets/search-input-search.png", classes: "moon-search-result-image"}
                ]}
            ]}
        ]}
    ],
    components: [
        {
            /* Fixme: enyo.DataList should be changed to moon.DataGrid to support scroll */
            kind: "moon.DataGridList",
            name: "resultInfo",
            spacing: 20,
            minWidth: 250,
            minHeight: 200,
            components: [
                {
                    kind: "moon.GridListImageItem",
                    ontap: "changeName",
                    bindings: [
                        {from: ".model.caption", to: ".caption"},
                        {from: ".model.src", to: ".source"}
                    ]
                }
            ]
        }
    ],
    bindings: [
        {from: ".controller.result", to: ".$.resultInfo.collection"}
    ],
    changeName: function(inSender, inEvent) {
        this.doChangeName({index:inEvent.index});
    }
});

// Sample model

enyo.ready(function(){
    var sampleModel = new enyo.Model({
        result: new enyo.Collection([
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"},
            {src: "../assets/default-movie.png", caption: "Person name"}
        ])
    });

//  Application to render sample

    new enyo.Application({
        view: {
            classes: "enyo-unselectable moon",
            components: [
                {name:"searchView", kind: "moon.sample.search.RecentSearchHalfSample", classes:"enyo-fit"}
            ]
        },
        components: [
            {
                name: "searchController",
                kind: "enyo.ModelController",
                model: sampleModel
            }
        ],
        bindings: [
            {from:".$.searchController", to:".view.$.searchView.controller"}
        ],
        handlers: {
            onChangeName: "changeName"
        },
        changeName: function(inSender, inEvent) {
            this.$.searchController.get("model").get("result").at(inEvent.index).set("caption", "New name set");
        }
    });
});<|endoftext|>


<commit_before>module.exports = function(server) {

  // Create an API namespace, so that the root does not
  // have to be repeated for each end point.
  server.namespace('/api', function() {

    server.get('/contests', function(req, res) {
      var contests = { "contest": [
        {id: 1, name: "Goodbye 2013", starts: "4pm, 31st January 2014", duration: "75 minutes", already_registered: "32"},
        {id: 2, name: "Welcome 2014", starts: "4pm, 7th January 2014", duration: "75 minutes", already_registered: "46"},
        {id: 3, name: "Contest 101", starts: "4pm, 14th January 2014", duration: "75 minutes", already_registered: "3"}
      ]};
      res.send(contests);
    });

  });

};
<commit_msg>Fix bug with stub-api. Add /contests/:id<commit_after>module.exports = function(server) {

  // Create an API namespace, so that the root does not
  // have to be repeated for each end point.
  server.namespace('/api', function() {

    var contests = { "contests": [
      {id: 1, name: "Goodbye 2013", starts: "4pm, 31st January 2014", duration: "75 minutes", already_registered: "32"},
      {id: 2, name: "Welcome 2014", starts: "4pm, 7th January 2014", duration: "75 minutes", already_registered: "46"},
      {id: 3, name: "Contest 101", starts: "4pm, 14th January 2014", duration: "75 minutes", already_registered: "3"}
    ]};

    server.get('/contests', function(req, res) {
      res.send(contests);
    });

    server.get('/contests/:id', function (req, res) {
      var result = contests.contest[req.params.id-1];
      res.send({"contest": result });
    })

  });

};
<|endoftext|>