<commit_before>var verbose_logging = (process.env.NODE_ENV !== "production");
var models  = require("../../models");
var express = require("express");
var router = express.Router();
var views = require("../../views/v1");
var passport = require("passport");
passport.use(require("../../middleware/passport-token").TokenStrategy);

router.route("/:site_id")
  .get(passport.authenticate("token",{session:false}), function(req,res) {

    models.GuardianSite
      .findOne({
        where: { guid: req.params.site_id },
        include: [ { all: true } ]
      }).then(function(dbSite){

        res.status(200).json(views.models.guardianSites(req,res,dbSite));

      }).catch(function(err){
        console.log("failed to return site | "+err);
        if (!!err) { res.status(500).json({msg:"failed to return site"}); }
      });

  })
;

module.exports = router;

<commit_msg>sites endpoints<commit_after>var verbose_logging = (process.env.NODE_ENV !== "production");
var models  = require("../../models");
var express = require("express");
var router = express.Router();
var views = require("../../views/v1");
var passport = require("passport");
passport.use(require("../../middleware/passport-token").TokenStrategy);

router.route("/")
  .get(passport.authenticate("token",{session:false}), function(req,res) {

    models.GuardianSite
      .findAll({
        where: { is_active: true },
//        include: [ { all: true } ],
//        order: [ ["last_check_in", "DESC"] ],
        limit: req.rfcx.limit,
        offset: req.rfcx.offset
      }).then(function(dbSite){

        res.status(200).json(views.models.guardianSites(req,res,dbSite));

      }).catch(function(err){
        console.log("failed to return site | "+err);
        if (!!err) { res.status(500).json({msg:"failed to return site"}); }
      });

  })
;

router.route("/:site_id")
  .get(passport.authenticate("token",{session:false}), function(req,res) {

    models.GuardianSite
      .findOne({
        where: { guid: req.params.site_id },
        include: [ { all: true } ]
      }).then(function(dbSite){

        res.status(200).json(views.models.guardianSites(req,res,dbSite));

      }).catch(function(err){
        console.log("failed to return site | "+err);
        if (!!err) { res.status(500).json({msg:"failed to return site"}); }
      });

  })
;

module.exports = router;

<|endoftext|>


<commit_before>O5.utils = O5.utils || {};
_.extend(O5.utils, {
	nlToBR: function(txt) {
		return _.escape(txt).replace('\n', '
');
	},

	notify: function(message, tag, opts) {
		var $container = $('#notifications');
		if (!$container.length) {
			$container = $('
');
			$('body').append($container);
		}
		opts = opts || {};
		_.defaults(opts, {
			message: message,
			tag: tag,
			hideDelay: 5000
		});
		var $alert = $(JST.notification(opts));
		$container.append($alert);
		if (opts.hideDelay) {
			setTimeout(function() { $alert.alert('close'); }, opts.hideDelay);
		}
	}
});<commit_msg>Oh, JS replace<commit_after>O5.utils = O5.utils || {};
_.extend(O5.utils, {
	nlToBR: function(txt) {
		return _.escape(txt).replace(/\n/g, '
');
	},

	notify: function(message, tag, opts) {
		var $container = $('#notifications');
		if (!$container.length) {
			$container = $('
');
			$('body').append($container);
		}
		opts = opts || {};
		_.defaults(opts, {
			message: message,
			tag: tag,
			hideDelay: 5000
		});
		var $alert = $(JST.notification(opts));
		$container.append($alert);
		if (opts.hideDelay) {
			setTimeout(function() { $alert.alert('close'); }, opts.hideDelay);
		}
	}
});<|endoftext|>


<commit_before>"use strict";

/**
 * Terrrain geometry is a plane like geometry deformed by a height map texture.
 *
 * This geometry type can be used to create large terrains.
 *
 * @class TerrainBufferGeometry
 * @constructor
 */
function TerrainBufferGeometry(width, height, widthSegments, heightSegments, image)
{
	THREE.BufferGeometry.call(this);

	this.type = "TerrainBufferGeometry";

	this.parameters =
	{
		width: width || 1,
		height: height || 1,
		widthSegments: widthSegments || 10,
		heightSegments: heightSegments || 10,
	};

	this.image = image;

	this.generate();
};

TerrainBufferGeometry.prototype = Object.create(THREE.BufferGeometry.prototype);
TerrainBufferGeometry.constructor = TerrainBufferGeometry;

TerrainBufferGeometry.prototype.generate = function()
{
	var width = this.parameters.width;
	var height = this.parameters.height;
	var widthSegments = this.parameters.widthSegments;
	var heightSegments = this.parameters.heightSegments;

	var data = this.image.getImageData();
	// TODO <REMOVE THIS>
	console.log(data);

	var widthHalf = width / 2;
	var heightHalf = height / 2;

	var gridX = Math.floor(widthSegments) || 1;
	var gridY = Math.floor(heightSegments) || 1;
	var gridX1 = gridX + 1;
	var gridY1 = gridY + 1;

	var segment_width = width / gridX;
	var segment_height = height / gridY;

	// Buffers
	var indices = [];
	var vertices = [];
	var normals = [];
	var uvs = [];

	// Generate vertices, normals and uvs
	for(var iy = 0; iy < gridY1; iy ++)
	{
		var y = iy * segment_height - heightHalf;

		for(var ix = 0; ix < gridX1; ix ++)
		{
			var x = ix * segment_width - widthHalf;

			vertices.push(x, 0, y);
			normals.push(0, 1, 0);

			uvs.push(ix / gridX);
			uvs.push(1 - (iy / gridY));
		}
	}

	// Indices
	for(var iy = 0; iy < gridY; iy ++)
	{
		for(var ix = 0; ix < gridX; ix ++)
		{
			var a = ix + gridX1 * iy;
			var b = ix + gridX1 * (iy + 1);
			var c = (ix + 1) + gridX1 * (iy + 1);
			var d = (ix + 1) + gridX1 * iy;

			indices.push(a, b, d);
			indices.push(b, c, d);
		}
	}

	this.setIndex(indices);
	this.setAttribute("position", new THREE.Float32BufferAttribute(vertices, 3));
	this.setAttribute("normal", new THREE.Float32BufferAttribute(normals, 3));
	this.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2));
};
<commit_msg>Derp<commit_after>"use strict";

/**
 * Terrrain geometry is a plane like geometry deformed by a height map texture.
 *
 * This geometry type can be used to create large terrains.
 *
 * @class TerrainBufferGeometry
 * @constructor
 */
function TerrainBufferGeometry(width, height, widthSegments, heightSegments, image)
{
	THREE.BufferGeometry.call(this);

	this.type = "TerrainBufferGeometry";

	this.parameters =
	{
		width: width || 1,
		height: height || 1,
		widthSegments: widthSegments || 10,
		heightSegments: heightSegments || 10,
	};

	this.image = image;

	this.generate();
};

TerrainBufferGeometry.prototype = Object.create(THREE.BufferGeometry.prototype);
TerrainBufferGeometry.constructor = TerrainBufferGeometry;

TerrainBufferGeometry.prototype.generate = function()
{
	var width = this.parameters.width;
	var height = this.parameters.height;
	var widthSegments = this.parameters.widthSegments;
	var heightSegments = this.parameters.heightSegments;

	var self = this;

	this.image.getImageData(function(data, w, h)
	{
		// TODO <REMOVE THIS>
		console.log(data);

		var widthHalf = width / 2;
		var heightHalf = height / 2;

		var gridX = Math.floor(widthSegments) || 1;
		var gridY = Math.floor(heightSegments) || 1;
		var gridX1 = gridX + 1;
		var gridY1 = gridY + 1;

		var segment_width = width / gridX;
		var segment_height = height / gridY;

		// Buffers
		var indices = [];
		var vertices = [];
		var normals = [];
		var uvs = [];

		// Generate vertices, normals and uvs
		for(var iy = 0; iy < gridY1; iy ++)
		{
			var y = iy * segment_height - heightHalf;

			for(var ix = 0; ix < gridX1; ix ++)
			{
				var x = ix * segment_width - widthHalf;

				vertices.push(x, 0, y);
				normals.push(0, 1, 0);

				uvs.push(ix / gridX);
				uvs.push(1 - (iy / gridY));
			}
		}

		// Indices
		for(var iy = 0; iy < gridY; iy ++)
		{
			for(var ix = 0; ix < gridX; ix ++)
			{
				var a = ix + gridX1 * iy;
				var b = ix + gridX1 * (iy + 1);
				var c = (ix + 1) + gridX1 * (iy + 1);
				var d = (ix + 1) + gridX1 * iy;

				indices.push(a, b, d);
				indices.push(b, c, d);
			}
		}

		self.setIndex(indices);

		self.setAttribute("position", new THREE.Float32BufferAttribute(vertices, 3));
		self.setAttribute("normal", new THREE.Float32BufferAttribute(normals, 3));
		self.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2));

		self.attributes.position.needsUpdate = true;
		self.attributes.normal.needsUpdate = true;
		self.attributes.uv.needsUpdate = true;
	});
};
<|endoftext|>


<commit_before>// Let's serve up the data file via json
var http = require( 'http' );
// Let's get the filestream api to write the temp data
var fs = require( 'fs' );
// Let's get the GPIO api for the rpi
var gpio = require( 'rpi-gpio' );
// Global request object for http get/post
var needle = require('needle');

var spiADC = {
	'options': {
		'channel': 0,
		'resistances_to_keep': 100,
		'ignore_data_beyond_pct': 0.05
	},
	'SPI': require( 'spi' ),
	'isOpen': false,
	'device': '',
	'resistances': [],
	'res_index': 0,
	'series_resistor': 10000,
	'thermistor': {
		'nominal_resistance': 10000,
		'nominal_temp': 25,
		'bcoefficient': 3950
	},
	open: function(){
		if(this.isOpen === true){
			console.log( 'Cannot open a device that is already open!' );
			return;
		}

		this.device = new this.SPI.Spi('/dev/spidev0.0', {}, function(s){s.open();});

		this.isOpen = true;
	},
	handleSpiData: function(device, buf){

		var data = ((buf[1]&3) << 8) + buf[2];

		// Let's exclude data readings that are 0
		// and readings that are more than +/- 10% of the previous reading (indicates a spike we should ignore)
		if( data === 0 && Math.abs( ( data - this.resistances[this.resistances.length-1] ) / this.resistances[this.resistances.length-1] ) > this.options.ignore_data_beyond_pct ){
			// Let's discard this reading
			return -1;
		}
		return data;
	},
	storeSpiData: function( device, data ){
		this.resistances[this.res_index] = data;
	},
	setNextResistanceIndex: function(){
		this.res_index++;
		if(this.res_index > (this.options.resistances_to_keep -1) ){
			this.res_index = 0;
		}
	},
	read: function(){
		var self = this;
		var txbuf = new Buffer([1, (8 + this.options.channel) << 4, 0]);
		var rxbuf = new Buffer([ 0x00, 0x00, 0x00 ]);

		this.device.transfer( txbuf, rxbuf, function( device, buf ){
			var data = self.handleSpiData( device, buf );

			if( data > 0 ){
				self.storeSpiData( device, data );
				self.setNextResistanceIndex();
			}
		});
	},
	getAverageData: function(){
		if( this.resistances.length === 0 ){
			return 0;
		}

		var sum = 0;
		for(var i = 0; i < this.resistances.length; i++){
			sum += parseFloat(this.resistances[i]);
		}

		return sum / this.resistances.length;

	},
	calculate_thermistor_resistance: function( average_raw ){
		console.log('average raw: ' + average_raw);

		var thermistor_resistance =  (1023 / average_raw) - 1;
		thermistor_resistance = this.series_resistor / thermistor_resistance;

		return thermistor_resistance;
	},
	steinhart: function( thermistor_resistance ){
		var steinhart = thermistor_resistance / this.thermistor.nominal_resistance;

		steinhart = Math.log( steinhart );
		steinhart = steinhart / this.thermistor.bcoefficient;
		steinhart += 1.0 / (this.thermistor.nominal_temp + 273.15);
		steinhart = 1.0 / steinhart;
		steinhart -= 273.15;

		return steinhart;
	},
	getAverageTemperature: function( average_resistance) {
		var thermistor_resistance = this.calculate_thermistor_resistance( average_resistance );
		var steinhart = this.steinhart( thermistor_resistance );

		console.log('thermistor resistance: ' + thermistor_resistance);
		console.log('thermistor temperature: ' + steinhart);

		return steinhart;
	}
};
var DataLogger = {
	'options': {
		'logfile': '',
		'endpointUrl': 'http://192.168.1.141/dev/test.php',
		'timeout': 5000
	},
	'txError': false,
	'data': [],
	init: function(logfile){
		this.options.logfile = logfile;
		// Return this object to be used once init'd
		return this;
	},
	addDataPoint: function(model){
		this.data.push(model);
	},
	writeDataToFile : function(){
		if( this.txError ) {
			return;
		}

		/* First load in the file contents */
		var self = this;
		fs.readFile(self.options.logfile, {'encoding': 'ascii'}, function (err, data) {
			if (err){
				throw err;
			}

			try{
				var fileData = [];

				if( data !== null && data !== '' ){
					fileData = JSON.parse(data);
				}

				var combinedData = fileData.concat(self.data);

				fs.writeFile(self.options.logfile, JSON.stringify(combinedData), { 'flag' : 'r+'}, function (err) {
					if (err){
						console.log(err);
						throw err;
					}

					self.data = [];
					console.log('It\'s saved!');
				});
			}catch( err ){
				//
			}
		});

	},
	readDataFile : function(){
		return fs.readFileSync(this.options.logfile, {'encoding': 'ascii'} );
	},
	sendDataUpdate: function(){
		var self = this;

		if( self.data.length === 0 ){
			return;
		}

		var postData = {
			payload: {
				value: JSON.stringify(self.data),
				content_type: 'application/json'
			}
		};

		needle.post( self.options.endpointUrl, postData, { timeout: self.options.timeout, multipart: true },
			function (error, response, body) {
				if (error || response.statusCode != 200) {
					/* We've got an error to deal with, let's set the error code till we get a successful send */
					self.txError = true;
				}else{
					self.txError = false;
				}
			}
		);
	}
};

var DataPointModel = {
	create: function(timestamp, data){
		return [timestamp, data];
	}
};

// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(function (request, response) {
	response.writeHead( 200, {
		'Content-Type': 'application/json'
	});

	response.end( DataLogger.readDataFile() );
});

// Listen on port 8000, IP defaults to 127.0.0.1
server.listen(8000);

DataLogger.init( '/home/pi/thermo-app/data/readings.data' );

/* Open the spi device */
spiADC.open();
/* Start reading the data from the spi device every XX ms */
setInterval( function(){ spiADC.read(); }, 33);
/* Let's get an average every XX ms */
setInterval( function(){
	var averageData = spiADC.getAverageData();
	var averageTemp = Math.round( spiADC.getAverageTemperature( averageData ) * 100 ) / 100;
	var model = DataPointModel.create( Math.round(new Date().getTime() / 1000), averageTemp );
	DataLogger.addDataPoint(model);
}, 2000);
/* Write the data we've captured to the data file and send our updates to the web app */
setInterval( function(){
	DataLogger.sendDataUpdate();
	DataLogger.writeDataToFile();
}, 60000);<commit_msg>tweaking when I round<commit_after>// Let's serve up the data file via json
var http = require( 'http' );
// Let's get the filestream api to write the temp data
var fs = require( 'fs' );
// Let's get the GPIO api for the rpi
var gpio = require( 'rpi-gpio' );
// Global request object for http get/post
var needle = require('needle');

var spiADC = {
	'options': {
		'channel': 0,
		'resistances_to_keep': 200,
		'ignore_data_beyond_pct': 0.02
	},
	'SPI': require( 'spi' ),
	'isOpen': false,
	'device': '',
	'resistances': [],
	'res_index': 0,
	'series_resistor': 10000,
	'thermistor': {
		'nominal_resistance': 10000,
		'nominal_temp': 25,
		'bcoefficient': 3950
	},
	open: function(){
		if(this.isOpen === true){
			console.log( 'Cannot open a device that is already open!' );
			return;
		}

		this.device = new this.SPI.Spi('/dev/spidev0.0', {}, function(s){s.open();});

		this.isOpen = true;
	},
	handleSpiData: function(device, buf){

		var data = ((buf[1]&3) << 8) + buf[2];

		// Let's exclude data readings that are 0
		// and readings that are more than +/- 10% of the previous reading (indicates a spike we should ignore)
		if( data === 0 && Math.abs( ( data - this.resistances[this.resistances.length-1] ) / this.resistances[this.resistances.length-1] ) > this.options.ignore_data_beyond_pct ){
			// Let's discard this reading
			return -1;
		}
		return data;
	},
	storeSpiData: function( device, data ){
		this.resistances[this.res_index] = data;
	},
	setNextResistanceIndex: function(){
		this.res_index++;
		if(this.res_index > (this.options.resistances_to_keep -1) ){
			this.res_index = 0;
		}
	},
	read: function(){
		var self = this;
		var txbuf = new Buffer([1, (8 + this.options.channel) << 4, 0]);
		var rxbuf = new Buffer([ 0x00, 0x00, 0x00 ]);

		this.device.transfer( txbuf, rxbuf, function( device, buf ){
			var data = self.handleSpiData( device, buf );

			if( data > 0 ){
				self.storeSpiData( device, data );
				self.setNextResistanceIndex();
			}
		});
	},
	getAverageData: function(){
		if( this.resistances.length === 0 ){
			return 0;
		}

		var sum = 0;
		for(var i = 0; i < this.resistances.length; i++){
			sum += parseFloat(this.resistances[i]);
		}

		return sum / this.resistances.length;

	},
	calculate_thermistor_resistance: function( average_raw ){
		console.log('average raw: ' + average_raw);

		var thermistor_resistance =  (1023 / average_raw) - 1;
		thermistor_resistance = this.series_resistor / thermistor_resistance;

		return thermistor_resistance;
	},
	steinhart: function( thermistor_resistance ){
		var steinhart = thermistor_resistance / this.thermistor.nominal_resistance;

		steinhart = Math.log( steinhart );
		steinhart = steinhart / this.thermistor.bcoefficient;
		steinhart += 1.0 / (this.thermistor.nominal_temp + 273.15);
		steinhart = 1.0 / steinhart;
		steinhart -= 273.15;

		return steinhart;
	},
	getAverageTemperature: function( average_resistance) {
		var thermistor_resistance = this.calculate_thermistor_resistance( average_resistance );
		var steinhart = this.steinhart( thermistor_resistance );

		console.log('thermistor resistance: ' + thermistor_resistance);
		console.log('thermistor temperature: ' + steinhart);

		return steinhart;
	}
};
var DataLogger = {
	'options': {
		'logfile': '',
		'endpointUrl': 'http://192.168.1.141/dev/test.php',
		'timeout': 5000
	},
	'txError': false,
	'data': [],
	init: function(logfile){
		this.options.logfile = logfile;
		// Return this object to be used once init'd
		return this;
	},
	addDataPoint: function(model){
		this.data.push(model);
	},
	writeDataToFile : function(){
		if( this.txError ) {
			return;
		}

		/* First load in the file contents */
		var self = this;
		fs.readFile(self.options.logfile, {'encoding': 'ascii'}, function (err, data) {
			if (err){
				throw err;
			}

			try{
				var fileData = [];

				if( data !== null && data !== '' ){
					fileData = JSON.parse(data);
				}

				var combinedData = fileData.concat(self.data);

				fs.writeFile(self.options.logfile, JSON.stringify(combinedData), { 'flag' : 'r+'}, function (err) {
					if (err){
						console.log(err);
						throw err;
					}

					self.data = [];
					console.log('It\'s saved!');
				});
			}catch( err ){
				//
			}
		});

	},
	readDataFile : function(){
		return fs.readFileSync(this.options.logfile, {'encoding': 'ascii'} );
	},
	sendDataUpdate: function(){
		var self = this;

		if( self.data.length === 0 ){
			return;
		}

		var postData = {
			payload: {
				value: JSON.stringify(self.data),
				content_type: 'application/json'
			}
		};

		needle.post( self.options.endpointUrl, postData, { timeout: self.options.timeout, multipart: true },
			function (error, response, body) {
				if (error || response.statusCode != 200) {
					/* We've got an error to deal with, let's set the error code till we get a successful send */
					self.txError = true;
				}else{
					self.txError = false;
				}
			}
		);
	}
};

var DataPointModel = {
	create: function(timestamp, data){
		return [timestamp, data];
	}
};

// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(function (request, response) {
	response.writeHead( 200, {
		'Content-Type': 'application/json'
	});

	response.end( DataLogger.readDataFile() );
});

// Listen on port 8000, IP defaults to 127.0.0.1
server.listen(8000);

DataLogger.init( '/home/pi/thermo-app/data/readings.data' );

/* Open the spi device */
spiADC.open();
/* Start reading the data from the spi device every XX ms */
setInterval( function(){ spiADC.read(); }, 33);
/* Let's get an average every XX ms */
setInterval( function(){
	var averageData = spiADC.getAverageData();
	var averageTemp = Math.round( spiADC.getAverageTemperature( averageData ) * 100 ) / 100;
	var model = DataPointModel.create( Math.round(new Date().getTime() / 1000), averageTemp );
	DataLogger.addDataPoint(model);
}, 2000);
/* Write the data we've captured to the data file and send our updates to the web app */
setInterval( function(){
	DataLogger.sendDataUpdate();
	DataLogger.writeDataToFile();
}, 60000);<|endoftext|>


<commit_before>var ed = require('ed25519'),
	ByteBuffer = require("bytebuffer"),
	crypto = require('crypto'),
	constants = require("../helpers/constants.js"),
	slots = require('../helpers/slots.js'),
	Router = require('../helpers/router.js'),
	async = require('async'),
	TransactionTypes = require('../helpers/transaction-types.js'),
	MilestoneBlocks = require("../helpers/milestoneBlocks.js"),
	sandboxHelper = require('../helpers/sandbox.js');

// Private fields
var modules, library, self, private = {}, shared = {};

function Signature() {
	this.create = function (data, trs) {
		trs.recipientId = null;
		trs.amount = 0;
		trs.asset.signature = {
			publicKey: data.secondKeypair.publicKey.toString('hex')
		};

		return trs;
	}

	this.calculateFee = function (trs, sender) {
		return 5 * constants.fixedPoint;
	}

	this.verify = function (trs, sender, cb) {
		if (!trs.asset.signature) {
			return setImmediate(cb, "Invalid transaction asset")
		}

		if (trs.amount != 0) {
			return setImmediate(cb, "Invalid transaction amount");
		}

		try {
			if (!trs.asset.signature.publicKey || new Buffer(trs.asset.signature.publicKey, 'hex').length != 32) {
				return setImmediate(cb, "Invalid signature length");
			}
		} catch (e) {
			return setImmediate(cb, "Invalid signature hex");
		}

		setImmediate(cb, null, trs);
	}

	this.process = function (trs, sender, cb) {
		setImmediate(cb, null, trs);
	}

	this.getBytes = function (trs) {
		try {
			var bb = new ByteBuffer(32, true);
			var publicKeyBuffer = new Buffer(trs.asset.signature.publicKey, 'hex');

			for (var i = 0; i < publicKeyBuffer.length; i++) {
				bb.writeByte(publicKeyBuffer[i]);
			}

			bb.flip();
		} catch (e) {
			throw Error(e.toString());
		}
		return bb.toBuffer();
	}

	this.apply = function (trs, block, sender, cb) {
		modules.accounts.setAccountAndGet({
			address: sender.address,
			secondSignature: 1,
			u_secondSignature: 0,
			secondPublicKey: trs.asset.signature.publicKey
		}, cb);
	}

	this.undo = function (trs, block, sender, cb) {
		modules.accounts.setAccountAndGet({
			address: sender.address,
			secondSignature: 0,
			u_secondSignature: 1,
			secondPublicKey: null
		}, cb);
	}

	this.applyUnconfirmed = function (trs, sender, cb) {
		if (sender.u_secondSignature || sender.secondSignature) {
			return setImmediate(cb, "Failed second signature: " + trs.id);
		}

		modules.accounts.setAccountAndGet({address: sender.address, u_secondSignature: 1}, cb);
	}

	this.undoUnconfirmed = function (trs, sender, cb) {
		modules.accounts.setAccountAndGet({address: sender.address, u_secondSignature: 0}, cb);
	}

	this.objectNormalize = function (trs) {
		var report = library.scheme.validate(trs.asset.signature, {
			object: true,
			properties: {
				publicKey: {
					type: 'string',
					format: 'publicKey'
				}
			},
			required: ['publicKey']
		});

		if (!report) {
			throw Error("Can't parse signature: " + library.scheme.getLastError());
		}

		return trs;
	}

	this.dbRead = function (raw) {
		if (!raw.s_publicKey) {
			return null
		} else {
			var signature = {
				transactionId: raw.t_id,
				publicKey: raw.s_publicKey
			}

			return {signature: signature};
		}
	}

	this.dbSave = function (trs, cb) {
		try {
			var publicKey = new Buffer(trs.asset.signature.publicKey, 'hex')
		} catch (e) {
			return cb(e.toString())
		}

		library.dbLite.query("INSERT INTO signatures(transactionId, publicKey) VALUES($transactionId, $publicKey)", {
			transactionId: trs.id,
			publicKey: publicKey
		}, cb);
	}

	this.ready = function (trs, sender) {
		if (sender.multisignatures.length) {
			if (!trs.signatures) {
				return false;
			}
			return trs.signatures.length >= sender.multimin - 1;
		} else {
			return true;
		}
	}
}

// Constructor
function Signatures(cb, scope) {
	library = scope;
	self = this;
	self.__private = private;
	private.attachApi();

	library.logic.transaction.attachAssetType(TransactionTypes.SIGNATURE, new Signature());

	setImmediate(cb, null, self);
}

// Private methods
private.attachApi = function () {
	var router = new Router();

	router.use(function (req, res, next) {
		if (modules) return next();
		res.status(500).send({success: false, error: "Blockchain is loading"});
	});

	router.map(shared, {
		"get /fee": "getFee",
		"put /": "addSignature"
	});

	router.use(function (req, res, next) {
		res.status(500).send({success: false, error: "API endpoint not found"});
	});

	library.network.app.use('/api/signatures', router);
	library.network.app.use(function (err, req, res, next) {
		if (!err) return next();
		library.logger.error(req.url, err.toString());
		res.status(500).send({success: false, error: err.toString()});
	});
}

// Public methods
Signatures.prototype.sandboxApi = function (call, args, cb) {
	sandboxHelper.callMethod(shared, call, args, cb);
}

// Events
Signatures.prototype.onBind = function (scope) {
	modules = scope;
}

// Shared
shared.getFee = function (req, cb) {
	var fee = null;

	fee = 5 * constants.fixedPoint;

	cb(null, {fee: fee})
}

shared.addSignature = function (req, cb) {
	var body = req.body;
	library.scheme.validate(body, {
		type: "object",
		properties: {
			secret: {
				type: "string",
				minLength: 1
			},
			secondSecret: {
				type: "string",
				minLength: 1
			},
			publicKey: {
				type: "string",
				format: "publicKey"
			},
			multisigAccountPublicKey: {
				type: "string",
				format: "publicKey"
			}
		},
		required: ["secret", "secondSecret"]
	}, function (err) {
		if (err) {
			return cb(err[0].message);
		}

		var hash = crypto.createHash('sha256').update(body.secret, 'utf8').digest();
		var keypair = ed.MakeKeypair(hash);

		if (body.publicKey) {
			if (keypair.publicKey.toString('hex') != body.publicKey) {
				return cb("Invalid passphrase");
			}
		}

		library.balancesSequence.add(function (cb) {
			if (body.multisigAccountPublicKey && body.multisigAccountPublicKey != keypair.publicKey.toString('hex')) {
				modules.accounts.getAccount({publicKey: body.multisigAccountPublicKey}, function (err, account) {
					if (err) {
						return cb(err.toString());
					}

					if (!account || !account.publicKey) {
						return cb("Multisignature account not found");
					}

					if (!account.multisignatures || !account.multisignatures) {
						return cb("Account does not have multisignatures enabled");
					}

					if (account.multisignatures.indexOf(keypair.publicKey.toString('hex')) < 0) {
						return cb("Account does not belong to multisignature group");
					}

					if (account.secondSignature || account.u_secondSignature) {
						return cb("Invalid second passphrase");
					}

					modules.accounts.getAccount({publicKey: keypair.publicKey}, function (err, requester) {
						if (err) {
							return cb(err.toString());
						}

						if (!requester || !requester.publicKey) {
							return cb("Invalid requester");
						}

						if (requester.secondSignature && !body.secondSecret) {
							return cb("Invalid second passphrase");
						}

						if (requester.publicKey == account.publicKey) {
							return cb("Invalid requester");
						}

						var secondHash = crypto.createHash('sha256').update(body.secondSecret, 'utf8').digest();
						var secondKeypair = ed.MakeKeypair(secondHash);

						try {
							var transaction = library.logic.transaction.create({
								type: TransactionTypes.SIGNATURE,
								sender: account,
								keypair: keypair,
								requester: keypair,
								secondKeypair: secondKeypair,

							});
						} catch (e) {
							return cb(e.toString());
						}

						modules.transactions.receiveTransactions([transaction], cb);
					});
				});
			} else {
				modules.accounts.getAccount({publicKey: keypair.publicKey.toString('hex')}, function (err, account) {
					if (err) {
						return cb(err.toString());
					}
					if (!account || !account.publicKey) {
						return cb("Account not found");
					}

					if (account.secondSignature || account.u_secondSignature) {
						return cb("Invalid second passphrase");
					}

					var secondHash = crypto.createHash('sha256').update(body.secondSecret, 'utf8').digest();
					var secondKeypair = ed.MakeKeypair(secondHash);

					try {
						var transaction = library.logic.transaction.create({
							type: TransactionTypes.SIGNATURE,
							sender: account,
							keypair: keypair,
							secondKeypair: secondKeypair
						});
					} catch (e) {
						return cb(e.toString());
					}
					modules.transactions.receiveTransactions([transaction], cb);
				});
			}

		}, function (err, transaction) {
			if (err) {
				return cb(err.toString());
			}
			cb(null, {transaction: transaction[0]});
		});

	});
}

module.exports = Signatures;
<commit_msg>Postgres: modules/signatures.js.<commit_after>var ed = require('ed25519'),
	ByteBuffer = require("bytebuffer"),
	crypto = require('crypto'),
	constants = require("../helpers/constants.js"),
	slots = require('../helpers/slots.js'),
	Router = require('../helpers/router.js'),
	async = require('async'),
	TransactionTypes = require('../helpers/transaction-types.js'),
	MilestoneBlocks = require("../helpers/milestoneBlocks.js"),
	sandboxHelper = require('../helpers/sandbox.js');

// Private fields
var modules, library, self, private = {}, shared = {};

function Signature() {
	this.create = function (data, trs) {
		trs.recipientId = null;
		trs.amount = 0;
		trs.asset.signature = {
			publicKey: data.secondKeypair.publicKey.toString('hex')
		};

		return trs;
	}

	this.calculateFee = function (trs, sender) {
		return 5 * constants.fixedPoint;
	}

	this.verify = function (trs, sender, cb) {
		if (!trs.asset.signature) {
			return setImmediate(cb, "Invalid transaction asset")
		}

		if (trs.amount != 0) {
			return setImmediate(cb, "Invalid transaction amount");
		}

		try {
			if (!trs.asset.signature.publicKey || new Buffer(trs.asset.signature.publicKey, 'hex').length != 32) {
				return setImmediate(cb, "Invalid signature length");
			}
		} catch (e) {
			return setImmediate(cb, "Invalid signature hex");
		}

		setImmediate(cb, null, trs);
	}

	this.process = function (trs, sender, cb) {
		setImmediate(cb, null, trs);
	}

	this.getBytes = function (trs) {
		try {
			var bb = new ByteBuffer(32, true);
			var publicKeyBuffer = new Buffer(trs.asset.signature.publicKey, 'hex');

			for (var i = 0; i < publicKeyBuffer.length; i++) {
				bb.writeByte(publicKeyBuffer[i]);
			}

			bb.flip();
		} catch (e) {
			throw Error(e.toString());
		}
		return bb.toBuffer();
	}

	this.apply = function (trs, block, sender, cb) {
		modules.accounts.setAccountAndGet({
			address: sender.address,
			secondSignature: 1,
			u_secondSignature: 0,
			secondPublicKey: trs.asset.signature.publicKey
		}, cb);
	}

	this.undo = function (trs, block, sender, cb) {
		modules.accounts.setAccountAndGet({
			address: sender.address,
			secondSignature: 0,
			u_secondSignature: 1,
			secondPublicKey: null
		}, cb);
	}

	this.applyUnconfirmed = function (trs, sender, cb) {
		if (sender.u_secondSignature || sender.secondSignature) {
			return setImmediate(cb, "Failed second signature: " + trs.id);
		}

		modules.accounts.setAccountAndGet({address: sender.address, u_secondSignature: 1}, cb);
	}

	this.undoUnconfirmed = function (trs, sender, cb) {
		modules.accounts.setAccountAndGet({address: sender.address, u_secondSignature: 0}, cb);
	}

	this.objectNormalize = function (trs) {
		var report = library.scheme.validate(trs.asset.signature, {
			object: true,
			properties: {
				publicKey: {
					type: 'string',
					format: 'publicKey'
				}
			},
			required: ['publicKey']
		});

		if (!report) {
			throw Error("Can't parse signature: " + library.scheme.getLastError());
		}

		return trs;
	}

	this.dbRead = function (raw) {
		if (!raw.s_publicKey) {
			return null
		} else {
			var signature = {
				transactionId: raw.t_id,
				publicKey: raw.s_publicKey
			}

			return {signature: signature};
		}
	}

	this.dbSave = function (trs) {
		try {
			var publicKey = new Buffer(trs.asset.signature.publicKey, 'hex')
		} catch (e) {
			throw e.toString();
		}

		return {
			query: "INSERT INTO signatures(\"transactionId\", \"publicKey\") VALUES(${transactionId}, DECODE(${publicKey}, 'hex'))",
			values: {
				transactionId: trs.id,
				publicKey: publicKey
			}
		};
	}

	this.ready = function (trs, sender) {
		if (sender.multisignatures && sender.multisignatures.length) {
			if (!trs.signatures) {
				return false;
			}
			return trs.signatures.length >= sender.multimin - 1;
		} else {
			return true;
		}
	}
}

// Constructor
function Signatures(cb, scope) {
	library = scope;
	self = this;
	self.__private = private;
	private.attachApi();

	library.logic.transaction.attachAssetType(TransactionTypes.SIGNATURE, new Signature());

	setImmediate(cb, null, self);
}

// Private methods
private.attachApi = function () {
	var router = new Router();

	router.use(function (req, res, next) {
		if (modules) return next();
		res.status(500).send({success: false, error: "Blockchain is loading"});
	});

	router.map(shared, {
		"get /fee": "getFee",
		"put /": "addSignature"
	});

	router.use(function (req, res, next) {
		res.status(500).send({success: false, error: "API endpoint not found"});
	});

	library.network.app.use('/api/signatures', router);
	library.network.app.use(function (err, req, res, next) {
		if (!err) return next();
		library.logger.error(req.url, err.toString());
		res.status(500).send({success: false, error: err.toString()});
	});
}

// Public methods
Signatures.prototype.sandboxApi = function (call, args, cb) {
	sandboxHelper.callMethod(shared, call, args, cb);
}

// Events
Signatures.prototype.onBind = function (scope) {
	modules = scope;
}

// Shared
shared.getFee = function (req, cb) {
	var fee = null;

	fee = 5 * constants.fixedPoint;

	cb(null, {fee: fee})
}

shared.addSignature = function (req, cb) {
	var body = req.body;
	library.scheme.validate(body, {
		type: "object",
		properties: {
			secret: {
				type: "string",
				minLength: 1
			},
			secondSecret: {
				type: "string",
				minLength: 1
			},
			publicKey: {
				type: "string",
				format: "publicKey"
			},
			multisigAccountPublicKey: {
				type: "string",
				format: "publicKey"
			}
		},
		required: ["secret", "secondSecret"]
	}, function (err) {
		if (err) {
			return cb(err[0].message);
		}

		var hash = crypto.createHash('sha256').update(body.secret, 'utf8').digest();
		var keypair = ed.MakeKeypair(hash);

		if (body.publicKey) {
			if (keypair.publicKey.toString('hex') != body.publicKey) {
				return cb("Invalid passphrase");
			}
		}

		library.balancesSequence.add(function (cb) {
			if (body.multisigAccountPublicKey && body.multisigAccountPublicKey != keypair.publicKey.toString('hex')) {
				modules.accounts.getAccount({publicKey: body.multisigAccountPublicKey}, function (err, account) {
					if (err) {
						return cb(err.toString());
					}

					if (!account || !account.publicKey) {
						return cb("Multisignature account not found");
					}

					if (!account.multisignatures || !account.multisignatures) {
						return cb("Account does not have multisignatures enabled");
					}

					if (account.multisignatures.indexOf(keypair.publicKey.toString('hex')) < 0) {
						return cb("Account does not belong to multisignature group");
					}

					if (account.secondSignature || account.u_secondSignature) {
						return cb("Invalid second passphrase");
					}

					modules.accounts.getAccount({publicKey: keypair.publicKey}, function (err, requester) {
						if (err) {
							return cb(err.toString());
						}

						if (!requester || !requester.publicKey) {
							return cb("Invalid requester");
						}

						if (requester.secondSignature && !body.secondSecret) {
							return cb("Invalid second passphrase");
						}

						if (requester.publicKey == account.publicKey) {
							return cb("Invalid requester");
						}

						var secondHash = crypto.createHash('sha256').update(body.secondSecret, 'utf8').digest();
						var secondKeypair = ed.MakeKeypair(secondHash);

						try {
							var transaction = library.logic.transaction.create({
								type: TransactionTypes.SIGNATURE,
								sender: account,
								keypair: keypair,
								requester: keypair,
								secondKeypair: secondKeypair,

							});
						} catch (e) {
							return cb(e.toString());
						}

						modules.transactions.receiveTransactions([transaction], cb);
					});
				});
			} else {
				modules.accounts.getAccount({publicKey: keypair.publicKey.toString('hex')}, function (err, account) {
					if (err) {
						return cb(err.toString());
					}
					if (!account || !account.publicKey) {
						return cb("Account not found");
					}

					if (account.secondSignature || account.u_secondSignature) {
						return cb("Invalid second passphrase");
					}

					var secondHash = crypto.createHash('sha256').update(body.secondSecret, 'utf8').digest();
					var secondKeypair = ed.MakeKeypair(secondHash);

					try {
						var transaction = library.logic.transaction.create({
							type: TransactionTypes.SIGNATURE,
							sender: account,
							keypair: keypair,
							secondKeypair: secondKeypair
						});
					} catch (e) {
						return cb(e.toString());
					}
					modules.transactions.receiveTransactions([transaction], cb);
				});
			}

		}, function (err, transaction) {
			if (err) {
				return cb(err.toString());
			}
			cb(null, {transaction: transaction[0]});
		});

	});
}

module.exports = Signatures;
<|endoftext|>


<commit_before>/*
Copyright 2014 OCAD University

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/gpii/universal/LICENSE.txt
*/

var fluid = fluid || require("infusion");
var jqUnit = fluid.require("jqUnit");
require("../inMemoryDatastore.js");

(function () {

    "use strict";

    var gpii = fluid.registerNamespace("gpii");
    fluid.registerNamespace("gpii.tests.oauth2.datastore");
    fluid.registerNamespace("gpii.tests.oauth2.datastore.testdata");

    fluid.defaults("gpii.tests.oauth2.datastore.datastoreWithTestData", {
        gradeNames: ["gpii.oauth2.inMemoryDatastore", "autoInit"],
        model: {
            users: [
                { id: 1, username: "alice", password: "a" },
                { id: 2, username: "bob", password: "b" }
            ],
            clients: [
                {
                    id: 1,
                    name: "Client A",
                    oauth2ClientId: "client_id_A",
                    oauth2ClientSecret: "client_secret_A",
                    redirectUri: "http://example.com/callback_A"
                },
                {
                    id: 2,
                    name: "Client B",
                    oauth2ClientId: "client_id_B",
                    oauth2ClientSecret: "client_secret_B",
                    redirectUri: "http://example.com/callback_B"
                }
            ]
        }
    });

    gpii.tests.oauth2.datastore.testdata.authDecision1 = {
        userId: 1,
        clientId: 2,
        redirectUri: "http://example.com/callback",
        accessToken: "access_token_1"
    };

    gpii.tests.oauth2.datastore.verifyAlice = function (user) {
        jqUnit.assertEquals("username is alice", "alice", user.username);
        jqUnit.assertEquals("password is a", "a", user.password);
    };

    gpii.tests.oauth2.datastore.verifyBob = function (user) {
        jqUnit.assertEquals("username is bob", "bob", user.username);
        jqUnit.assertEquals("password is b", "b", user.password);
    };

    gpii.tests.oauth2.datastore.verifyClientA = function (client) {
        jqUnit.assertEquals("name", "Client A", client.name);
        jqUnit.assertEquals("oauth2ClientId", "client_id_A", client.oauth2ClientId);
        jqUnit.assertEquals("oauth2ClientSecret", "client_secret_A", client.oauth2ClientSecret);
        jqUnit.assertEquals("redirectUri", "http://example.com/callback_A", client.redirectUri);
    };

    gpii.tests.oauth2.datastore.verifyClientB = function (client) {
        jqUnit.assertEquals("name", "Client B", client.name);
        jqUnit.assertEquals("oauth2ClientId", "client_id_B", client.oauth2ClientId);
        jqUnit.assertEquals("oauth2ClientSecret", "client_secret_B", client.oauth2ClientSecret);
        jqUnit.assertEquals("redirectUri", "http://example.com/callback_B", client.redirectUri);
    };

    gpii.tests.oauth2.datastore.saveAuthDecision1 = function (datastore) {
        return datastore.saveAuthDecision(gpii.tests.oauth2.datastore.testdata.authDecision1.userId,
            gpii.tests.oauth2.datastore.testdata.authDecision1.clientId,
            gpii.tests.oauth2.datastore.testdata.authDecision1.redirectUri,
            gpii.tests.oauth2.datastore.testdata.authDecision1.accessToken);
    };

    gpii.tests.oauth2.datastore.findAuthDecision1 = function (datastore) {
        return datastore.findAuthDecision(gpii.tests.oauth2.datastore.testdata.authDecision1.userId,
            gpii.tests.oauth2.datastore.testdata.authDecision1.clientId,
            gpii.tests.oauth2.datastore.testdata.authDecision1.redirectUri);
    };

    gpii.tests.oauth2.datastore.verifyAuthDecision1 = function (authDecision) {
        jqUnit.assertEquals("userId", gpii.tests.oauth2.datastore.testdata.authDecision1.userId, authDecision.userId);
        jqUnit.assertEquals("clientId", gpii.tests.oauth2.datastore.testdata.authDecision1.clientId, authDecision.clientId);
        jqUnit.assertEquals("redirectUri", gpii.tests.oauth2.datastore.testdata.authDecision1.redirectUri, authDecision.redirectUri);
        jqUnit.assertEquals("accessToken", gpii.tests.oauth2.datastore.testdata.authDecision1.accessToken, authDecision.accessToken);
        jqUnit.assertFalse("not revoked", authDecision.revoked);
    };

    gpii.tests.oauth2.datastore.revokeAuthDecision1 = function (datastore, authDecisionId) {
        datastore.revokeAuthDecision(gpii.tests.oauth2.datastore.testdata.authDecision1.userId,
            authDecisionId);
    };

    gpii.tests.oauth2.datastore.saveAuthCode1 = function (datastore, authDecisionId) {
        datastore.saveAuthCode(authDecisionId, "code_1");
    };

    gpii.tests.oauth2.datastore.findAuthByCode1 = function (datastore) {
        return datastore.findAuthByCode("code_1");
    };

    gpii.tests.oauth2.datastore.verifyAuthForCode1 = function (auth) {
        jqUnit.assertEquals("clientId",
            gpii.tests.oauth2.datastore.testdata.authDecision1.clientId,
            auth.clientId);
        jqUnit.assertEquals("redirectUri",
            gpii.tests.oauth2.datastore.testdata.authDecision1.redirectUri,
            auth.redirectUri);
        jqUnit.assertEquals("accessToken",
            gpii.tests.oauth2.datastore.testdata.authDecision1.accessToken,
            auth.accessToken);
    };

    jqUnit.module("GPII OAuth2 data store");

    jqUnit.test("findUserById() returns the user for existing id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        gpii.tests.oauth2.datastore.verifyAlice(datastore.findUserById(1));
        gpii.tests.oauth2.datastore.verifyBob(datastore.findUserById(2));
    });

    jqUnit.test("findUserById() returns falsey for non-existing id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing user is falsey", datastore.findUserById(-1));
    });

    jqUnit.test("findUserByUsername() returns the user for existing username", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        gpii.tests.oauth2.datastore.verifyAlice(datastore.findUserByUsername("alice"));
        gpii.tests.oauth2.datastore.verifyBob(datastore.findUserByUsername("bob"));
    });

    jqUnit.test("findUserByUsername() returns falsey for non-existing username", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing user is falsey", datastore.findUserByUsername("NON-EXISTING"));
    });

    jqUnit.test("findClientById() returns the client for existing id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        gpii.tests.oauth2.datastore.verifyClientA(datastore.findClientById(1));
        gpii.tests.oauth2.datastore.verifyClientB(datastore.findClientById(2));
    });

    jqUnit.test("findClientById() returns falsey for non-existing id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing client is falsey", datastore.findClientById(-1));
    });

    jqUnit.test("findClientByOauth2ClientId() returns the client for existing client_id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        gpii.tests.oauth2.datastore.verifyClientA(datastore.findClientByOauth2ClientId("client_id_A"));
        gpii.tests.oauth2.datastore.verifyClientB(datastore.findClientByOauth2ClientId("client_id_B"));
    });

    jqUnit.test("findClientByOauth2ClientId() returns falsey for non-existing client_id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing client is falsey", datastore.findClientByOauth2ClientId("NON-EXISTING"));
    });

    jqUnit.test("saveAuthDecision() assigns an id and returns the new entity", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        var authDecision1 = gpii.tests.oauth2.datastore.saveAuthDecision1(datastore);
        gpii.tests.oauth2.datastore.verifyAuthDecision1(authDecision1);
        jqUnit.assertValue("Id has been assigned", authDecision1.id);
    });

    jqUnit.test("findAuthDecisionById() finds an existing authorization", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        var authDecision1 = gpii.tests.oauth2.datastore.saveAuthDecision1(datastore);
        var retrieved = datastore.findAuthDecisionById(authDecision1.id);
        gpii.tests.oauth2.datastore.verifyAuthDecision1(retrieved);
    });

    jqUnit.test("findAuthDecisionById() returns falsey for non-existing authorization", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing authDecision is falsey",
            datastore.findAuthDecisionById(-1));
    });

    jqUnit.test("findAuthDecision() finds an existing authorization, but not revoked", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        // save
        var authDecision1 = gpii.tests.oauth2.datastore.saveAuthDecision1(datastore);
        // find and verify
        gpii.tests.oauth2.datastore.verifyAuthDecision1(gpii.tests.oauth2.datastore.findAuthDecision1(datastore));
        // revoke
        gpii.tests.oauth2.datastore.revokeAuthDecision1(datastore, authDecision1.id);
        // verify no longer found
        jqUnit.assertFalse("revoked authDecision is falsey",
            gpii.tests.oauth2.datastore.findAuthDecision1(datastore));
    });

    jqUnit.test("findAuthDecision() returns falsey for non-existing authorization", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing authDecision is falsey",
            gpii.tests.oauth2.datastore.findAuthDecision1(datastore));
    });

    jqUnit.test("saveAuthCode(), verify findAuthByCode(), revoke, and then verify no longer found", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        // save authDecision and authCode
        var authDecision1 = gpii.tests.oauth2.datastore.saveAuthDecision1(datastore);
        gpii.tests.oauth2.datastore.saveAuthCode1(datastore, authDecision1.id);
        // find and verify
        gpii.tests.oauth2.datastore.verifyAuthForCode1(gpii.tests.oauth2.datastore.findAuthByCode1(datastore));
        // revoke authorization
        gpii.tests.oauth2.datastore.revokeAuthDecision1(datastore, authDecision1.id);
        // verify no longer found
        jqUnit.assertFalse("revoked authorization is falsey", gpii.tests.oauth2.datastore.findAuthByCode1(datastore));
    });

})();
<commit_msg>Datastore findAuthorizedClientsByUserId() test<commit_after>/*
Copyright 2014 OCAD University

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/gpii/universal/LICENSE.txt
*/

var fluid = fluid || require("infusion");
var jqUnit = fluid.require("jqUnit");
require("../inMemoryDatastore.js");

(function () {

    "use strict";

    var gpii = fluid.registerNamespace("gpii");
    fluid.registerNamespace("gpii.tests.oauth2.datastore");
    fluid.registerNamespace("gpii.tests.oauth2.datastore.testdata");

    fluid.defaults("gpii.tests.oauth2.datastore.datastoreWithTestData", {
        gradeNames: ["gpii.oauth2.inMemoryDatastore", "autoInit"],
        model: {
            users: [
                { id: 1, username: "alice", password: "a" },
                { id: 2, username: "bob", password: "b" }
            ],
            clients: [
                {
                    id: 1,
                    name: "Client A",
                    oauth2ClientId: "client_id_A",
                    oauth2ClientSecret: "client_secret_A",
                    redirectUri: "http://example.com/callback_A"
                },
                {
                    id: 2,
                    name: "Client B",
                    oauth2ClientId: "client_id_B",
                    oauth2ClientSecret: "client_secret_B",
                    redirectUri: "http://example.com/callback_B"
                },
                {
                    id: 3,
                    name: "Client C",
                    oauth2ClientId: "client_id_C",
                    oauth2ClientSecret: "client_secret_C",
                    redirectUri: "http://example.com/callback_C"
                }
            ]
        }
    });

    gpii.tests.oauth2.datastore.testdata.userId1 = 1;

    gpii.tests.oauth2.datastore.testdata.authDecision1 = {
        userId: gpii.tests.oauth2.datastore.testdata.userId1,
        clientId: 2,
        redirectUri: "http://example.com/callback_B",
        accessToken: "access_token_1"
    };

    gpii.tests.oauth2.datastore.testdata.authDecision2 = {
        userId: gpii.tests.oauth2.datastore.testdata.userId1,
        clientId: 3,
        redirectUri: "http://example.com/callback_C",
        accessToken: "access_token_2"
    };

    gpii.tests.oauth2.datastore.testdata.authDecision3 = {
        userId: gpii.tests.oauth2.datastore.testdata.userId1,
        clientId: 2,
        redirectUri: "http://example.com/callback_B",
        accessToken: "access_token_3"
    };

    gpii.tests.oauth2.datastore.verifyAlice = function (user) {
        jqUnit.assertEquals("username is alice", "alice", user.username);
        jqUnit.assertEquals("password is a", "a", user.password);
    };

    gpii.tests.oauth2.datastore.verifyBob = function (user) {
        jqUnit.assertEquals("username is bob", "bob", user.username);
        jqUnit.assertEquals("password is b", "b", user.password);
    };

    gpii.tests.oauth2.datastore.verifyClientA = function (client) {
        jqUnit.assertEquals("name", "Client A", client.name);
        jqUnit.assertEquals("oauth2ClientId", "client_id_A", client.oauth2ClientId);
        jqUnit.assertEquals("oauth2ClientSecret", "client_secret_A", client.oauth2ClientSecret);
        jqUnit.assertEquals("redirectUri", "http://example.com/callback_A", client.redirectUri);
    };

    gpii.tests.oauth2.datastore.verifyClientB = function (client) {
        jqUnit.assertEquals("name", "Client B", client.name);
        jqUnit.assertEquals("oauth2ClientId", "client_id_B", client.oauth2ClientId);
        jqUnit.assertEquals("oauth2ClientSecret", "client_secret_B", client.oauth2ClientSecret);
        jqUnit.assertEquals("redirectUri", "http://example.com/callback_B", client.redirectUri);
    };

    gpii.tests.oauth2.datastore.saveAuthDecision = function (datastore, authDecision) {
        return datastore.saveAuthDecision(authDecision.userId, authDecision.clientId,
            authDecision.redirectUri, authDecision.accessToken);
    };

    gpii.tests.oauth2.datastore.saveAuthDecision1 = function (datastore) {
        return gpii.tests.oauth2.datastore.saveAuthDecision(datastore,
            gpii.tests.oauth2.datastore.testdata.authDecision1);
    };

    gpii.tests.oauth2.datastore.saveAuthDecision2 = function (datastore) {
        return gpii.tests.oauth2.datastore.saveAuthDecision(datastore,
            gpii.tests.oauth2.datastore.testdata.authDecision2);
    };

    gpii.tests.oauth2.datastore.saveAuthDecision3 = function (datastore) {
        return gpii.tests.oauth2.datastore.saveAuthDecision(datastore,
            gpii.tests.oauth2.datastore.testdata.authDecision3);
    };

    gpii.tests.oauth2.datastore.findAuthDecision1 = function (datastore) {
        return datastore.findAuthDecision(gpii.tests.oauth2.datastore.testdata.authDecision1.userId,
            gpii.tests.oauth2.datastore.testdata.authDecision1.clientId,
            gpii.tests.oauth2.datastore.testdata.authDecision1.redirectUri);
    };

    gpii.tests.oauth2.datastore.verifyAuthDecision1 = function (authDecision) {
        jqUnit.assertEquals("userId", gpii.tests.oauth2.datastore.testdata.authDecision1.userId, authDecision.userId);
        jqUnit.assertEquals("clientId", gpii.tests.oauth2.datastore.testdata.authDecision1.clientId, authDecision.clientId);
        jqUnit.assertEquals("redirectUri", gpii.tests.oauth2.datastore.testdata.authDecision1.redirectUri, authDecision.redirectUri);
        jqUnit.assertEquals("accessToken", gpii.tests.oauth2.datastore.testdata.authDecision1.accessToken, authDecision.accessToken);
        jqUnit.assertFalse("not revoked", authDecision.revoked);
    };

    gpii.tests.oauth2.datastore.saveAuthCode1 = function (datastore, authDecisionId) {
        datastore.saveAuthCode(authDecisionId, "code_1");
    };

    gpii.tests.oauth2.datastore.findAuthByCode1 = function (datastore) {
        return datastore.findAuthByCode("code_1");
    };

    gpii.tests.oauth2.datastore.verifyAuthorizedClientB = function (authClient, authDecisionId) {
        jqUnit.assertEquals("authDecisionId", authDecisionId, authClient.authDecisionId);
        jqUnit.assertEquals("clientName", "Client B", authClient.clientName);
    };

    gpii.tests.oauth2.datastore.verifyAuthorizedClientC = function (authClient, authDecisionId) {
        jqUnit.assertEquals("authDecisionId", authDecisionId, authClient.authDecisionId);
        jqUnit.assertEquals("clientName", "Client C", authClient.clientName);
    };

    jqUnit.module("GPII OAuth2 data store");

    jqUnit.test("findUserById() returns the user for existing id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        gpii.tests.oauth2.datastore.verifyAlice(datastore.findUserById(1));
        gpii.tests.oauth2.datastore.verifyBob(datastore.findUserById(2));
    });

    jqUnit.test("findUserById() returns falsey for non-existing id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing user is falsey", datastore.findUserById(-1));
    });

    jqUnit.test("findUserByUsername() returns the user for existing username", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        gpii.tests.oauth2.datastore.verifyAlice(datastore.findUserByUsername("alice"));
        gpii.tests.oauth2.datastore.verifyBob(datastore.findUserByUsername("bob"));
    });

    jqUnit.test("findUserByUsername() returns falsey for non-existing username", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing user is falsey", datastore.findUserByUsername("NON-EXISTING"));
    });

    jqUnit.test("findClientById() returns the client for existing id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        gpii.tests.oauth2.datastore.verifyClientA(datastore.findClientById(1));
        gpii.tests.oauth2.datastore.verifyClientB(datastore.findClientById(2));
    });

    jqUnit.test("findClientById() returns falsey for non-existing id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing client is falsey", datastore.findClientById(-1));
    });

    jqUnit.test("findClientByOauth2ClientId() returns the client for existing client_id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        gpii.tests.oauth2.datastore.verifyClientA(datastore.findClientByOauth2ClientId("client_id_A"));
        gpii.tests.oauth2.datastore.verifyClientB(datastore.findClientByOauth2ClientId("client_id_B"));
    });

    jqUnit.test("findClientByOauth2ClientId() returns falsey for non-existing client_id", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing client is falsey", datastore.findClientByOauth2ClientId("NON-EXISTING"));
    });

    jqUnit.test("saveAuthDecision() assigns an id and returns the new entity", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        var authDecision1 = gpii.tests.oauth2.datastore.saveAuthDecision1(datastore);
        gpii.tests.oauth2.datastore.verifyAuthDecision1(authDecision1);
        jqUnit.assertValue("Id has been assigned", authDecision1.id);
    });

    jqUnit.test("findAuthDecisionById() finds an existing authorization", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        var authDecision1 = gpii.tests.oauth2.datastore.saveAuthDecision1(datastore);
        var retrieved = datastore.findAuthDecisionById(authDecision1.id);
        gpii.tests.oauth2.datastore.verifyAuthDecision1(retrieved);
    });

    jqUnit.test("findAuthDecisionById() returns falsey for non-existing authorization", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing authDecision is falsey",
            datastore.findAuthDecisionById(-1));
    });

    jqUnit.test("findAuthDecision() finds an existing authorization and falsey for revoked", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        // save
        var authDecision1 = gpii.tests.oauth2.datastore.saveAuthDecision1(datastore);
        // find and verify
        gpii.tests.oauth2.datastore.verifyAuthDecision1(gpii.tests.oauth2.datastore.findAuthDecision1(datastore));
        // revoke
        datastore.revokeAuthDecision(authDecision1.userId, authDecision1.id);
        // verify no longer found
        jqUnit.assertFalse("revoked authDecision is falsey",
            gpii.tests.oauth2.datastore.findAuthDecision1(datastore));
    });

    jqUnit.test("findAuthDecision() returns falsey for non-existing authorization", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        jqUnit.assertFalse("non-existing authDecision is falsey",
            gpii.tests.oauth2.datastore.findAuthDecision1(datastore));
    });

    jqUnit.test("saveAuthCode(), verify findAuthByCode(), revoke, and then verify no longer found", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        // save authDecision and authCode
        var authDecision1 = gpii.tests.oauth2.datastore.saveAuthDecision1(datastore);
        gpii.tests.oauth2.datastore.saveAuthCode1(datastore, authDecision1.id);
        // find and verify
        var auth = gpii.tests.oauth2.datastore.findAuthByCode1(datastore);
        jqUnit.assertEquals("clientId",
            gpii.tests.oauth2.datastore.testdata.authDecision1.clientId,
            auth.clientId);
        jqUnit.assertEquals("redirectUri",
            gpii.tests.oauth2.datastore.testdata.authDecision1.redirectUri,
            auth.redirectUri);
        jqUnit.assertEquals("accessToken",
            gpii.tests.oauth2.datastore.testdata.authDecision1.accessToken,
            auth.accessToken);
        // revoke authorization
        datastore.revokeAuthDecision(authDecision1.userId, authDecision1.id);
        // verify no longer found
        jqUnit.assertFalse("revoked authorization is falsey", gpii.tests.oauth2.datastore.findAuthByCode1(datastore));
    });

    jqUnit.test("findAuthorizedClientsByUserId() with revoking", function () {
        var datastore = gpii.tests.oauth2.datastore.datastoreWithTestData();
        // save authDecisions
        var authDecision1 = gpii.tests.oauth2.datastore.saveAuthDecision1(datastore);
        var authDecision2 = gpii.tests.oauth2.datastore.saveAuthDecision2(datastore);
        var userId = gpii.tests.oauth2.datastore.testdata.userId1;
        // find both clients
        var clients = datastore.findAuthorizedClientsByUserId(userId);
        jqUnit.assertEquals("2 clients", 2, clients.length);
        gpii.tests.oauth2.datastore.verifyAuthorizedClientB(clients[0], authDecision1.id);
        gpii.tests.oauth2.datastore.verifyAuthorizedClientC(clients[1], authDecision2.id);
        // revoke authDecision1
        datastore.revokeAuthDecision(authDecision1.userId, authDecision1.id);
        clients = datastore.findAuthorizedClientsByUserId(userId);
        jqUnit.assertEquals("1 client", 1, clients.length);
        gpii.tests.oauth2.datastore.verifyAuthorizedClientC(clients[0], authDecision2.id);
        // save a new authDecision and verify found
        var authDecision3 = gpii.tests.oauth2.datastore.saveAuthDecision3(datastore);
        clients = datastore.findAuthorizedClientsByUserId(userId);
        jqUnit.assertEquals("2 clients", 2, clients.length);
        gpii.tests.oauth2.datastore.verifyAuthorizedClientC(clients[0], authDecision2.id);
        gpii.tests.oauth2.datastore.verifyAuthorizedClientB(clients[1], authDecision3.id);
        // revoke authDecision2 and authDecision3
        datastore.revokeAuthDecision(authDecision2.userId, authDecision2.id);
        datastore.revokeAuthDecision(authDecision3.userId, authDecision3.id);
        clients = datastore.findAuthorizedClientsByUserId(userId);
        jqUnit.assertEquals("0 clients", 0, clients.length);
    });

})();
<|endoftext|>


<commit_before>/*
 * OpenSpeedMonitor (OSM)
 * Copyright 2014 iteratec GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//= require_tree bower_components/jquery
//= require_tree bower_components/jquery-ui
//= require_tree bower_components/bootstrap
//= require_tree bower_components/bootstrap-colorpicker/dist/js/
//= require_tree bower_components/chosen
//= require_tree bower_components/clipboard
//= require kickstart/checkboxes
//= require spinner
//= require bower_components/bootstrap-validator/js/validator
//= require_self

delete $.fn.datepicker; // so it can be replaced by air-datepicker

/**
 * Global namespace for OpenSpeedMonitor application.
 */
var OpenSpeedMonitor = OpenSpeedMonitor || {};

/**
 * Map for URLs to use
 */
OpenSpeedMonitor.urls = OpenSpeedMonitor.urls || {};

/**
 * Map for i18n to use
 */
OpenSpeedMonitor.i18n = OpenSpeedMonitor.i18n || {};

/**
 * Loads all registered JavaScript files. Used by microservices.
 * @type {Array}
 */
OpenSpeedMonitor.postLoadUrls = OpenSpeedMonitor.postLoadUrls || [];
OpenSpeedMonitor.postLoadUrls.forEach(function (scriptUrl) {
    $.getScript(scriptUrl);
});

OpenSpeedMonitor.postLoader = (function () {

    var head = document.getElementsByTagName("head")[0];

    var loadJavascript = function (url, async, name) {
        async = async || true;
        var script = document.createElement("script");
        script.onload = function () {
            fireWindowEvent("" + name + "Loaded");
        };
        script.setAttribute("src", url);
        script.setAttribute("type", "text/javascript");
        script.setAttribute("async", async);
        //script.setAttribute("charset","ISO-8859-1");
        head.appendChild(script);
    };
    var loadStylesheet = function (url) {
        var link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = url;
        link.media = "all";
        head.appendChild(link);
    };

    return {
        loadJavascript: loadJavascript,
        loadStylesheet: loadStylesheet
    }

})();

/**
 * Global string utilities module.
 */
OpenSpeedMonitor.stringUtils = (function () {
    var stringToBoolean = function (string) {
        if (!string) {
            return false;
        }
        switch (string.toLowerCase()) {
            case "true":
            case "yes":
            case "1":
            case "on":
                return true;
            case "false":
            case "no":
            case "0":
            case "off":
            case null:
                return false;
            default:
                return false;
        }
    };

    var isNumeric = function (string) {
        return !isNaN(string);
    };

    return {
        isNumeric: isNumeric,
        stringToBoolean: stringToBoolean
    };
})();

/**
 * Global module providing functionalities for storage of data in the browser.
 *
 * @returns {{
 *      setCookie: setCookie,
 *      getCookie: getCookie,
 *      setToLocalStorage: setToLocalStorage,
 *      getFromLocalStorage: getFromLocalStorage,
 *      getObjectFromLocalStorage: getObjectFromLocalStorage,
 *      setObjectToLocalStorage: setObjectToLocalStorage}}
 */
OpenSpeedMonitor.clientSideStorageUtils = function () {
    var setCookie = function (key, value, path, shouldExpireInMillisecsFromNow) {
        var expires = new Date();
        expires.setTime(expires.getTime() + shouldExpireInMillisecsFromNow);
        var cookieToSet = key + '=' + btoa(value) + ';expires=' + expires.toUTCString() + ';path=' + path;
        console.log(cookieToSet);
        document.cookie = cookieToSet;
    };

    var getCookie = function (key) {
        var keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
        return keyValue ? atob(keyValue[2]) : null;
    };

    var setToLocalStorage = function (key, value) {
        try {
            localStorage.setItem(key, value)
        } catch (e) {
            console.log('Can\'t write data to local storage: ' + e.message);
        }
    };

    var getFromLocalStorage = function (key) {
        try {
            return localStorage.getItem(key);
        } catch (e) {
            console.log('Can\'t read data from local storage: ' + e.message);
        }
        return null;
    };

    /**
     * Reads a whole object in local storage.
     * @param keyObject An object with different properties whose values are the local storage keys.
     * @return object A new object with the same properties as keyObject and values from the local storage.
     */
    var getObjectFromLocalStorage = function (keyObject) {
        var hasValues = false;
        var values = {};
        for (var property in keyObject) {
            if (keyObject.hasOwnProperty(property)) {
                var value = getFromLocalStorage(keyObject[property]);
                hasValues = hasValues || value !== null;
                values[property] = value;
            }
        }
        return hasValues ? values : null;
    };

    /**
     * Saves a whole object in local storage
     * @param keyObject An object whose properties are the same as in value. The value of each property is the local storage key.
     * @param value The object to save with the same properties as in keyObject.
     */
    var setObjectToLocalStorage = function (keyObject, value) {
        for (var property in keyObject) {
            if (keyObject.hasOwnProperty(property)) {
                setToLocalStorage(keyObject[property], value[property]);
            }
        }
    };

    return {
        setCookie: setCookie,
        getCookie: getCookie,
        setToLocalStorage: setToLocalStorage,
        getFromLocalStorage: getFromLocalStorage,
        getObjectFromLocalStorage: getObjectFromLocalStorage,
        setObjectToLocalStorage: setObjectToLocalStorage
    };
};

OpenSpeedMonitor.urlUtils = (function () {
    var getAllVars = function () {
        var vars = [];
        var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
        for (var i = 0; i < hashes.length; i++) {
            var hash = hashes[i].split('=');
            var key = decodeURIComponent(hash[0]);
            vars.push(key);
            vars[key] = decodeURIComponent(hash[1]);
        }
        return vars;
    };

    var getVar = function (name) {
        return getAllVars()[name];
    };

    return {
        getAllVars: getAllVars,
        getVar: getVar
    };
})();

OpenSpeedMonitor.domUtils = (function () {
    /**
     * Creates option elements by a list of values which all contain an 'id' and a 'name'
     * @param values Array with objects containing id and name
     * @return Array The list of newly created option elements, sorted by name
     */
    var createOptionsByIdAndName = function (values) {
        var options = [];
        if (!values) {
            return [];
        }
        values.sort(function (a, b) {
            return a.name.localeCompare(b.name);
        });
        values.forEach(function (value) {
            if (value && value.id && value.name) {
                options.push($("<option/>", {
                    value: value.id,
                    text: value.name
                }));
            }
        });
        return options;
    };

    /**
     * Gets all values of all option elements in a select element
     * @param selectElement The select element with options as children
     * @returns Array An array with all values of all options
     */
    var getAllOptionValues = function (selectElement) {
        return $.map($(selectElement).find("option"), function (option) {
            return option.value;
        });
    };

    var hasAllOptionsSelected = function (selectElement) {
        selectElement = $(selectElement);
        return selectElement.find(":not(:selected)").length == 0 && selectElement.find("option").length > 0;
    };

    /**
     * Updates a select element with new values
     * @param selectElement The select element to update
     * @param idAndNameList A list of objects with id and name
     * @param noResultsText If set, a disabled option with this text is appended if the idAndNameList is empty
     */
    var updateSelectOptions = function (selectElement, idAndNameList, noResultsText) {
        selectElement = $(selectElement);
        var selection = selectElement.val();
        selectElement.empty();
        selectElement.append(OpenSpeedMonitor.domUtils.createOptionsByIdAndName(idAndNameList));
        if (!selectElement.children().length && noResultsText) {
            selectElement.append($("<option/>", {disabled: "disabled", text: noResultsText}));
        }
        selectElement.val(selection);
    };

    /**
     * Deselects all selected options in a select element
     * @param selectElement The select element
     * @param avoidEvent Optional. If true, no change event will be triggered
     */
    var deselectAllOptions = function (selectElement, avoidEvent) {
        selectElement = $(selectElement);
        selectElement.find("option:selected").removeAttr("selected");
        if (!avoidEvent) {
            selectElement.trigger("change");
        }
    };

    return {
        createOptionsByIdAndName: createOptionsByIdAndName,
        getAllOptionValues: getAllOptionValues,
        hasAllOptionsSelected: hasAllOptionsSelected,
        updateSelectOptions: updateSelectOptions,
        deselectAllOptions: deselectAllOptions
    };
})();

/**
 * This method will just return the given message. We use it,
 * so you can override it for a specialised delete conformation for the given domain
 */
function domainDeleteConfirmation(message, id, link) {
    var confirmMessage = "";
    if (typeof link !== "undefined" && link !== null && link !== "") {
        jQuery.ajax({
            type: 'GET',
            url: link,
            data: {id: id},
            async: false,
            success: function (result) {
                confirmMessage = message + "<br>" + result;
            },
            error: function (result) {
                confirmMessage = message;
            }
        });
        return confirmMessage;
    } else {
        return message;
    }

}

/**
 * Necessary to prevent Chosen dropdown from being cut off in tabs
 * @see http://stackoverflow.com/a/21375637
 * TODO: after first selection dropdown of chosen select disappears after click. So one have to hold the mouse button while selection :(
 */
function fixChosen() {
    var els = $(".chosen");
    els.on("chosen:showing_dropdown", function (event, chosen) {
        $(this).parents("div").css("overflow", "visible");
    });
    els.on("chosen:hiding_dropdown", function () {
        var $parent = $(this).parents("div");
        // See if we need to reset the overflow or not.
        var noOtherExpanded = $('.chosen-with-drop', $parent).length == 0;
        if (noOtherExpanded)
            $parent.css("overflow", "");
        //$('.tab-content').scrollTop(($('.tab-content').height()*2));
    });
}

function makeChosenAccessibleForBootstrapValidation(){
    //bootstraps validation highlighting only works, of the element to be highlighted has the class "form-control"
    //since the chosen plugin provides us with this form, we have no other way then adding the class dynamically
    $(".chosen-single").addClass("form-control");
}

function fireWindowEvent(eventName) {
    var event = document.createEvent('Event');
    event.initEvent(eventName, true, true);
    window.dispatchEvent(event);
}

$("#main-navbar .dropdown-toggle").click(function () {
    var parent = $(this).parent();
    var wasOpen = parent.hasClass("open");
    $("#main-navbar .dropdown.open").removeClass("open").attr('aria-expanded', 'false');
    if (!wasOpen) {
        parent.addClass("open");
        $(this).trigger('focus').attr('aria-expanded', 'true')
    }
});

/**
 * Adds a cron validator to the form. The cron input field must define the attribute: data-cron, to use this.
 * @param $form the form which holds a cron input
 * @param $outputElement will receive a text which describws the entered cron
 */
function addCronValidatorToForm($form, $outputElement){
    $form.validator({
        custom: {
            'cron': function() {
                var error = "";
                $.ajax({
                    url: OpenSpeedMonitor.urls.cronExpressionNextExecution,
                    data: { cronExpression: cronStringInputField.val()},
                    dataType: "text",
                    type: 'GET',
                    async:false,
                    success: function (data) {
                        $outputElement.text(prettyCron.toString(cronStringInputField.val()));
                    },
                    error: function (e, status) {
                        if (status === "error") {
                            error = e.responseText;
                            $outputElement.text("");
                        } else {
                            console.error(e);
                        }
                    }
                });
                return error;
            }
        }
    });
}
<commit_msg>postloaded onLoaded functionality to call callbacks when all dependencies are loaded<commit_after>/*
 * OpenSpeedMonitor (OSM)
 * Copyright 2014 iteratec GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//= require_tree bower_components/jquery
//= require_tree bower_components/jquery-ui
//= require_tree bower_components/bootstrap
//= require_tree bower_components/bootstrap-colorpicker/dist/js/
//= require_tree bower_components/chosen
//= require_tree bower_components/clipboard
//= require kickstart/checkboxes
//= require spinner
//= require bower_components/bootstrap-validator/js/validator
//= require_self

delete $.fn.datepicker; // so it can be replaced by air-datepicker

/**
 * Global namespace for OpenSpeedMonitor application.
 */
var OpenSpeedMonitor = OpenSpeedMonitor || {};

/**
 * Map for URLs to use
 */
OpenSpeedMonitor.urls = OpenSpeedMonitor.urls || {};

/**
 * Map for i18n to use
 */
OpenSpeedMonitor.i18n = OpenSpeedMonitor.i18n || {};

/**
 * Loads all registered JavaScript files. Used by microservices.
 * @type {Array}
 */
OpenSpeedMonitor.postLoadUrls = OpenSpeedMonitor.postLoadUrls || [];
OpenSpeedMonitor.postLoadUrls.forEach(function (scriptUrl) {
    $.getScript(scriptUrl);
});

OpenSpeedMonitor.postLoader = (function () {
    var postloadedScripts = {};
    var onLoadedHandlers = {};

    var head = document.getElementsByTagName("head")[0];

    var loadJavascript = function (url, async, name) {
        async = async || true;
        var script = document.createElement("script");
        script.onload = function () {
            postloadedScripts[name] = true;
            checkCallHandler(name);
            fireWindowEvent("" + name + "Loaded");
        };
        script.setAttribute("src", url);
        script.setAttribute("type", "text/javascript");
        script.setAttribute("async", async);
        //script.setAttribute("charset","ISO-8859-1");
        head.appendChild(script);
    };

    var loadStylesheet = function (url) {
        var link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = url;
        link.media = "all";
        head.appendChild(link);
    };

    var onLoaded = function(dependencies, callback) {
        if (typeof dependencies === 'string' || dependencies instanceof String) {
            dependencies = [dependencies];
        }
        var dependencyId = dependencies.sort().join(";");
        if (!onLoadedHandlers[dependencyId]) {
            onLoadedHandlers[dependencyId] = [];
        }
        if (onLoadedHandlers[dependencyId].indexOf(callback) < 0) {
            onLoadedHandlers[dependencyId].push(callback);
        }
        if (allDependenciesAreLoaded(dependencies)) {
            callback();
        }
    };

    var checkCallHandler = function(nameOfNewLoaded) {
        Object.keys(onLoadedHandlers).forEach(function(dependencyId) {
            var dependencies = dependencyId.split(";");
            if (dependencies.indexOf(nameOfNewLoaded) < 0) {
                return;
            }
            if (allDependenciesAreLoaded(dependencies)) {
                onLoadedHandlers[dependencyId].forEach(function(callback) {
                    callback();
                });
            }
        });
    };

    var allDependenciesAreLoaded = function (dependencies) {
        return dependencies.every(function (d) { return !!postloadedScripts[d]; });
    };

    return {
        loadJavascript: loadJavascript,
        loadStylesheet: loadStylesheet,
        onLoaded: onLoaded
    }

})();

/**
 * Global string utilities module.
 */
OpenSpeedMonitor.stringUtils = (function () {
    var stringToBoolean = function (string) {
        if (!string) {
            return false;
        }
        switch (string.toLowerCase()) {
            case "true":
            case "yes":
            case "1":
            case "on":
                return true;
            case "false":
            case "no":
            case "0":
            case "off":
            case null:
                return false;
            default:
                return false;
        }
    };

    var isNumeric = function (string) {
        return !isNaN(string);
    };

    return {
        isNumeric: isNumeric,
        stringToBoolean: stringToBoolean
    };
})();

/**
 * Global module providing functionalities for storage of data in the browser.
 *
 * @returns {{
 *      setCookie: setCookie,
 *      getCookie: getCookie,
 *      setToLocalStorage: setToLocalStorage,
 *      getFromLocalStorage: getFromLocalStorage,
 *      getObjectFromLocalStorage: getObjectFromLocalStorage,
 *      setObjectToLocalStorage: setObjectToLocalStorage}}
 */
OpenSpeedMonitor.clientSideStorageUtils = function () {
    var setCookie = function (key, value, path, shouldExpireInMillisecsFromNow) {
        var expires = new Date();
        expires.setTime(expires.getTime() + shouldExpireInMillisecsFromNow);
        var cookieToSet = key + '=' + btoa(value) + ';expires=' + expires.toUTCString() + ';path=' + path;
        console.log(cookieToSet);
        document.cookie = cookieToSet;
    };

    var getCookie = function (key) {
        var keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
        return keyValue ? atob(keyValue[2]) : null;
    };

    var setToLocalStorage = function (key, value) {
        try {
            localStorage.setItem(key, value)
        } catch (e) {
            console.log('Can\'t write data to local storage: ' + e.message);
        }
    };

    var getFromLocalStorage = function (key) {
        try {
            return localStorage.getItem(key);
        } catch (e) {
            console.log('Can\'t read data from local storage: ' + e.message);
        }
        return null;
    };

    /**
     * Reads a whole object in local storage.
     * @param keyObject An object with different properties whose values are the local storage keys.
     * @return object A new object with the same properties as keyObject and values from the local storage.
     */
    var getObjectFromLocalStorage = function (keyObject) {
        var hasValues = false;
        var values = {};
        for (var property in keyObject) {
            if (keyObject.hasOwnProperty(property)) {
                var value = getFromLocalStorage(keyObject[property]);
                hasValues = hasValues || value !== null;
                values[property] = value;
            }
        }
        return hasValues ? values : null;
    };

    /**
     * Saves a whole object in local storage
     * @param keyObject An object whose properties are the same as in value. The value of each property is the local storage key.
     * @param value The object to save with the same properties as in keyObject.
     */
    var setObjectToLocalStorage = function (keyObject, value) {
        for (var property in keyObject) {
            if (keyObject.hasOwnProperty(property)) {
                setToLocalStorage(keyObject[property], value[property]);
            }
        }
    };

    return {
        setCookie: setCookie,
        getCookie: getCookie,
        setToLocalStorage: setToLocalStorage,
        getFromLocalStorage: getFromLocalStorage,
        getObjectFromLocalStorage: getObjectFromLocalStorage,
        setObjectToLocalStorage: setObjectToLocalStorage
    };
};

OpenSpeedMonitor.urlUtils = (function () {
    var getAllVars = function () {
        var vars = [];
        var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
        for (var i = 0; i < hashes.length; i++) {
            var hash = hashes[i].split('=');
            var key = decodeURIComponent(hash[0]);
            vars.push(key);
            vars[key] = decodeURIComponent(hash[1]);
        }
        return vars;
    };

    var getVar = function (name) {
        return getAllVars()[name];
    };

    return {
        getAllVars: getAllVars,
        getVar: getVar
    };
})();

OpenSpeedMonitor.domUtils = (function () {
    /**
     * Creates option elements by a list of values which all contain an 'id' and a 'name'
     * @param values Array with objects containing id and name
     * @return Array The list of newly created option elements, sorted by name
     */
    var createOptionsByIdAndName = function (values) {
        var options = [];
        if (!values) {
            return [];
        }
        values.sort(function (a, b) {
            return a.name.localeCompare(b.name);
        });
        values.forEach(function (value) {
            if (value && value.id && value.name) {
                options.push($("<option/>", {
                    value: value.id,
                    text: value.name
                }));
            }
        });
        return options;
    };

    /**
     * Gets all values of all option elements in a select element
     * @param selectElement The select element with options as children
     * @returns Array An array with all values of all options
     */
    var getAllOptionValues = function (selectElement) {
        return $.map($(selectElement).find("option"), function (option) {
            return option.value;
        });
    };

    var hasAllOptionsSelected = function (selectElement) {
        selectElement = $(selectElement);
        return selectElement.find(":not(:selected)").length == 0 && selectElement.find("option").length > 0;
    };

    /**
     * Updates a select element with new values
     * @param selectElement The select element to update
     * @param idAndNameList A list of objects with id and name
     * @param noResultsText If set, a disabled option with this text is appended if the idAndNameList is empty
     */
    var updateSelectOptions = function (selectElement, idAndNameList, noResultsText) {
        selectElement = $(selectElement);
        var selection = selectElement.val();
        selectElement.empty();
        selectElement.append(OpenSpeedMonitor.domUtils.createOptionsByIdAndName(idAndNameList));
        if (!selectElement.children().length && noResultsText) {
            selectElement.append($("<option/>", {disabled: "disabled", text: noResultsText}));
        }
        selectElement.val(selection);
    };

    /**
     * Deselects all selected options in a select element
     * @param selectElement The select element
     * @param avoidEvent Optional. If true, no change event will be triggered
     */
    var deselectAllOptions = function (selectElement, avoidEvent) {
        selectElement = $(selectElement);
        selectElement.find("option:selected").removeAttr("selected");
        if (!avoidEvent) {
            selectElement.trigger("change");
        }
    };

    return {
        createOptionsByIdAndName: createOptionsByIdAndName,
        getAllOptionValues: getAllOptionValues,
        hasAllOptionsSelected: hasAllOptionsSelected,
        updateSelectOptions: updateSelectOptions,
        deselectAllOptions: deselectAllOptions
    };
})();

/**
 * This method will just return the given message. We use it,
 * so you can override it for a specialised delete conformation for the given domain
 */
function domainDeleteConfirmation(message, id, link) {
    var confirmMessage = "";
    if (typeof link !== "undefined" && link !== null && link !== "") {
        jQuery.ajax({
            type: 'GET',
            url: link,
            data: {id: id},
            async: false,
            success: function (result) {
                confirmMessage = message + "<br>" + result;
            },
            error: function (result) {
                confirmMessage = message;
            }
        });
        return confirmMessage;
    } else {
        return message;
    }

}

/**
 * Necessary to prevent Chosen dropdown from being cut off in tabs
 * @see http://stackoverflow.com/a/21375637
 * TODO: after first selection dropdown of chosen select disappears after click. So one have to hold the mouse button while selection :(
 */
function fixChosen() {
    var els = $(".chosen");
    els.on("chosen:showing_dropdown", function (event, chosen) {
        $(this).parents("div").css("overflow", "visible");
    });
    els.on("chosen:hiding_dropdown", function () {
        var $parent = $(this).parents("div");
        // See if we need to reset the overflow or not.
        var noOtherExpanded = $('.chosen-with-drop', $parent).length == 0;
        if (noOtherExpanded)
            $parent.css("overflow", "");
        //$('.tab-content').scrollTop(($('.tab-content').height()*2));
    });
}

function makeChosenAccessibleForBootstrapValidation(){
    //bootstraps validation highlighting only works, of the element to be highlighted has the class "form-control"
    //since the chosen plugin provides us with this form, we have no other way then adding the class dynamically
    $(".chosen-single").addClass("form-control");
}

function fireWindowEvent(eventName) {
    var event = document.createEvent('Event');
    event.initEvent(eventName, true, true);
    window.dispatchEvent(event);
}

$("#main-navbar .dropdown-toggle").click(function () {
    var parent = $(this).parent();
    var wasOpen = parent.hasClass("open");
    $("#main-navbar .dropdown.open").removeClass("open").attr('aria-expanded', 'false');
    if (!wasOpen) {
        parent.addClass("open");
        $(this).trigger('focus').attr('aria-expanded', 'true')
    }
});

/**
 * Adds a cron validator to the form. The cron input field must define the attribute: data-cron, to use this.
 * @param $form the form which holds a cron input
 * @param $outputElement will receive a text which describws the entered cron
 */
function addCronValidatorToForm($form, $outputElement){
    $form.validator({
        custom: {
            'cron': function() {
                var error = "";
                $.ajax({
                    url: OpenSpeedMonitor.urls.cronExpressionNextExecution,
                    data: { cronExpression: cronStringInputField.val()},
                    dataType: "text",
                    type: 'GET',
                    async:false,
                    success: function (data) {
                        $outputElement.text(prettyCron.toString(cronStringInputField.val()));
                    },
                    error: function (e, status) {
                        if (status === "error") {
                            error = e.responseText;
                            $outputElement.text("");
                        } else {
                            console.error(e);
                        }
                    }
                });
                return error;
            }
        }
    });
}
<|endoftext|>