<commit_before>/* global NAF */
var ReservedDataType = { Update: 'u', UpdateMulti: 'um', Remove: 'r' };

class NetworkConnection {

  constructor(networkEntities) {
    this.entities = networkEntities;
    this.setupDefaultDataSubscriptions();

    this.connectedClients = {};
    this.activeDataChannels = {};
  }

  setNetworkAdapter(adapter) {
    this.adapter = adapter;
  }

  setupDefaultDataSubscriptions() {
    this.dataChannelSubs = {};

    this.dataChannelSubs[ReservedDataType.Update]
        = this.entities.updateEntity.bind(this.entities);

    this.dataChannelSubs[ReservedDataType.UpdateMulti]
        = this.entities.updateEntityMulti.bind(this.entities);

    this.dataChannelSubs[ReservedDataType.Remove]
        = this.entities.removeRemoteEntity.bind(this.entities);
  }

  connect(serverUrl, appName, roomName, enableAudio = false, enableVideo = false) {
    NAF.app = appName;
    NAF.room = roomName;

    this.adapter.setServerUrl(serverUrl);
    this.adapter.setApp(appName);
    this.adapter.setRoom(roomName);

    var webrtcOptions = {
      audio: enableAudio,
      video: enableAudio,
      datachannel: true
    };
    this.adapter.setWebRtcOptions(webrtcOptions);

    this.adapter.setServerConnectListeners(
      this.connectSuccess.bind(this),
      this.connectFailure.bind(this)
    );
    this.adapter.setDataChannelListeners(
      this.dataChannelOpen.bind(this),
      this.dataChannelClosed.bind(this),
      this.receivedData.bind(this)
    );
    this.adapter.setRoomOccupantListener(this.occupantsReceived.bind(this));

    return this.adapter.connect();
  }

  onConnect(callback) {
    this.onConnectCallback = callback;

    if (this.isConnected()) {
      callback();
    } else {
      document.body.addEventListener('connected', callback, false);
    }
  }

  connectSuccess(clientId) {
    NAF.log.write('Networked-Aframe Client ID:', clientId);
    NAF.clientId = clientId;

    var evt = new CustomEvent('connected', {'detail': { clientId: clientId }});
    document.body.dispatchEvent(evt);
  }

  connectFailure(errorCode, message) {
    NAF.log.error(errorCode, "failure to connect");
  }

  occupantsReceived(occupantList) {
    var prevConnectedClients = Object.assign({}, this.connectedClients);
    this.connectedClients = occupantList;
    this.checkForDisconnectingClients(prevConnectedClients, occupantList);
    this.checkForConnectingClients(occupantList);
  }

  checkForDisconnectingClients(oldOccupantList, newOccupantList) {
    for (var id in oldOccupantList) {
      var clientFound = newOccupantList[id];
      if (!clientFound) {
        NAF.log.write('Closing stream to ', id);
        this.adapter.closeStreamConnection(id);
      }
    }
  }

  // Some adapters will handle this internally
  checkForConnectingClients(occupantList) {
    for (var id in occupantList) {
      var startConnection = this.isNewClient(id) && this.adapter.shouldStartConnectionTo(occupantList[id]);
      if (startConnection) {
        NAF.log.write('Opening datachannel to ', id);
        this.adapter.startStreamConnection(id);
      }
    }
  }

  getConnectedClients() {
    return this.connectedClients;
  }

  isConnected() {
    return !!NAF.clientId;
  }

  isMineAndConnected(clientId) {
    return this.isConnected() && NAF.clientId === clientId;
  }

  isNewClient(clientId) {
    return !this.isConnectedTo(clientId);
  }

  isConnectedTo(clientId) {
    return this.adapter.getConnectStatus(clientId) === NAF.adapters.IS_CONNECTED;
  }

  dataChannelOpen(clientId) {
    NAF.log.write('Opened data channel from ' + clientId);
    this.activeDataChannels[clientId] = true;
    this.entities.completeSync(clientId, true);

    var evt = new CustomEvent('clientConnected', {detail: {clientId: clientId}});
    document.body.dispatchEvent(evt);
  }

  dataChannelClosed(clientId) {
    NAF.log.write('Closed data channel from ' + clientId);
    this.activeDataChannels[clientId] = false;
    this.entities.removeEntitiesOfClient(clientId);

    var evt = new CustomEvent('clientDisconnected', {detail: {clientId: clientId}});
    document.body.dispatchEvent(evt);
  }

  hasActiveDataChannel(clientId) {
    return !!this.activeDataChannels[clientId];
  }

  broadcastData(dataType, data) {
    this.adapter.broadcastData(dataType, data);
  }

  broadcastDataGuaranteed(dataType, data) {
    this.adapter.broadcastDataGuaranteed(dataType, data);
  }

  sendData(toClientId, dataType, data, guaranteed) {
    if (this.hasActiveDataChannel(toClientId)) {
      if (guaranteed) {
        this.adapter.sendDataGuaranteed(toClientId, dataType, data);
      } else {
        this.adapter.sendData(toClientId, dataType, data);
      }
    } else {
      // console.error("NOT-CONNECTED", "not connected to " + toClient);
    }
  }

  sendDataGuaranteed(toClientId, dataType, data) {
    this.sendData(toClientId, dataType, data, true);
  }

  subscribeToDataChannel(dataType, callback) {
    if (this.isReservedDataType(dataType)) {
      NAF.log.error('NetworkConnection@subscribeToDataChannel: ' + dataType + ' is a reserved dataType. Choose another');
      return;
    }
    this.dataChannelSubs[dataType] = callback;
  }

  unsubscribeToDataChannel(dataType) {
    if (this.isReservedDataType(dataType)) {
      NAF.log.error('NetworkConnection@unsubscribeToDataChannel: ' + dataType + ' is a reserved dataType. Choose another');
      return;
    }
    delete this.dataChannelSubs[dataType];
  }

  isReservedDataType(dataType) {
    return dataType == ReservedDataType.Update
        || dataType == ReservedDataType.Remove;
  }

  receivedData(fromClientId, dataType, data, source) {
    if (this.dataChannelSubs[dataType]) {
      this.dataChannelSubs[dataType](fromClientId, dataType, data, source);
    } else {
      NAF.log.write('NetworkConnection@receivedData: ' + dataType + ' has not been subscribed to yet. Call subscribeToDataChannel()');
    }
  }

  getServerTime() {
    return this.adapter.getServerTime();
  }

  disconnect() {
    this.entities.removeRemoteEntities();

    if (this.adapter) {
      this.adapter.disconnect();
    }

    NAF.app = '';
    NAF.room = '';
    NAF.clientId = '';
    this.connectedClients = {};
    this.activeDataChannels = {};
    this.adapter = null;

    this.setupDefaultDataSubscriptions();

    document.body.removeEventListener('connected', this.onConnectCallback);
  }
}

module.exports = NetworkConnection;
<commit_msg>fix NetworkConnection enableVideo<commit_after>/* global NAF */
var ReservedDataType = { Update: 'u', UpdateMulti: 'um', Remove: 'r' };

class NetworkConnection {

  constructor(networkEntities) {
    this.entities = networkEntities;
    this.setupDefaultDataSubscriptions();

    this.connectedClients = {};
    this.activeDataChannels = {};
  }

  setNetworkAdapter(adapter) {
    this.adapter = adapter;
  }

  setupDefaultDataSubscriptions() {
    this.dataChannelSubs = {};

    this.dataChannelSubs[ReservedDataType.Update]
        = this.entities.updateEntity.bind(this.entities);

    this.dataChannelSubs[ReservedDataType.UpdateMulti]
        = this.entities.updateEntityMulti.bind(this.entities);

    this.dataChannelSubs[ReservedDataType.Remove]
        = this.entities.removeRemoteEntity.bind(this.entities);
  }

  connect(serverUrl, appName, roomName, enableAudio = false, enableVideo = false) {
    NAF.app = appName;
    NAF.room = roomName;

    this.adapter.setServerUrl(serverUrl);
    this.adapter.setApp(appName);
    this.adapter.setRoom(roomName);

    var webrtcOptions = {
      audio: enableAudio,
      video: enableVideo,
      datachannel: true
    };
    this.adapter.setWebRtcOptions(webrtcOptions);

    this.adapter.setServerConnectListeners(
      this.connectSuccess.bind(this),
      this.connectFailure.bind(this)
    );
    this.adapter.setDataChannelListeners(
      this.dataChannelOpen.bind(this),
      this.dataChannelClosed.bind(this),
      this.receivedData.bind(this)
    );
    this.adapter.setRoomOccupantListener(this.occupantsReceived.bind(this));

    return this.adapter.connect();
  }

  onConnect(callback) {
    this.onConnectCallback = callback;

    if (this.isConnected()) {
      callback();
    } else {
      document.body.addEventListener('connected', callback, false);
    }
  }

  connectSuccess(clientId) {
    NAF.log.write('Networked-Aframe Client ID:', clientId);
    NAF.clientId = clientId;

    var evt = new CustomEvent('connected', {'detail': { clientId: clientId }});
    document.body.dispatchEvent(evt);
  }

  connectFailure(errorCode, message) {
    NAF.log.error(errorCode, "failure to connect");
  }

  occupantsReceived(occupantList) {
    var prevConnectedClients = Object.assign({}, this.connectedClients);
    this.connectedClients = occupantList;
    this.checkForDisconnectingClients(prevConnectedClients, occupantList);
    this.checkForConnectingClients(occupantList);
  }

  checkForDisconnectingClients(oldOccupantList, newOccupantList) {
    for (var id in oldOccupantList) {
      var clientFound = newOccupantList[id];
      if (!clientFound) {
        NAF.log.write('Closing stream to ', id);
        this.adapter.closeStreamConnection(id);
      }
    }
  }

  // Some adapters will handle this internally
  checkForConnectingClients(occupantList) {
    for (var id in occupantList) {
      var startConnection = this.isNewClient(id) && this.adapter.shouldStartConnectionTo(occupantList[id]);
      if (startConnection) {
        NAF.log.write('Opening datachannel to ', id);
        this.adapter.startStreamConnection(id);
      }
    }
  }

  getConnectedClients() {
    return this.connectedClients;
  }

  isConnected() {
    return !!NAF.clientId;
  }

  isMineAndConnected(clientId) {
    return this.isConnected() && NAF.clientId === clientId;
  }

  isNewClient(clientId) {
    return !this.isConnectedTo(clientId);
  }

  isConnectedTo(clientId) {
    return this.adapter.getConnectStatus(clientId) === NAF.adapters.IS_CONNECTED;
  }

  dataChannelOpen(clientId) {
    NAF.log.write('Opened data channel from ' + clientId);
    this.activeDataChannels[clientId] = true;
    this.entities.completeSync(clientId, true);

    var evt = new CustomEvent('clientConnected', {detail: {clientId: clientId}});
    document.body.dispatchEvent(evt);
  }

  dataChannelClosed(clientId) {
    NAF.log.write('Closed data channel from ' + clientId);
    this.activeDataChannels[clientId] = false;
    this.entities.removeEntitiesOfClient(clientId);

    var evt = new CustomEvent('clientDisconnected', {detail: {clientId: clientId}});
    document.body.dispatchEvent(evt);
  }

  hasActiveDataChannel(clientId) {
    return !!this.activeDataChannels[clientId];
  }

  broadcastData(dataType, data) {
    this.adapter.broadcastData(dataType, data);
  }

  broadcastDataGuaranteed(dataType, data) {
    this.adapter.broadcastDataGuaranteed(dataType, data);
  }

  sendData(toClientId, dataType, data, guaranteed) {
    if (this.hasActiveDataChannel(toClientId)) {
      if (guaranteed) {
        this.adapter.sendDataGuaranteed(toClientId, dataType, data);
      } else {
        this.adapter.sendData(toClientId, dataType, data);
      }
    } else {
      // console.error("NOT-CONNECTED", "not connected to " + toClient);
    }
  }

  sendDataGuaranteed(toClientId, dataType, data) {
    this.sendData(toClientId, dataType, data, true);
  }

  subscribeToDataChannel(dataType, callback) {
    if (this.isReservedDataType(dataType)) {
      NAF.log.error('NetworkConnection@subscribeToDataChannel: ' + dataType + ' is a reserved dataType. Choose another');
      return;
    }
    this.dataChannelSubs[dataType] = callback;
  }

  unsubscribeToDataChannel(dataType) {
    if (this.isReservedDataType(dataType)) {
      NAF.log.error('NetworkConnection@unsubscribeToDataChannel: ' + dataType + ' is a reserved dataType. Choose another');
      return;
    }
    delete this.dataChannelSubs[dataType];
  }

  isReservedDataType(dataType) {
    return dataType == ReservedDataType.Update
        || dataType == ReservedDataType.Remove;
  }

  receivedData(fromClientId, dataType, data, source) {
    if (this.dataChannelSubs[dataType]) {
      this.dataChannelSubs[dataType](fromClientId, dataType, data, source);
    } else {
      NAF.log.write('NetworkConnection@receivedData: ' + dataType + ' has not been subscribed to yet. Call subscribeToDataChannel()');
    }
  }

  getServerTime() {
    return this.adapter.getServerTime();
  }

  disconnect() {
    this.entities.removeRemoteEntities();

    if (this.adapter) {
      this.adapter.disconnect();
    }

    NAF.app = '';
    NAF.room = '';
    NAF.clientId = '';
    this.connectedClients = {};
    this.activeDataChannels = {};
    this.adapter = null;

    this.setupDefaultDataSubscriptions();

    document.body.removeEventListener('connected', this.onConnectCallback);
  }
}

module.exports = NetworkConnection;
<|endoftext|>


<commit_before>var assert   = require('assert')
var Mod      = require('../')
var Moment   = require('moment');
var mongoose = require('mongoose')

var MomentSchema;
var MongooseMoment;
var Schema   = mongoose.Schema;

describe('MongooseMoment', function(){
	before(function(){
		MomentSchema = Mod(mongoose);
		MongooseMoment = mongoose.Types.Moment;
	});

	it('has a version', function(){
		assert.equal(require('../package').version, Mod.version);
	});

	it('is a function', function(){
		assert.equal('function', typeof MomentSchema);
	});

	it('extends mongoose.Schema.Types', function(){
		assert.ok(Schema.Types.Moment);
		assert.equal(MomentSchema, Schema.Types.Moment);
	});

	it('extends mongoose.Types', function(){
		assert.ok(mongoose.Types.Moment);
	});

	/** The Moment constructor was created as an anonymous function, so Moment.name = ''. This means you must use a String to set the field type in the schema, instead of being able to use the constructor.
	 * Fixing this would require a moment.js code change.
	*/
	it('can be used in schemas', function(){
		var s = new Schema({ m: 'Moment' });
		var m = s.path('m')
		assert.ok(m instanceof mongoose.SchemaType);
		assert.equal('function', typeof m.get);
	});

	describe('integration', function(){
		var db, S, schema, id;

		before(function(done){
			db = mongoose.createConnection('localhost', 'mongoose_moment')
			db.once('open', function () {
        done();
			});
		});

		after(function(done){
			db.db.dropDatabase(function () {
				db.close(done);
			});
		});

    it('create model', function(done){
      schema = new Schema({
          m: {type: 'Moment', default: Moment("12-25-1995", "MM-DD-YYYY")}
        , docs: [{ m: 'Moment' }]
      });
      S = db.model('MomentModel', schema);
      done();
    });

		describe('casts', function(){
      it('default', function(done){
        var s = new S({});//note no value for m is
        assert.ok(Moment.isMoment(s.m), 'isMoment('+s.m+') = false');
        assert.ok(new Moment("12-25-1995", "MM-DD-YYYY").isSame(s.m), "correct value");
        done();
      });

			it('null', function(done){
				var s = new S({ m: null });
				assert.equal(s.m, null);
				done();
			});

			it('dates', function(done){
				var s = new S({ m: '2013-02-08' });
				assert.ok(Moment.isMoment(s.m), 'isMoment('+s.m+') = false');
				assert.ok(new Moment('2013-02-08').isSame(s.m), "correct value");
				done();
			});
		});

		describe('with db', function(){
			var id;
			// mongoose.set('debug', true);

			it('save', function(done){

				var s = new S({
						m: new Moment("12-25-1995", "MM-DD-YYYY")
					, docs: [null, { m: new Moment({years: 2010, months: 3, days: 5, hours: 15, minutes: 10, seconds: 3, milliseconds: 123}) } ]
				});
				s.save(function (err) {
					assert.ifError(err);
					id = s.id;
					done();
				})
			});

			it('findById', function(done){
				S.findById(id, function (err, doc) {
					assert.ifError(err);
					assert.ok(Moment.isMoment(doc.m));
					assert.ok(doc.m.isSame(new Moment("12-25-1995", "MM-DD-YYYY")));
					assert.equal(null, doc.docs[0]);
					assert.ok(Moment.isMoment(doc.docs[1].m));
					assert.ok(doc.docs[1].m.isSame(new Moment({years: 2010, months: 3, days: 5, hours: 15, minutes: 10, seconds: 3, milliseconds: 123})));
					done();
				});
			});

			it('findOne matching null', function(done){
				S.create({ m: null }, function (err, doc_) {
					assert.ifError(err);
					S.findOne({ m: null }, function (err, doc) {
						assert.ifError(err);
						assert.equal(doc.id, doc_.id, 'id mismatch');
						done();
					});
				});
			});

			it('find with instanceof Moment', function(done){
				S.find({ 'docs.m': new Moment({years: 2010, months: 3, days: 5, hours: 15, minutes: 10, seconds: 3, milliseconds: 123}).valueOf() }, function (err, docs) {
					assert.ifError(err);
					assert.equal(1, docs.length, 'expected 1 result, got '+docs.length);
					var doc = docs[0];
					assert.equal(id, doc.id, 'id mismatch');
					done();
				});
			});

			it('find with string', function(done){
				S.find({ 'docs.m': new Moment('2010-04-05T15:10:03.123').valueOf() }, function (err, docs) {
					assert.ifError(err);
					assert.equal(1, docs.length, 'expected 1 result, got '+docs.length);
					var doc = docs[0];
					assert.equal(id, doc.id);
					done();
				});
			});

			it('find with string $in', function(done){
				S.find({ 'docs.m': { $in: [new Moment('2010-04-05T15:10:03.123').valueOf(), new Moment('2010-04-06T15:10:03.123').valueOf(), new Moment('2010-04-07T15:10:03.123').valueOf()] }}, function (err, docs) {
					assert.ifError(err);
					assert.equal(1, docs.length);
					var doc = docs[0];
					assert.equal(id, doc.id);
					done();
				});
			});

			it('find with between', function(done) {
				S.where('docs.m').between(new Moment('2010-04-05'), new Moment('2010-04-07') ).exec(function(err, docs) {
					assert.ifError(err);
					assert.equal(1, docs.length);
					var doc = docs[0];
					assert.equal(id, doc.id);
					done();
				});
			});

			describe('is updateable', function(){
				it('in general', function(done){
					S.findById(id, function (err, doc) {
						assert.ifError(err);

						// doc.m = new Moment("12-25-1995", "MM-DD-YYYY");
						// assert.ok(!doc.isModified('m'));

						// doc.m = "Mon Dec 25 1995 00:00:00 GMT-0800";
						// assert.ok(!doc.isModified('m'));

						doc.m = new Moment("12-26-1995", "MM-DD-YYYY");
						doc.save(function (err) {
							assert.ifError(err);
							S.findById(id, function (err, doc) {
								assert.ifError(err);
								assert.ok(doc.m.isSame(new Moment("12-26-1995", "MM-DD-YYYY")));
								done();
							});
						});
					});
				});
			});

		});
	});
});
<commit_msg>tests for required properties<commit_after>var assert   = require('assert')
var Mod      = require('../')
var Moment   = require('moment');
var mongoose = require('mongoose')

var MomentSchema;
var MongooseMoment;
var Schema   = mongoose.Schema;

describe('MongooseMoment', function(){
	before(function(){
		MomentSchema = Mod(mongoose);
		MongooseMoment = mongoose.Types.Moment;
	});

	it('has a version', function(){
		assert.equal(require('../package').version, Mod.version);
	});

	it('is a function', function(){
		assert.equal('function', typeof MomentSchema);
	});

	it('extends mongoose.Schema.Types', function(){
		assert.ok(Schema.Types.Moment);
		assert.equal(MomentSchema, Schema.Types.Moment);
	});

	it('extends mongoose.Types', function(){
		assert.ok(mongoose.Types.Moment);
	});

	/** The Moment constructor was created as an anonymous function, so Moment.name = ''. This means you must use a String to set the field type in the schema, instead of being able to use the constructor.
	 * Fixing this would require a moment.js code change.
	*/
	it('can be used in schemas', function(){
		var s = new Schema({ m: 'Moment' });
		var m = s.path('m')
		assert.ok(m instanceof mongoose.SchemaType);
		assert.equal('function', typeof m.get);
	});

	describe('integration', function(){
		var db, S, R, N, schema, id;

		before(function(done){
			db = mongoose.createConnection('localhost', 'mongoose_moment')
			db.once('open', function () {
        done();
			});
		});

		after(function(done){
			db.db.dropDatabase(function () {
				db.close(done);
			});
		});

    it('create model', function(done){
      schema = new Schema({
          m: {type: 'Moment', default: Moment("12-25-1995", "MM-DD-YYYY")},
          docs: [{ m: 'Moment' }]
      });
      S = db.model('MomentModel', schema);
      done();
    });

    it('create model with required moment property', function(done){
      schema = new Schema({
          m: {type: 'Moment', required: true},
          docs: [{ m: 'Moment' }]
      });
      R = db.model('MomentModelRequired', schema);
      done();
    });

    it('create model with normal moment property and required moment property', function(done){
      schema = new Schema({
          n: 'Moment',
          m: {type: 'Moment', required: true},
          docs: [{ m: 'Moment' }]
      });
      N = db.model('MomentModelNormalRequired', schema);
      done();
    });

		describe('casts', function(){
      it('default', function(done){
        var s = new S({});//note no value for m is
        assert.ok(Moment.isMoment(s.m), 'isMoment('+s.m+') = false');
        assert.ok(new Moment("12-25-1995", "MM-DD-YYYY").isSame(s.m), "correct value");
        done();
      });

			it('null', function(done){
				var s = new S({ m: null });
				assert.equal(s.m, null);
				done();
			});

			it('dates', function(done){
				var s = new S({ m: '2013-02-08' });
				assert.ok(Moment.isMoment(s.m), 'isMoment('+s.m+') = false');
				assert.ok(new Moment('2013-02-08').isSame(s.m), "correct value");
				done();
			});
<<<<<<< HEAD
=======

			it('non-castables produce _saveErrors', function(done){
				var schema = new Schema({ date: 'Moment' }, { strict: 'throw' });
				var M = db.model('throws', schema);
				var m = new M({ date: "not a real date" });
				m.save(function (err) {
					console.log( err );
					assert.ok(err, 'error expected');
					assert.equal('moment', err.type, 'wrong type');
					assert.equal('CastError', err.name, 'wrong name');
					done();
				});
			});
>>>>>>> 32f45c3c0cf9eeeeea264e5e1baffc12060dc2c9
		});

		describe('with db', function(){
			var id, r_id, n_id;
			// mongoose.set('debug', true);

			it('save', function(done){

				var s = new S({
						m: new Moment("12-25-1995", "MM-DD-YYYY")
					, docs: [null, { m: new Moment({years: 2010, months: 3, days: 5, hours: 15, minutes: 10, seconds: 3, milliseconds: 123}) } ]
				});
				s.save(function (err) {
					assert.ifError(err);
					id = s.id;
					done();
				})
			});

      it('save instance of model with required property', function(done){

				var r = new R({
						m: new Moment("12-25-1995", "MM-DD-YYYY")
					, docs: [null, { m: new Moment({years: 2010, months: 3, days: 5, hours: 15, minutes: 10, seconds: 3, milliseconds: 123}) } ]
				});
				r.save(function (err) {
					assert.ifError(err);
					r_id = r.id;
					done();
				})
			});

      it('save instance of model with normal property and required', function(done){

				var n = new N({
          m: new Moment("12-25-1995", "MM-DD-YYYY"),
          n: new Moment("12-25-1995", "MM-DD-YYYY"),
					docs: [null, { m: new Moment({years: 2010, months: 3, days: 5, hours: 15, minutes: 10, seconds: 3, milliseconds: 123}) } ]
				});
				n.save(function (err) {
					assert.ifError(err);
					n_id = n.id;
					done();
				})
			});

			it('findById', function(done){
				S.findById(id, function (err, doc) {
					assert.ifError(err);
					assert.ok(Moment.isMoment(doc.m));
					assert.ok(doc.m.isSame(new Moment("12-25-1995", "MM-DD-YYYY")));
					assert.equal(null, doc.docs[0]);
					assert.ok(Moment.isMoment(doc.docs[1].m));
					assert.ok(doc.docs[1].m.isSame(new Moment({years: 2010, months: 3, days: 5, hours: 15, minutes: 10, seconds: 3, milliseconds: 123})));
					done();
				});
			});

			it('findOne matching null', function(done){
				S.create({ m: null }, function (err, doc_) {
					assert.ifError(err);
					S.findOne({ m: null }, function (err, doc) {
						assert.ifError(err);
						assert.equal(doc.id, doc_.id, 'id mismatch');
						done();
					});
				});
			});

			it('find with instanceof Moment', function(done){
				S.find({ 'docs.m': new Moment({years: 2010, months: 3, days: 5, hours: 15, minutes: 10, seconds: 3, milliseconds: 123}).valueOf() }, function (err, docs) {
					assert.ifError(err);
					assert.equal(1, docs.length, 'expected 1 result, got '+docs.length);
					var doc = docs[0];
					assert.equal(id, doc.id, 'id mismatch');
					done();
				});
			});

			it('find with string', function(done){
				S.find({ 'docs.m': new Moment('2010-04-05T15:10:03.123').valueOf() }, function (err, docs) {
					assert.ifError(err);
					assert.equal(1, docs.length, 'expected 1 result, got '+docs.length);
					var doc = docs[0];
					assert.equal(id, doc.id);
					done();
				});
			});

			it('find with string $in', function(done){
				S.find({ 'docs.m': { $in: [new Moment('2010-04-05T15:10:03.123').valueOf(), new Moment('2010-04-06T15:10:03.123').valueOf(), new Moment('2010-04-07T15:10:03.123').valueOf()] }}, function (err, docs) {
					assert.ifError(err);
					assert.equal(1, docs.length);
					var doc = docs[0];
					assert.equal(id, doc.id);
					done();
				});
			});

			it('find with between', function(done) {
				S.where('docs.m').between(new Moment('2010-04-05'), new Moment('2010-04-07') ).exec(function(err, docs) {
					assert.ifError(err);
					assert.equal(1, docs.length);
					var doc = docs[0];
					assert.equal(id, doc.id);
					done();
				});
			});

			describe('is updateable', function(){
        it('in general', function(done){
					S.findById(id, function (err, doc) {
						assert.ifError(err);

						// doc.m = new Moment("12-25-1995", "MM-DD-YYYY");
						// assert.ok(!doc.isModified('m'));

						// doc.m = "Mon Dec 25 1995 00:00:00 GMT-0800";
						// assert.ok(!doc.isModified('m'));

						doc.m = new Moment("12-26-1995", "MM-DD-YYYY");
						doc.save(function (err) {
							assert.ifError(err);
							S.findById(id, function (err, doc) {
								assert.ifError(err);
								assert.ok(doc.m.isSame(new Moment("12-26-1995", "MM-DD-YYYY")));
								done();
							});
						});
					});
				});
        it('with required property', function(done){
					R.findById(r_id, function (err, doc) {
						assert.ifError(err);

						doc.m = new Moment("12-26-1995", "MM-DD-YYYY");
						doc.save(function (err) {
							assert.ifError(err);
							R.findById(r_id, function (err, doc) {
								assert.ifError(err);
								assert.ok(doc.m.isSame(new Moment("12-26-1995", "MM-DD-YYYY")));
								done();
							});
						});
					});
				});
        it('with normal property and required property', function(done){
					N.findById(n_id, function (err, doc) {
						assert.ifError(err);

            console.log(JSON.stringify(doc));
						doc.n = new Moment("12-26-1995", "MM-DD-YYYY");
						doc.save(function (err) {
							assert.ifError(err);
							N.findById(n_id, function (err, doc) {
								assert.ifError(err);
								assert.ok(doc.n.isSame(new Moment("12-26-1995", "MM-DD-YYYY")));
								done();
							});
						});
					});
				});
			});

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


<commit_before>'use strict';

const Lab = require('lab');
const Code = require('code');
const Joi = require('joi');
const Hapi = require('hapi');
const HapiCsv = require('../lib/index');

const lab = exports.lab = Lab.script();
const describe = lab.experiment;
const it = lab.it;
const before = lab.before;
const after = lab.after;
const expect = Code.expect;

describe('Hapi csv', () => {

    describe('Basics', () => {

        it('Registers', (done) => {

            const server = new Hapi.Server();
            server.connection();

            server.register({
                register: HapiCsv
            }, (err) => {

                expect(err, 'error').to.not.exists();

                return done();
            });
        });
    });

    describe('Basic convertions', () => {

        let simpleServer;
        const user = {
            first_name: 'firstName',
            last_name: 'lastName',
            age: 25
        };
        const userCSV = `first_name,last_name,age,\n"firstName","lastName","25",`;
        const testResponseSchema = Joi.object().keys({
            first_name: Joi.string(),
            last_name: Joi.string(),
            age: Joi.number()
        });

        before((done) => {

            simpleServer = new Hapi.Server();
            simpleServer.connection();

            simpleServer.route([{
                method: 'GET',
                path: '/user',
                config: {
                    handler: function (request, reply) {

                        return reply(user);
                    },
                    response: {
                        schema: testResponseSchema
                    }
                }
            }, {
                method: 'GET',
                path: '/userWithoutSchema',
                config: {
                    handler: function (request, reply) {

                        return reply(user);
                    }
                }
            }]);

            return simpleServer.register({
                register: HapiCsv
            }, (err) => {

                expect(err, 'error').to.not.exist();

                // initialize is needed for hapi-csv route mapping to trigger
                return simpleServer.initialize((err) => {

                    expect(err, 'error').to.not.exist();

                    return done();
                });
            });
        });

        after((done) => {

            return simpleServer.stop(done);
        });

        it('Converts with text/csv header', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/user',
                headers: {
                    'Accept': 'text/csv'
                }
            }, (res) => {

                expect(res.result).to.equal(userCSV);
                expect(res.headers['content-type']).to.equal('text/csv; charset=utf-8');

                return done();
            });
        });

        it('Converts with application/csv header', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/user',
                headers: {
                    'Accept': 'application/csv'
                }
            }, (res) => {

                expect(res.result).to.equal(userCSV);
                expect(res.headers['content-type']).to.equal('application/csv');

                return done();
            });
        });

        it('Converts when route ends with .csv', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/user.csv'
            }, (res) => {

                expect(res.result).to.equal(userCSV);
                expect(res.headers['content-type']).to.equal('text/csv; charset=utf-8');

                return done();
            });
        });

        it('Still replies with JSON when asked', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/user',
                headers: {
                    Accept: 'application/json'
                }
            }, (res) => {

                expect(res.headers['content-type']).to.equal('application/json; charset=utf-8');
                expect(res.result).to.equal(user);

                return done();
            });
        });

        it('Still replies with JSON when no accept header present', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/user',
                headers: {
                    Accept: ''
                }
            }, (res) => {

                expect(res.headers['content-type']).to.equal('application/json; charset=utf-8');
                expect(res.result).to.equal(user);

                return done();
            });
        });

        it('Still replies with JSON when no response schema is specified', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/userWithoutSchema',
                headers: {
                    Accept: 'text/csv'
                }
            }, (res) => {

                expect(res.headers['content-type']).to.equal('application/json; charset=utf-8');
                expect(res.result).to.equal(user);

                return done();
            });
        });
    });

    describe('Advanced convertions', () => {

        it('Converts more advanced, nested schema', (done) => {

            const server = new Hapi.Server();
            server.connection();

            const testResponseSchema = Joi.array().required().items({
                testObject: Joi.object().keys({
                    testPropOne: Joi.number().required(),
                    testPropTwo: Joi.number(),
                    testPropThree: Joi.string()
                }).allow(null),
                testNumber: Joi.number().required(),
                testString: Joi.string().allow(null),
                testEmail: Joi.string().email({ errorLevel: 68 }).lowercase().max(1000).required(),
                testDate: Joi.date().iso().allow(null),
                testArray: Joi.array().items(Joi.object().keys({
                    testPropOne: Joi.number().required(),
                    testPropTwo: Joi.string()
                })),
                testObjectArrayWithoutKeys: Joi.object(),
                testPrimitiveArray: Joi.array().items(Joi.number())
            });

            const dataset = [{
                testObject: null,
                testNumber: 5,
                testString: 'test',
                testEmail: 'test@testprovider.com',
                testDate: '2016-07-04T13:56:31.000Z',
                testPrimitiveArray: [5, 5],
                testObjectArrayWithoutKeys: { 'testPropOne': 1 },
                testArray: [{
                    testPropOne: 1,
                    testPropTwo: 'One'
                }, {
                    testPropOne: 2,
                    testPropTwo: 'Two'
                }, {
                    testPropOne: 3,
                    testPropTwo: 'Three'
                }, {
                    testPropOne: 4,
                    testPropTwo: 'Four'
                }]
            }];

            return server.register(HapiCsv, (err) => {

                expect(err, 'error').to.not.exist();

                server.route([{
                    method: 'GET',
                    path: '/test',
                    config: {
                        handler: function (request, reply) {

                            return reply(dataset);
                        },
                        response: {
                            schema: testResponseSchema
                        }
                    }
                }]);

                return server.initialize((err) => {

                    expect(err, 'error').to.not.exist();

                    return server.inject({
                        method: 'GET',
                        url: '/test',
                        headers: {
                            'Accept': 'text/csv'
                        }
                    }, (res) => {

                        const expectedResult = 'testObject.testPropOne,testObject.testPropTwo,testObject.testPropThree,testNumber,testString,testEmail,testDate,testArray_0.testPropOne,testArray_0.testPropTwo,testArray_1.testPropOne,testArray_1.testPropTwo,testArray_2.testPropOne,testArray_2.testPropTwo,testArray_3.testPropOne,testArray_3.testPropTwo,testArray_4.testPropOne,testArray_4.testPropTwo,testPrimitiveArray_0,testPrimitiveArray_1,testPrimitiveArray_2,testPrimitiveArray_3,testPrimitiveArray_4,\n,,,"5","test","test@testprovider.com","2016-07-04T13:56:31.000Z","1","One","2","Two","3","Three","4","Four",,,"5","5",,,,';

                        expect(res.result).to.equal(expectedResult);

                        return server.stop(done);
                    });
                });
            });
        });

        it('Test plugin with schema existing of primitive type', (done) => {

            const server = new Hapi.Server();
            server.connection();

            return server.register(HapiCsv, (err) => {

                expect(err, 'error').to.not.exist();

                server.route([{
                    method: 'GET',
                    path: '/test',
                    config: {
                        handler: function (request, reply) {

                            return reply(5);
                        },
                        response: {
                            schema: Joi.number()
                        }
                    }
                }]);

                return server.initialize((err) => {

                    expect(err, 'error').to.not.exist();

                    return server.inject({
                        method: 'GET',
                        url: '/test',
                        headers: {
                            'Accept': 'text/csv'
                        }
                    }, (res) => {

                        expect(res.result).to.equal(5);

                        return server.stop(done);
                    });
                });
            });
        });
    });

    // todo add array depth test
    describe('Options', () => {

        it('Uses the passed options', (done) => {

            const user = {
                first_name: 'firstName',
                last_name: 'lastName',
                age: 25,
                tags: ['person', 'guitar']
            };
            const userCSV = `first_name+last_name+age+tags_0+\n"firstName"+"lastName"+"25"+"person"+`;

            const server = new Hapi.Server();
            server.connection();

            return server.register({
                register: HapiCsv,
                options: {
                    separator: '+',
                    maximumElementsInArray: '1'
                }
            }, (err) => {

                expect(err, 'error').to.not.exist();

                server.route([{
                    method: 'GET',
                    path: '/test',
                    config: {
                        handler: function (request, reply) {

                            return reply(user);
                        },
                        response: {
                            schema: Joi.object().keys({
                                first_name: Joi.string(),
                                last_name: Joi.string(),
                                age: Joi.number(),
                                tags: Joi.array().items(Joi.string())
                            })
                        }
                    }
                }]);

                return server.initialize((err) => {

                    expect(err, 'error').to.not.exist();

                    return server.inject({
                        method: 'GET',
                        url: '/test',
                        headers: {
                            'Accept': 'text/csv'
                        }
                    }, (res) => {

                        expect(res.result, 'result').to.equal(userCSV);

                        return server.stop(done);
                    });
                });
            });
        });
    });
});
<commit_msg>add extra test for .csv with query params<commit_after>'use strict';

const Lab = require('lab');
const Code = require('code');
const Joi = require('joi');
const Hapi = require('hapi');
const HapiCsv = require('../lib/index');

const lab = exports.lab = Lab.script();
const describe = lab.experiment;
const it = lab.it;
const before = lab.before;
const after = lab.after;
const expect = Code.expect;

describe('Hapi csv', () => {

    describe('Basics', () => {

        it('Registers', (done) => {

            const server = new Hapi.Server();
            server.connection();

            server.register({
                register: HapiCsv
            }, (err) => {

                expect(err, 'error').to.not.exists();

                return done();
            });
        });
    });

    describe('Basic convertions', () => {

        let simpleServer;
        const user = {
            first_name: 'firstName',
            last_name: 'lastName',
            age: 25
        };
        const userCSV = `first_name,last_name,age,\n"firstName","lastName","25",`;
        const testResponseSchema = Joi.object().keys({
            first_name: Joi.string(),
            last_name: Joi.string(),
            age: Joi.number()
        });

        before((done) => {

            simpleServer = new Hapi.Server();
            simpleServer.connection();

            simpleServer.route([{
                method: 'GET',
                path: '/user',
                config: {
                    handler: function (request, reply) {

                        return reply(user);
                    },
                    response: {
                        schema: testResponseSchema
                    }
                }
            }, {
                method: 'GET',
                path: '/userWithoutSchema',
                config: {
                    handler: function (request, reply) {

                        return reply(user);
                    }
                }
            }]);

            return simpleServer.register({
                register: HapiCsv
            }, (err) => {

                expect(err, 'error').to.not.exist();

                // initialize is needed for hapi-csv route mapping to trigger
                return simpleServer.initialize((err) => {

                    expect(err, 'error').to.not.exist();

                    return done();
                });
            });
        });

        after((done) => {

            return simpleServer.stop(done);
        });

        it('Converts with text/csv header', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/user',
                headers: {
                    'Accept': 'text/csv'
                }
            }, (res) => {

                expect(res.result).to.equal(userCSV);
                expect(res.headers['content-type']).to.equal('text/csv; charset=utf-8');

                return done();
            });
        });

        it('Converts with application/csv header', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/user',
                headers: {
                    'Accept': 'application/csv'
                }
            }, (res) => {

                expect(res.result).to.equal(userCSV);
                expect(res.headers['content-type']).to.equal('application/csv');

                return done();
            });
        });

        it('Converts when route ends with .csv', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/user.csv'
            }, (res) => {

                expect(res.result).to.equal(userCSV);
                expect(res.headers['content-type']).to.equal('text/csv; charset=utf-8');

                return done();
            });
        });

        it('Converts when route ends with .csv and has query params', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/user.csv?q=1'
            }, (res) => {

                expect(res.result).to.equal(userCSV);
                expect(res.headers['content-type']).to.equal('text/csv; charset=utf-8');

                return done();
            });
        });

        it('Still replies with JSON when asked', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/user',
                headers: {
                    Accept: 'application/json'
                }
            }, (res) => {

                expect(res.headers['content-type']).to.equal('application/json; charset=utf-8');
                expect(res.result).to.equal(user);

                return done();
            });
        });

        it('Still replies with JSON when no accept header present', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/user',
                headers: {
                    Accept: ''
                }
            }, (res) => {

                expect(res.headers['content-type']).to.equal('application/json; charset=utf-8');
                expect(res.result).to.equal(user);

                return done();
            });
        });

        it('Still replies with JSON when no response schema is specified', (done) => {

            return simpleServer.inject({
                method: 'GET',
                url: '/userWithoutSchema',
                headers: {
                    Accept: 'text/csv'
                }
            }, (res) => {

                expect(res.headers['content-type']).to.equal('application/json; charset=utf-8');
                expect(res.result).to.equal(user);

                return done();
            });
        });
    });

    describe('Advanced convertions', () => {

        it('Converts more advanced, nested schema', (done) => {

            const server = new Hapi.Server();
            server.connection();

            const testResponseSchema = Joi.array().required().items({
                testObject: Joi.object().keys({
                    testPropOne: Joi.number().required(),
                    testPropTwo: Joi.number(),
                    testPropThree: Joi.string()
                }).allow(null),
                testNumber: Joi.number().required(),
                testString: Joi.string().allow(null),
                testEmail: Joi.string().email({ errorLevel: 68 }).lowercase().max(1000).required(),
                testDate: Joi.date().iso().allow(null),
                testArray: Joi.array().items(Joi.object().keys({
                    testPropOne: Joi.number().required(),
                    testPropTwo: Joi.string()
                })),
                testObjectArrayWithoutKeys: Joi.object(),
                testPrimitiveArray: Joi.array().items(Joi.number())
            });

            const dataset = [{
                testObject: null,
                testNumber: 5,
                testString: 'test',
                testEmail: 'test@testprovider.com',
                testDate: '2016-07-04T13:56:31.000Z',
                testPrimitiveArray: [5, 5],
                testObjectArrayWithoutKeys: { 'testPropOne': 1 },
                testArray: [{
                    testPropOne: 1,
                    testPropTwo: 'One'
                }, {
                    testPropOne: 2,
                    testPropTwo: 'Two'
                }, {
                    testPropOne: 3,
                    testPropTwo: 'Three'
                }, {
                    testPropOne: 4,
                    testPropTwo: 'Four'
                }]
            }];

            return server.register(HapiCsv, (err) => {

                expect(err, 'error').to.not.exist();

                server.route([{
                    method: 'GET',
                    path: '/test',
                    config: {
                        handler: function (request, reply) {

                            return reply(dataset);
                        },
                        response: {
                            schema: testResponseSchema
                        }
                    }
                }]);

                return server.initialize((err) => {

                    expect(err, 'error').to.not.exist();

                    return server.inject({
                        method: 'GET',
                        url: '/test',
                        headers: {
                            'Accept': 'text/csv'
                        }
                    }, (res) => {

                        const expectedResult = 'testObject.testPropOne,testObject.testPropTwo,testObject.testPropThree,testNumber,testString,testEmail,testDate,testArray_0.testPropOne,testArray_0.testPropTwo,testArray_1.testPropOne,testArray_1.testPropTwo,testArray_2.testPropOne,testArray_2.testPropTwo,testArray_3.testPropOne,testArray_3.testPropTwo,testArray_4.testPropOne,testArray_4.testPropTwo,testPrimitiveArray_0,testPrimitiveArray_1,testPrimitiveArray_2,testPrimitiveArray_3,testPrimitiveArray_4,\n,,,"5","test","test@testprovider.com","2016-07-04T13:56:31.000Z","1","One","2","Two","3","Three","4","Four",,,"5","5",,,,';

                        expect(res.result).to.equal(expectedResult);

                        return server.stop(done);
                    });
                });
            });
        });

        it('Test plugin with schema existing of primitive type', (done) => {

            const server = new Hapi.Server();
            server.connection();

            return server.register(HapiCsv, (err) => {

                expect(err, 'error').to.not.exist();

                server.route([{
                    method: 'GET',
                    path: '/test',
                    config: {
                        handler: function (request, reply) {

                            return reply(5);
                        },
                        response: {
                            schema: Joi.number()
                        }
                    }
                }]);

                return server.initialize((err) => {

                    expect(err, 'error').to.not.exist();

                    return server.inject({
                        method: 'GET',
                        url: '/test',
                        headers: {
                            'Accept': 'text/csv'
                        }
                    }, (res) => {

                        expect(res.result).to.equal(5);

                        return server.stop(done);
                    });
                });
            });
        });
    });

    // todo add array depth test
    describe('Options', () => {

        it('Uses the passed options', (done) => {

            const user = {
                first_name: 'firstName',
                last_name: 'lastName',
                age: 25,
                tags: ['person', 'guitar']
            };
            const userCSV = `first_name+last_name+age+tags_0+\n"firstName"+"lastName"+"25"+"person"+`;

            const server = new Hapi.Server();
            server.connection();

            return server.register({
                register: HapiCsv,
                options: {
                    separator: '+',
                    maximumElementsInArray: '1'
                }
            }, (err) => {

                expect(err, 'error').to.not.exist();

                server.route([{
                    method: 'GET',
                    path: '/test',
                    config: {
                        handler: function (request, reply) {

                            return reply(user);
                        },
                        response: {
                            schema: Joi.object().keys({
                                first_name: Joi.string(),
                                last_name: Joi.string(),
                                age: Joi.number(),
                                tags: Joi.array().items(Joi.string())
                            })
                        }
                    }
                }]);

                return server.initialize((err) => {

                    expect(err, 'error').to.not.exist();

                    return server.inject({
                        method: 'GET',
                        url: '/test',
                        headers: {
                            'Accept': 'text/csv'
                        }
                    }, (res) => {

                        expect(res.result, 'result').to.equal(userCSV);

                        return server.stop(done);
                    });
                });
            });
        });
    });
});
<|endoftext|>


<commit_before>/**
 * Amata.js - List multi-selection multi-action form multi-task executer
 *
 * @link    https://github.com/textpattern/amata
 * @license MIT
 */

/*
 * Copyright (C) 2013 The Textpattern Development Team
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * @name jQuery
 * @class
 */

/**
 * @name fn
 * @class
 * @memberOf jQuery
 */

(function (factory)
{
    'use strict';

    if (typeof define === 'function' && define.amd)
    {
        define(['jquery'], factory);
    }
    else
    {
        factory(window.jQuery);
    }
}(function ($)
{
    'use strict';

    /**
     * Methods.
     *
     * @var {Object}
     */

    var methods = {};

    /**
     * Initializes the multi-editor.
     *
     * @param {Object} [options={}] Options
     */

    methods.init = function (options)
    {
        options = $.extend({
            'selectAll'     : '[name=amata-select-all]',
            'button'        : '[type=submit]',
            'boxes'         : '[name="selected[]"]',
            'highlighted'   : 'tr',
            'selectedClass' : 'highlighted',
            'clickRegion'   : 'table tbody tr td'
        }, options);

        this.closest('form').not('.amata-ready').each(function ()
        {
            var $this = $(this), button = $this.find(options.button).hide(), actions = $(this).find('select.amata-actions').val(''), selectAll = $(options.selectAll), lastCheck = false;

            methods.registerOptions.call($this);

            selectAll.on('change', function ()
            {
                $(options.boxes).prop('checked', $(this).prop('checked')).change();
            });

            $this.on('click.amata', options.clickRegion, function (e)
            {
                var $this = $(this), self = ($(e.target).is(options.boxes) || $(this).is(options.boxes)), box, checked;

                if (!self)
                {
                    // Clicking the row, but without holding CTRL/ALT.

                    if (!e.altKey && !e.ctrlKey)
                    {
                        return;
                    }

                    // Skip actions invoked from clicking links and inputs.

                    if (e.target !== this || $this.is('a, :input') || $(e.target).is('a, :input'))
                    {
                        return;
                    }
                }

                box = $this.closest(options.highlighted).find(options.boxes).eq(0);

                if (!box.length)
                {
                    return;
                }

                checked = box.prop('checked');

                if (self)
                {
                    checked = !checked;
                }

                if (e.shiftKey && lastCheck)
                {
                    var boxes = $this.find(options.boxes), start = boxes.index(box), end = boxes.index(lastCheck);

                    boxes
                        .slice(Math.min(start, end), Math.max(start, end) + 1)
                        .prop('checked', !checked)
                        .change();
                }
                else if (!self)
                {
                    box.prop('checked', !checked).change();
                }

                if (checked === false)
                {
                    lastCheck = box;
                }
                else
                {
                    lastCheck = null;
                }
            });

            $this.on('change.amata', options.boxes, function ()
            {
                var box = $(this), boxes = $(options.boxes);

                if (box.prop('checked'))
                {
                    box.closest(options.highlighted).addClass(options.selectedClass);
                    selectAll.prop('checked', boxes.filter(':checked').length === boxes.length);
                }
                else
                {
                    box.closest(options.highlighted).removeClass(options.selectedClass);
                    selectAll.prop('checked', false);
                }
            });

            actions.on('change.amata', function ()
            {
                var selected = $(this).find('option:selected').eq(0);
                $this.trigger('amata-action-change.amata').find('.amata-active-step').remove();

                if (!selected.val())
                {
                    button.hide();
                    return;
                }

                if (selected.data('amata-method'))
                {
                    $(this).after($('<div />').attr('class', 'amata-active-step').html(selected.data('amata-method')));
                    button.show();
                }
                else
                {
                    button.hide();
                    $this.trigger('submit.amata');
                }
            });

            $this.addClass('.amata-ready');
        });

        return this;
    };

    /**
     * Adds a multi-edit option.
     *
     * @param  {object} options
     * @param  {string} options.label The option's label
     * @param  {string} options.value The option's value
     * @param  {string} options.html  The second step HTML
     * @return {object} this
     * @example
     * $('form').amata('addOption', {
     *  'label' : 'Delete',
     *  'value' : 'delete'
     * });
     */

    methods.addOption = function (options)
    {
        options = $.extend({
            'label' : null,
            'value' : null,
            'html'  : null
        }, options);

        var $this = this.closest('form').find('.amata-actions').eq(0).val(''), exists = false;

        if (!options.value || !$this.length)
        {
            return this;
        }

        var option = $this.find('option').filter(function ()
        {
            return $(this).val() === options.value;
        }).eq(0);

        exists = (option.length !== 0);

        if (!exists)
        {
            option = $('<option />');
        }

        if (!exists || !option.data('amata-method'))
        {
            if (!option.val())
            {
                option.val(options.value);
            }

            if (!option.text() && options.label)
            {
                option.text(options.label);
            }

            option.data('amata-method', options.html);

            if (!exists)
            {
                $this.append(option);
            }
        }

        return this;
    };

    /**
     * Registers multi-edit options from the document.
     *
     * @return   {Object} this
     * @method   registerOptions
     * @memberof jQuery.fn.amata
     */

    methods.registerOptions = function ()
    {
        return this.each(function ()
        {
            var $this = $(this), multiOptions = $this.find('[data-amata-option]');

            $this.find('select.amata-actions option').each(function ()
            {
                var value = $(this).val();

                if (value)
                {
                    var option = multiOptions.filter(function ()
                    {
                        return $(this).attr('data-amata-option') === value;
                    });

                    if (option.length > 0)
                    {
                        methods.addOption.call($this, {
                            'label' : null,
                            'html'  : option.eq(0).contents(),
                            'value' : $(this).val()
                        });
                    }
                }
            });

            multiOptions.remove();
        });
    };

    /**
     * Multi-edit functions.
     *
     * @param    {String|Object} [method=init] Called method
     * @param    {Object}        [options={}]  Options passed to the method
     * @class    amata
     * @memberof jQuery.fn
     */

    $.fn.amata = function (method, options)
    {
        if ($.type(method) !== 'string' || $.type(methods[method]) !== 'function')
        {
            options = method;
            method = 'init';
        }

        return methods[method].call(this, options);
    };
}));<commit_msg>Shift click selects regions.<commit_after>/**
 * Amata.js - List multi-selection multi-action form multi-task executer
 *
 * @link    https://github.com/textpattern/amata
 * @license MIT
 */

/*
 * Copyright (C) 2013 The Textpattern Development Team
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * @name jQuery
 * @class
 */

/**
 * @name fn
 * @class
 * @memberOf jQuery
 */

(function (factory)
{
    'use strict';

    if (typeof define === 'function' && define.amd)
    {
        define(['jquery'], factory);
    }
    else
    {
        factory(window.jQuery);
    }
}(function ($)
{
    'use strict';

    /**
     * Methods.
     *
     * @var {Object}
     */

    var methods = {};

    /**
     * Initializes the multi-editor.
     *
     * @param {Object} [options={}] Options
     */

    methods.init = function (options)
    {
        options = $.extend({
            'selectAll'     : '[name=amata-select-all]',
            'button'        : '[type=submit]',
            'boxes'         : '[name="selected[]"]',
            'highlighted'   : 'tr',
            'selectedClass' : 'highlighted',
            'clickRegion'   : 'table tbody tr td'
        }, options);

        this.closest('form').not('.amata-ready').each(function ()
        {
            var $this = $(this), button = $this.find(options.button).hide(), actions = $(this).find('select.amata-actions').val(''), selectAll = $(options.selectAll), lastCheck = false;

            methods.registerOptions.call($this);

            selectAll.on('change', function ()
            {
                $(options.boxes).prop('checked', $(this).prop('checked')).change();
            });

            $this.on('click.amata', options.clickRegion, function (e)
            {
                var row = $(this), self = ($(e.target).is(options.boxes) || row.is(options.boxes)), box, checked;

                if (!self)
                {
                    // Clicking the row, but without holding CTRL/ALT.

                    if (!e.altKey && !e.ctrlKey)
                    {
                        return;
                    }

                    // Skip actions invoked from clicking links and inputs.

                    if (e.target !== this || row.is('a, :input') || $(e.target).is('a, :input'))
                    {
                        return;
                    }
                }

                box = row.closest(options.highlighted).find(options.boxes);

                if (!box.length)
                {
                    return;
                }

                checked = box.prop('checked');

                if (self)
                {
                    checked = !checked;
                }

                if (e.shiftKey && lastCheck)
                {
                    var boxes = $this.find(options.boxes), start = boxes.index(box), end = boxes.index(lastCheck);

                    boxes
                        .slice(Math.min(start, end), Math.max(start, end) + 1)
                        .prop('checked', !checked)
                        .change();
                }
                else if (!self)
                {
                    box.prop('checked', !checked).change();
                }

                if (checked === false)
                {
                    lastCheck = box;
                }
                else
                {
                    lastCheck = null;
                }
            });

            $this.on('change.amata', options.boxes, function ()
            {
                var box = $(this), boxes = $(options.boxes);

                if (box.prop('checked'))
                {
                    box.closest(options.highlighted).addClass(options.selectedClass);
                    selectAll.prop('checked', boxes.filter(':checked').length === boxes.length);
                }
                else
                {
                    box.closest(options.highlighted).removeClass(options.selectedClass);
                    selectAll.prop('checked', false);
                }
            });

            actions.on('change.amata', function ()
            {
                var selected = $(this).find('option:selected').eq(0);
                $this.trigger('amata-action-change.amata').find('.amata-active-step').remove();

                if (!selected.val())
                {
                    button.hide();
                    return;
                }

                if (selected.data('amata-method'))
                {
                    $(this).after($('<div />').attr('class', 'amata-active-step').html(selected.data('amata-method')));
                    button.show();
                }
                else
                {
                    button.hide();
                    $this.trigger('submit.amata');
                }
            });

            $this.addClass('.amata-ready');
        });

        return this;
    };

    /**
     * Adds a multi-edit option.
     *
     * @param  {object} options
     * @param  {string} options.label The option's label
     * @param  {string} options.value The option's value
     * @param  {string} options.html  The second step HTML
     * @return {object} this
     * @example
     * $('form').amata('addOption', {
     *  'label' : 'Delete',
     *  'value' : 'delete'
     * });
     */

    methods.addOption = function (options)
    {
        options = $.extend({
            'label' : null,
            'value' : null,
            'html'  : null
        }, options);

        var $this = this.closest('form').find('.amata-actions').eq(0).val(''), exists = false;

        if (!options.value || !$this.length)
        {
            return this;
        }

        var option = $this.find('option').filter(function ()
        {
            return $(this).val() === options.value;
        }).eq(0);

        exists = (option.length !== 0);

        if (!exists)
        {
            option = $('<option />');
        }

        if (!exists || !option.data('amata-method'))
        {
            if (!option.val())
            {
                option.val(options.value);
            }

            if (!option.text() && options.label)
            {
                option.text(options.label);
            }

            option.data('amata-method', options.html);

            if (!exists)
            {
                $this.append(option);
            }
        }

        return this;
    };

    /**
     * Registers multi-edit options from the document.
     *
     * @return   {Object} this
     * @method   registerOptions
     * @memberof jQuery.fn.amata
     */

    methods.registerOptions = function ()
    {
        return this.each(function ()
        {
            var $this = $(this), multiOptions = $this.find('[data-amata-option]');

            $this.find('select.amata-actions option').each(function ()
            {
                var value = $(this).val();

                if (value)
                {
                    var option = multiOptions.filter(function ()
                    {
                        return $(this).attr('data-amata-option') === value;
                    });

                    if (option.length > 0)
                    {
                        methods.addOption.call($this, {
                            'label' : null,
                            'html'  : option.eq(0).contents(),
                            'value' : $(this).val()
                        });
                    }
                }
            });

            multiOptions.remove();
        });
    };

    /**
     * Multi-edit functions.
     *
     * @param    {String|Object} [method=init] Called method
     * @param    {Object}        [options={}]  Options passed to the method
     * @class    amata
     * @memberof jQuery.fn
     */

    $.fn.amata = function (method, options)
    {
        if ($.type(method) !== 'string' || $.type(methods[method]) !== 'function')
        {
            options = method;
            method = 'init';
        }

        return methods[method].call(this, options);
    };
}));<|endoftext|>


<commit_before>'use strict'

const fs     = require('fs')
const path   = require('path')
const assert = require('chai').assert
const temp   = require('temp').track()
const index  = require('./../src/index')

const newFile = function(content, suffix) {

	const file = temp.openSync({ suffix })

	fs.writeFileSync(file.path, content)

	return file

}

const data = {
	path: path.resolve(process.cwd(), './data.json')
}

fs.writeFileSync(data.path, '{}')

describe('index()', function() {

	before(function() {

		fs.writeFileSync(data.path, '{}')

	})

	it('should return an error when called with an invalid filePath', function() {

		return index(null, '/src', '/dist', {}).then(({ data, savePath }) => {

			throw new Error('Returned without error')

		}, (err) => {

			assert.isNotNull(err)

		})

	})

	it('should return an error when called with a fictive filePath', function() {

		return index('test.scss', '/src', '/dist', {}).then(({ data, savePath }) => {

			throw new Error('Returned without error')

		}, (err) => {

			assert.isNotNull(err)

		})

	})

	it('should load EJS and transform it to HTML when everything specified', function() {

		const file = newFile('', '.ejs')

		return index(file.path, '/src', '/dist', {}).then(({ data, savePath }) => {

			assert.isString(savePath)
			assert.strictEqual(data, '')
			assert.strictEqual(savePath.substr(-5), '.html')

		})

	})

	it('should load XML and transform it to HTML when custom fileExt specified', function() {

		const file  = newFile('', '.xml')
		const route = { args: { fileExt: 'xml' } }

		return index(file.path, '/src', '/dist', route).then(({ data, savePath }) => {

			assert.isString(savePath)
			assert.strictEqual(data, '')
			assert.strictEqual(savePath.substr(-5), '.html')

		})

	})

	it('should load EJS and transform it to XML when custom saveExt specified', function() {

		const file  = newFile('', '.ejs')
		const route = { args: { saveExt: 'xml' } }

		return index(file.path, '/src', '/dist', route).then(({ data, savePath }) => {

			assert.isString(savePath)
			assert.strictEqual(data, '')
			assert.strictEqual(savePath.substr(-4), '.xml')

		})

	})

	it('should load EJS and transform it to HTML when distPath not specified', function() {

		const file = newFile('', '.ejs')

		return index(file.path, '/src', null, {}).then(({ data, savePath }) => {

			assert.isString(savePath)
			assert.strictEqual(data, '')
			assert.strictEqual(savePath.substr(-5), '.html')

		})

	})

	describe('.cache', function() {

		it('should be an array', function() {

			assert.isArray(index.cache)

		})

	})

	after(function() {

		fs.unlinkSync(data.path)

	})

})<commit_msg>Simplified newFile fn and remove writeFileSync duplicate<commit_after>'use strict'

const fs     = require('fs')
const path   = require('path')
const assert = require('chai').assert
const temp   = require('temp').track()
const index  = require('./../src/index')

const newFile = function(suffix) {

	return temp.openSync({ suffix })

}

const data = {
	path: path.resolve(process.cwd(), './data.json')
}

describe('index()', function() {

	before(function() {

		fs.writeFileSync(data.path, '{}')

	})

	it('should return an error when called with an invalid filePath', function() {

		return index(null, '/src', '/dist', {}).then(({ data, savePath }) => {

			throw new Error('Returned without error')

		}, (err) => {

			assert.isNotNull(err)

		})

	})

	it('should return an error when called with a fictive filePath', function() {

		return index('test.scss', '/src', '/dist', {}).then(({ data, savePath }) => {

			throw new Error('Returned without error')

		}, (err) => {

			assert.isNotNull(err)

		})

	})

	it('should load EJS and transform it to HTML when everything specified', function() {

		const file = newFile('.ejs')

		return index(file.path, '/src', '/dist', {}).then(({ data, savePath }) => {

			assert.isString(savePath)
			assert.strictEqual(data, '')
			assert.strictEqual(savePath.substr(-5), '.html')

		})

	})

	it('should load XML and transform it to HTML when custom fileExt specified', function() {

		const file  = newFile('.xml')
		const route = { args: { fileExt: 'xml' } }

		return index(file.path, '/src', '/dist', route).then(({ data, savePath }) => {

			assert.isString(savePath)
			assert.strictEqual(data, '')
			assert.strictEqual(savePath.substr(-5), '.html')

		})

	})

	it('should load EJS and transform it to XML when custom saveExt specified', function() {

		const file  = newFile('.ejs')
		const route = { args: { saveExt: 'xml' } }

		return index(file.path, '/src', '/dist', route).then(({ data, savePath }) => {

			assert.isString(savePath)
			assert.strictEqual(data, '')
			assert.strictEqual(savePath.substr(-4), '.xml')

		})

	})

	it('should load EJS and transform it to HTML when distPath not specified', function() {

		const file = newFile('.ejs')

		return index(file.path, '/src', null, {}).then(({ data, savePath }) => {

			assert.isString(savePath)
			assert.strictEqual(data, '')
			assert.strictEqual(savePath.substr(-5), '.html')

		})

	})

	describe('.cache', function() {

		it('should be an array', function() {

			assert.isArray(index.cache)

		})

	})

	after(function() {

		fs.unlinkSync(data.path)

	})

})<|endoftext|>


<commit_before>// Require all test files (files that ends with .spec.js)
const testsContext = require.context('./specs', true, /\.spec$/);
testsContext.keys().forEach(testsContext);

// Require all source files for coverage.
// You can also change this to match only the subset of files that you want coverage for.
const srcContext = require.context('../source', true, /^\.js$/);
srcContext.keys().forEach(srcContext);
<commit_msg>chore: fixtures<commit_after>// Require all fixtures (files that ends with .fixture.html)
const fixturesContext = require.context('./fixtures', true, /\.fixture\.html$/);
fixturesContext.keys().forEach(fixturesContext);

// Require all test files (files that ends with .spec.js)
const testsContext = require.context('./specs', true, /\.spec$/);
testsContext.keys().forEach(testsContext);

// Require all source files for coverage.
// You can also change this to match only the subset of files that you want coverage for.
const srcContext = require.context('../source', true, /^\.js$/);
srcContext.keys().forEach(srcContext);
<|endoftext|>


<commit_before>import Log from './Log';
import OidcClientSettings from './OidcClientSettings';
import MetadataService from './MetadataService';
import SigninRequest from './SigninRequest';
import SigninResponse from './SigninResponse';
import SignoutRequest from './SignoutRequest';
import SignoutResponse from './SignoutResponse';
import WebStorageStateStore from './WebStorageStateStore';
import ResponseValidator from './ResponseValidator';
import State from './State';

export default class OidcClientService {
    // logging
    static get logger(){
        return Log.logger;
    }
    static set logger(value){
        Log.logger = value;
    }
    static get logLevel(){
        return Log.level;
    }
    static set logLevel(value){
        if (typeof value === 'string'){
            Log.level = Log[value];
        }
        else {
            Log.level = value;
        }
    }

    constructor(settings,
        stateStore = new WebStorageStateStore(),
        ResponseValidatorCtor = ResponseValidator,
        MetadataServiceCtor = MetadataService
    ){
        if (!settings) {
            Log.error("No settings passed to OidcClientService");
            throw new Error("settings");
        }

        this._settings = new OidcClientSettings(settings);
        this._stateStore = stateStore;
        this._validator = new ResponseValidatorCtor(this._settings);
        this._metadataService = new MetadataServiceCtor(this._settings);
    }

    get settings() {
        return this._settings;
    }

    createSigninRequest({
        response_type, scope, redirect_uri, data,
        prompt, display, max_age, ui_locales, id_token_hint, login_hint, acr_values}={}
    ) {
        Log.info("OidcClientService.createSigninRequest");

        let client_id = this._settings.client_id;
        response_type = response_type || this._settings.response_type;
        scope = scope || this._settings.scope;
        redirect_uri = redirect_uri || this._settings.redirect_uri;

        // id_token_hint, login_hint aren't allowed on _settings
        prompt = prompt || this._settings.prompt;
        display = display || this._settings.display;
        max_age = max_age  || this._settings.max_age ;
        ui_locales = ui_locales || this._settings.ui_locales;
        acr_values = acr_values || this._settings.acr_values;

        return this._metadataService.getAuthorizationEndpoint().then(url => {
            Log.info("Received authorization endpoint", url);

            let request = new SigninRequest({url,
                client_id,
                redirect_uri,
                response_type,
                scope,
                data,
                prompt, display, max_age, ui_locales, id_token_hint, login_hint, acr_values
            });

            var state = request.state;
            this._stateStore.set(state.id, state.toStorageString());

            return request;
        });
    }

    processSigninResponse(url){
        Log.info("OidcClientService.processSigninResponse");

        var response = new SigninResponse(url);
        if (!response.state) {
            Log.error("No state in response");
            return Promise.reject(new Error("No state in response"));
        }

        var stateKey = response.state;

        return this._stateStore.remove(stateKey).then(storedStateString => {
            if (!storedStateString){
                Log.error("No matching state found in storage");
                throw new Error("No matching state found in storage");
            }

            let state = State.fromStorageString(storedStateString);

            Log.info("Received state from storage; validating response");
            return this._validator.validateSigninResponse(state, response);
        });
    }

    createSignoutRequest({id_token_hint, data, post_logout_redirect_uri}={}){
        Log.info("OidcClientService.createSignoutRequest");

        post_logout_redirect_uri = post_logout_redirect_uri || this._settings.post_logout_redirect_uri;

        return this._metadataService.getEndSessionEndpoint().then(url => {
            Log.info("Received end session endpoint", url);

            let request = new SignoutRequest({url,
                id_token_hint,
                post_logout_redirect_uri,
                data
            });

            var state = request.state;
            this._stateStore.set(state.id, state.toStorageString());

            return request;
        });
    }

    processSignoutResponse(url){
        Log.info("OidcClientService.processSignoutResponse");

        var response = new SignoutResponse(url);
        if (!response.state) {
            Log.error("No state in response");
            return Promise.reject(new Error("No state in response"));
        }

        var stateKey = response.state;

        return this._stateStore.remove(stateKey).then(storedStateString => {
            if (!storedStateString){
                Log.error("No matching state found in storage");
                throw new Error("Failed to process response");
            }

            let state = State.fromStorageString(storedStateString);

            Log.info("Received state from storage; validating response");
            return this._validator.validateSignoutResponse(state, response);
        });
    }
}
<commit_msg>error wording typo<commit_after>import Log from './Log';
import OidcClientSettings from './OidcClientSettings';
import MetadataService from './MetadataService';
import SigninRequest from './SigninRequest';
import SigninResponse from './SigninResponse';
import SignoutRequest from './SignoutRequest';
import SignoutResponse from './SignoutResponse';
import WebStorageStateStore from './WebStorageStateStore';
import ResponseValidator from './ResponseValidator';
import State from './State';

export default class OidcClientService {
    // logging
    static get logger(){
        return Log.logger;
    }
    static set logger(value){
        Log.logger = value;
    }
    static get logLevel(){
        return Log.level;
    }
    static set logLevel(value){
        if (typeof value === 'string'){
            Log.level = Log[value];
        }
        else {
            Log.level = value;
        }
    }

    constructor(settings,
        stateStore = new WebStorageStateStore(),
        ResponseValidatorCtor = ResponseValidator,
        MetadataServiceCtor = MetadataService
    ){
        if (!settings) {
            Log.error("No settings passed to OidcClientService");
            throw new Error("settings");
        }

        this._settings = new OidcClientSettings(settings);
        this._stateStore = stateStore;
        this._validator = new ResponseValidatorCtor(this._settings);
        this._metadataService = new MetadataServiceCtor(this._settings);
    }

    get settings() {
        return this._settings;
    }

    createSigninRequest({
        response_type, scope, redirect_uri, data,
        prompt, display, max_age, ui_locales, id_token_hint, login_hint, acr_values}={}
    ) {
        Log.info("OidcClientService.createSigninRequest");

        let client_id = this._settings.client_id;
        response_type = response_type || this._settings.response_type;
        scope = scope || this._settings.scope;
        redirect_uri = redirect_uri || this._settings.redirect_uri;

        // id_token_hint, login_hint aren't allowed on _settings
        prompt = prompt || this._settings.prompt;
        display = display || this._settings.display;
        max_age = max_age  || this._settings.max_age ;
        ui_locales = ui_locales || this._settings.ui_locales;
        acr_values = acr_values || this._settings.acr_values;

        return this._metadataService.getAuthorizationEndpoint().then(url => {
            Log.info("Received authorization endpoint", url);

            let request = new SigninRequest({url,
                client_id,
                redirect_uri,
                response_type,
                scope,
                data,
                prompt, display, max_age, ui_locales, id_token_hint, login_hint, acr_values
            });

            var state = request.state;
            this._stateStore.set(state.id, state.toStorageString());

            return request;
        });
    }

    processSigninResponse(url){
        Log.info("OidcClientService.processSigninResponse");

        var response = new SigninResponse(url);
        if (!response.state) {
            Log.error("No state in response");
            return Promise.reject(new Error("No state in response"));
        }

        var stateKey = response.state;

        return this._stateStore.remove(stateKey).then(storedStateString => {
            if (!storedStateString){
                Log.error("No matching state found in storage");
                throw new Error("No matching state found in storage");
            }

            let state = State.fromStorageString(storedStateString);

            Log.info("Received state from storage; validating response");
            return this._validator.validateSigninResponse(state, response);
        });
    }

    createSignoutRequest({id_token_hint, data, post_logout_redirect_uri}={}){
        Log.info("OidcClientService.createSignoutRequest");

        post_logout_redirect_uri = post_logout_redirect_uri || this._settings.post_logout_redirect_uri;

        return this._metadataService.getEndSessionEndpoint().then(url => {
            Log.info("Received end session endpoint", url);

            let request = new SignoutRequest({url,
                id_token_hint,
                post_logout_redirect_uri,
                data
            });

            var state = request.state;
            this._stateStore.set(state.id, state.toStorageString());

            return request;
        });
    }

    processSignoutResponse(url){
        Log.info("OidcClientService.processSignoutResponse");

        var response = new SignoutResponse(url);
        if (!response.state) {
            Log.error("No state in response");
            return Promise.reject(new Error("No state in response"));
        }

        var stateKey = response.state;

        return this._stateStore.remove(stateKey).then(storedStateString => {
            if (!storedStateString){
                Log.error("No matching state found in storage");
                throw new Error("No matching state found in storage");
            }

            let state = State.fromStorageString(storedStateString);

            Log.info("Received state from storage; validating response");
            return this._validator.validateSignoutResponse(state, response);
        });
    }
}
<|endoftext|>


<commit_before>var tar = require('../')
var path = require('path')
var rfile = require('rfile')
var rimraf = require('rimraf').sync
var mkdir = require('mkdirp').sync

var read = require('fs').createReadStream
var write = require('fs').createWriteStream
var assert = require('assert')

beforeEach(function () {
  rimraf(__dirname + '/output')
})
afterEach(function () {
  rimraf(__dirname + '/output')
})
describe('tarball.pipe(unpack(directory, callback))', function () {
  it('unpacks the tarball into the directory', function (done) {
    read(__dirname + '/fixtures/packed.tar').pipe(tar.unpack(__dirname + '/output/unpacked', function (err) {
      if (err) return done(err)
      assert.equal(rfile('./output/unpacked/bar.txt'), rfile('./fixtures/to-pack/bar.txt'))
      assert.equal(rfile('./output/unpacked/foo.txt'), rfile('./fixtures/to-pack/foo.txt'))
      done()
    }))
  })
})
describe('gziptarball.pipe(unpack(directory, callback))', function () {
  it('unpacks the tarball into the directory', function (done) {
    read(__dirname + '/fixtures/packed.tar.gz').pipe(tar.unpack(__dirname + '/output/unpacked', function (err) {
      if (err) return done(err)
      assert.equal(rfile('./output/unpacked/bar.txt'), rfile('./fixtures/to-pack/bar.txt'))
      assert.equal(rfile('./output/unpacked/foo.txt'), rfile('./fixtures/to-pack/foo.txt'))
      done()
    }))
  })
})
describe('file.pipe(unpack(directory, callback))', function () {
  it('copies the file into the directory', function (done) {
    read(__dirname + '/fixtures/packed-file.txt').pipe(tar.unpack(__dirname + '/output/unpacked', function (err) {
      if (err) return done(err)
      assert.equal(rfile('./output/unpacked/index.js'), rfile('./fixtures/packed-file.txt'))
      done()
    }))
  })
})
describe('pack(directory).pipe(tarball)', function () {
  it('packs the directory into the output', function (done) {
    var called = false
    mkdir(__dirname + '/output/')
    tar.pack(__dirname + '/fixtures/to-pack').pipe(write(__dirname + '/output/packed.tar.gz'))
      .on('error', function (err) {
        if (called) return
        called = true
        done(err)
      })
      .on('close', function () {
        if (called) return
        called = true
        read(__dirname + '/output/packed.tar.gz').pipe(tar.unpack(__dirname + '/output/unpacked', function (err) {
          if (err) return done(err)
          assert.equal(rfile('./output/unpacked/bar.txt'), rfile('./fixtures/to-pack/bar.txt'))
          assert.equal(rfile('./output/unpacked/foo.txt'), rfile('./fixtures/to-pack/foo.txt'))
          done()
        }))
      })
  })
})<commit_msg>Added tests for strip 0 and fromBase true options<commit_after>var tar = require('../')
var path = require('path')
var rfile = require('rfile')
var rimraf = require('rimraf').sync
var mkdir = require('mkdirp').sync

var read = require('fs').createReadStream
var write = require('fs').createWriteStream
var assert = require('assert')

beforeEach(function () {
  rimraf(__dirname + '/output')
})
afterEach(function () {
  rimraf(__dirname + '/output')
})
describe('tarball.pipe(unpack(directory, callback))', function () {
  it('unpacks the tarball into the directory', function (done) {
    read(__dirname + '/fixtures/packed.tar').pipe(tar.unpack(__dirname + '/output/unpacked', function (err) {
      if (err) return done(err)
      assert.equal(rfile('./output/unpacked/bar.txt'), rfile('./fixtures/to-pack/bar.txt'))
      assert.equal(rfile('./output/unpacked/foo.txt'), rfile('./fixtures/to-pack/foo.txt'))
      done()
    }))
  })
})
describe('tarball.pipe(unpack(directory, { strip: 0 }, callback))', function () {
  it('unpacks the tarball into the directory with subdir package', function (done) {
    read(__dirname + '/fixtures/packed.tar').pipe(tar.unpack(__dirname + '/output/unpacked', { strip: 0 } , function (err) {
      if (err) return done(err)
      assert.equal(rfile('./output/unpacked/package/bar.txt'), rfile('./fixtures/to-pack/bar.txt'))
      assert.equal(rfile('./output/unpacked/package/foo.txt'), rfile('./fixtures/to-pack/foo.txt'))
      done()
    }))
  })
})
describe('gziptarball.pipe(unpack(directory, callback))', function () {
  it('unpacks the tarball into the directory', function (done) {
    read(__dirname + '/fixtures/packed.tar.gz').pipe(tar.unpack(__dirname + '/output/unpacked', function (err) {
      if (err) return done(err)
      assert.equal(rfile('./output/unpacked/bar.txt'), rfile('./fixtures/to-pack/bar.txt'))
      assert.equal(rfile('./output/unpacked/foo.txt'), rfile('./fixtures/to-pack/foo.txt'))
      done()
    }))
  })
})
describe('file.pipe(unpack(directory, callback))', function () {
  it('copies the file into the directory', function (done) {
    read(__dirname + '/fixtures/packed-file.txt').pipe(tar.unpack(__dirname + '/output/unpacked', function (err) {
      if (err) return done(err)
      assert.equal(rfile('./output/unpacked/index.js'), rfile('./fixtures/packed-file.txt'))
      done()
    }))
  })
})
describe('pack(directory).pipe(tarball)', function () {
  it('packs the directory into the output', function (done) {
    var called = false
    mkdir(__dirname + '/output/')
    tar.pack(__dirname + '/fixtures/to-pack').pipe(write(__dirname + '/output/packed.tar.gz'))
      .on('error', function (err) {
        if (called) return
        called = true
        done(err)
      })
      .on('close', function () {
        if (called) return
        called = true
        read(__dirname + '/output/packed.tar.gz').pipe(tar.unpack(__dirname + '/output/unpacked', function (err) {
          if (err) return done(err)
          assert.equal(rfile('./output/unpacked/bar.txt'), rfile('./fixtures/to-pack/bar.txt'))
          assert.equal(rfile('./output/unpacked/foo.txt'), rfile('./fixtures/to-pack/foo.txt'))
          done()
        }))
      })
  })
})
describe('pack(directory, { fromBase: true }).pipe(tarball)', function () {
  it('packs the directory with input dir as base dir', function (done) {
    var called = false
    mkdir(__dirname + '/output/')
    tar.pack(__dirname + '/fixtures/to-pack', { fromBase: true }).pipe(write(__dirname + '/output/packed.tar.gz'))
      .on('error', function (err) {
        if (called) return
        called = true
        done(err)
      })
      .on('close', function () {
        if (called) return
        called = true
        read(__dirname + '/output/packed.tar.gz').pipe(tar.unpack(__dirname + '/output/unpacked', { strip: 0 }, function (err) {
          if (err) return done(err)
          assert.equal(rfile('./output/unpacked/bar.txt'), rfile('./fixtures/to-pack/bar.txt'))
          assert.equal(rfile('./output/unpacked/foo.txt'), rfile('./fixtures/to-pack/foo.txt'))
          done()
        }))
      })
  })
})
<|endoftext|>