<commit_before>javascript:
(function() {
	if ($.inArray(mw.config.get('wgNamespaceNumber'), [0, 10, 14]) === -1) {
		/* Enabled on main, template, category namespaces only. */
		return;
	}

	if ($('#t-wikibase').length > 0) {
		/* Disabled for linked pages */
		return;
	}

	function LinkData(localurl, sitelang, sitecode) {
		var pagename = prompt('輸入頁面名稱', window.getSelection().toString());
		if (pagename === null) {
			mw.notify('動作已取消');
			return;
		}

		/* 取得對應條目的名字 */
		var localapi = new mw.ForeignApi(localurl);
		localapi.get({
			action: 'query',
			format: 'json',
			prop: 'pageprops',
			titles: pagename,
			redirects: 'yes',
			converttitles: 'yes',
		}).done(function(data) {
			var hasitem = false;
			var hastitle = false;
			var title;
			var dataid;
			if (data.query && data.query.pages) {
				for (var pageid in data.query.pages) {
					var item = data.query.pages[pageid];
					if (item.missing === '') {
						continue;
					}
					hastitle = true;
					title = item.title;
					if (item.pageprops && item.pageprops.wikibase_item) {
						hasitem = true;
						dataid = item.pageprops.wikibase_item;
					}
				}
			}
			if (!hastitle) {
				mw.notify('找不到對應條目，可能是因為尚未建立或者名稱不一致。');
			} else {
				/* 加入連結 */
				var api = new mw.ForeignApi('https://www.wikidata.org/w/api.php');
				api.get({
					action: 'query',
					meta: 'tokens'
				}).done(function(data) {
					if (!hasitem) {
						if (!confirm('對應項目沒有維基數據。是否添加？')) {
							mw.notify('已取消建立項目。');
							return;
						}
						var targetsite = sitecode;
						api.post({
							action: 'wbeditentity',
							'new': 'item',
							token: data.query.tokens.csrftoken,
							'data': JSON.stringify({
								labels: [{
									language: sitelang,
									value: title,
								}, {
									language: 'szy',
									value: mw.config.get('wgPageName'),
								}],
								sitelinks: [{
									site: targetsite,
									title: title,
								}, {
									site: mw.config.get('wgDBname'),
									title: mw.config.get('wgPageName'),
								}],
							})
						}).done(function() {
							mw.notify('成功建立新的維基數據項目。');
							location.reload();
						}).fail(function() {
							mw.notify('存取維基數據時發生錯誤。');
						});
					} else {
						api.post({
							action: 'wbsetsitelink',
							id: dataid,
							token: data.query.tokens.csrftoken,
							linksite: mw.config.get('wgDBname'),
							linktitle: mw.config.get('wgPageName'),
						}).done(function(data) {
							if (data.success) {
								mw.notify('成功連結至現有維基數據項目。');
								location.reload();
							} else {
								mw.notify('存取維基數據時發生錯誤。');
							}
						}).fail(function() {
							mw.notify('存取維基數據時發生錯誤。');
						});
					}
				}).fail(function() {
					mw.notify('存取維基數據時發生錯誤。');
				});
			}
		}).fail(function() {
			mw.notify('取得條目名稱時發生錯誤。');
		});
	}

	var wikis = [
		{ text: '連結到中維', url: 'https://zh.wikipedia.org/w/api.php', lang: 'zh', sitecode: 'zhwiki' },
		{ text: '英維', url: 'https://en.wikipedia.org/w/api.php', lang: 'en', sitecode: 'enwiki' },
	];
	wikis.forEach(wiki => {
		var link = mw.util.addPortletLink('p-namespaces', '#', wiki.text);
		$(link).on('click', function() {
			LinkData(wiki.url, wiki.lang, wiki.sitecode);
		})
	});

}
)();
<commit_msg>Add summary<commit_after>javascript:
(function() {
	if ($.inArray(mw.config.get('wgNamespaceNumber'), [0, 10, 14]) === -1) {
		/* Enabled on main, template, category namespaces only. */
		return;
	}

	if ($('#t-wikibase').length > 0) {
		/* Disabled for linked pages */
		return;
	}

	var wdsummary = 'via [[:w:szy:User:Xiplus/js/quick-link-wikidata-szywp.js|QLWszywp]]';

	function LinkData(localurl, sitelang, sitecode) {
		var pagename = prompt('輸入頁面名稱', window.getSelection().toString());
		if (pagename === null) {
			mw.notify('動作已取消');
			return;
		}

		/* 取得對應條目的名字 */
		var localapi = new mw.ForeignApi(localurl);
		localapi.get({
			action: 'query',
			format: 'json',
			prop: 'pageprops',
			titles: pagename,
			redirects: 'yes',
			converttitles: 'yes',
		}).done(function(data) {
			var hasitem = false;
			var hastitle = false;
			var title;
			var dataid;
			if (data.query && data.query.pages) {
				for (var pageid in data.query.pages) {
					var item = data.query.pages[pageid];
					if (item.missing === '') {
						continue;
					}
					hastitle = true;
					title = item.title;
					if (item.pageprops && item.pageprops.wikibase_item) {
						hasitem = true;
						dataid = item.pageprops.wikibase_item;
					}
				}
			}
			if (!hastitle) {
				mw.notify('找不到對應條目，可能是因為尚未建立或者名稱不一致。');
			} else {
				/* 加入連結 */
				var api = new mw.ForeignApi('https://www.wikidata.org/w/api.php');
				api.get({
					action: 'query',
					meta: 'tokens'
				}).done(function(data) {
					if (!hasitem) {
						if (!confirm('對應項目沒有維基數據。是否添加？')) {
							mw.notify('已取消建立項目。');
							return;
						}
						var targetsite = sitecode;
						api.post({
							action: 'wbeditentity',
							'new': 'item',
							token: data.query.tokens.csrftoken,
							'data': JSON.stringify({
								labels: [{
									language: sitelang,
									value: title,
								}, {
									language: 'szy',
									value: mw.config.get('wgPageName'),
								}],
								sitelinks: [{
									site: targetsite,
									title: title,
								}, {
									site: mw.config.get('wgDBname'),
									title: mw.config.get('wgPageName'),
								}],
							}),
							summary: wdsummary,
						}).done(function() {
							mw.notify('成功建立新的維基數據項目。');
							location.reload();
						}).fail(function() {
							mw.notify('存取維基數據時發生錯誤。');
						});
					} else {
						api.post({
							action: 'wbsetsitelink',
							id: dataid,
							token: data.query.tokens.csrftoken,
							linksite: mw.config.get('wgDBname'),
							linktitle: mw.config.get('wgPageName'),
							summary: wdsummary,
						}).done(function(data) {
							if (data.success) {
								mw.notify('成功連結至現有維基數據項目。');
								location.reload();
							} else {
								mw.notify('存取維基數據時發生錯誤。');
							}
						}).fail(function() {
							mw.notify('存取維基數據時發生錯誤。');
						});
					}
				}).fail(function() {
					mw.notify('存取維基數據時發生錯誤。');
				});
			}
		}).fail(function() {
			mw.notify('取得條目名稱時發生錯誤。');
		});
	}

	var wikis = [
		{ text: '連結到中維', url: 'https://zh.wikipedia.org/w/api.php', lang: 'zh', sitecode: 'zhwiki' },
		{ text: '英維', url: 'https://en.wikipedia.org/w/api.php', lang: 'en', sitecode: 'enwiki' },
	];
	wikis.forEach(wiki => {
		var link = mw.util.addPortletLink('p-namespaces', '#', wiki.text);
		$(link).on('click', function() {
			LinkData(wiki.url, wiki.lang, wiki.sitecode);
		})
	});

}
)();
<|endoftext|>


<commit_before>'use strict';

const memwatch = require('memwatch-next');
const cluster = require('cluster');
const path = require('path');

const logger = require('../logger.js');

module.exports = exports = {};

exports.clearConsole = function() {
    logger.debug('Function call. clearConsole()', {args: [].slice.call(arguments)});
    // console.log('\x1Bc');
    process.stdout.write('\x1Bc');
};

exports.getProcessLaunchDate = function() {
    logger.debug('Function call. getProcessLaunchDate()', {args: [].slice.call(arguments)});
    // The result is not absolutely precise.
    // Deviations of up to 2 seconds are to be expected
    const ms_in_second = 1000;
    const now = new Date().getTime();
    const uptime = process.uptime() * ms_in_second;
    return new Date(now - uptime);
};

exports.capitalize = function(str) {
    logger.debug('Function call. capitalize(str)', {args: [].slice.call(arguments)});
    if (!str.length || typeof str !== 'string') {
        return str;
    }

    str = str[0].toUpperCase() + str.substr(1);
    return str;
};

exports.monitorMemoryLeaks = function() {
    memwatch.on('leak', function(info) {
        logger.warn('Possible MEMORY LEAK detected', info);
    });
};

exports.spawnStalker = function(args, onMessage, onError=console.error) {
    cluster.setupMaster({
        exec: path.resolve(__dirname, '../../stalker/run'),
        args: args,
        silent: true
    });

    const worker = cluster.fork();
    worker.on('message', onMessageThunkify(onMessage));
    worker.on('error', onError);
};

function onMessageThunkify(fn) {
    return msg => {
        if (typeof msg.data === 'string') {
            console.log(msg.data);
        }

        if (msg.error) {
            console.log(msg.error);
        }

        return fn(msg);
    };
}
<commit_msg>Remove memory-leak detection helper from console interface.<commit_after>'use strict';

const cluster = require('cluster');
const path = require('path');

const logger = require('../logger.js');

module.exports = exports = {};

exports.clearConsole = function() {
    logger.debug('Function call. clearConsole()', {args: [].slice.call(arguments)});
    // console.log('\x1Bc');
    process.stdout.write('\x1Bc');
};

exports.getProcessLaunchDate = function() {
    logger.debug('Function call. getProcessLaunchDate()', {args: [].slice.call(arguments)});
    // The result is not absolutely precise.
    // Deviations of up to 2 seconds are to be expected
    const ms_in_second = 1000;
    const now = new Date().getTime();
    const uptime = process.uptime() * ms_in_second;
    return new Date(now - uptime);
};

exports.capitalize = function(str) {
    logger.debug('Function call. capitalize(str)', {args: [].slice.call(arguments)});
    if (!str.length || typeof str !== 'string') {
        return str;
    }

    str = str[0].toUpperCase() + str.substr(1);
    return str;
};

exports.spawnStalker = function(args, onMessage, onError=console.error) {
    cluster.setupMaster({
        exec: path.resolve(__dirname, '../../stalker/run'),
        args: args,
        silent: true
    });

    const worker = cluster.fork();
    worker.on('message', onMessageThunkify(onMessage));
    worker.on('error', onError);
};

function onMessageThunkify(fn) {
    return msg => {
        if (typeof msg.data === 'string') {
            console.log(msg.data);
        }

        if (msg.error) {
            console.log(msg.error);
        }

        return fn(msg);
    };
}
<|endoftext|>


<commit_before>/* Copyright (c) 2014 Richard Rodger, MIT License */
'use strict';

var _    = require('underscore')
var amqp = require('amqplib/callback_api')

module.exports = function( options ) {
  var seneca = this
  var plugin = 'rabbitmq-transport'

  var so = seneca.options()

  options = seneca.util.deepextend(
    {
      rabbitmq: {
        type: 'rabbitmq',
        url: 'amqp://localhost',
        socketoptions: {}
      }
    },
    so.transport,
    options)

  var tu = seneca.export('transport/utils')

  seneca.add({role:'transport',hook:'listen',type:'rabbitmq'}, hook_listen_rabbitmq)
  seneca.add({role:'transport',hook:'client',type:'rabbitmq'}, hook_client_rabbitmq)

  function hook_listen_rabbitmq( args, done ) {
    var seneca         = this
    var type           = args.type
    var listen_options = seneca.util.clean(_.extend({},options[type],args))

    amqp.connect(listen_options.url, listen_options.socketoptions, function (error, connection) {
      if (error) return done(error)

      connection.createChannel(function (error, channel) {
        if (error) return done(error);

        channel.on('error', done);

        tu.listen_topics( seneca, args, listen_options, function ( topic ) {
          var acttopic = topic+'_act'

          seneca.log.debug('listen', 'subscribe', acttopic, listen_options, seneca)

          channel.assertQueue(acttopic)

          // Subscribe
          channel.consume(acttopic, on_message);

          var asserted = {}

          function on_message ( message ) {
            var content = message.content ? message.content.toString() : undefined
            var data = tu.parseJSON( seneca, 'listen-'+type, content )

            channel.ack(message)

            // Publish
            tu.handle_request( seneca, data, listen_options, function(out){
              if( null === out ) return;
              var outstr = tu.stringifyJSON( seneca, 'listen-'+type, out )

              var restopic = topic+'_res'+'/'+data.origin

              if (!asserted[restopic]) {
                channel.assertQueue(restopic)
                asserted[restopic] = true
              }

              channel.sendToQueue(restopic, new Buffer(outstr));
            })
          }
        });

        seneca.add('role:seneca,cmd:close',function( close_args, done ) {
          var closer = this
          channel.close();
          connection.close();
          closer.prior(close_args,done)
        })

        seneca.log.info('listen', 'open', listen_options, seneca)

        done()
      })
    })
  }

  function hook_client_rabbitmq( args, client_done ) {
    var seneca         = this
    var type           = args.type
    var client_options = seneca.util.clean(_.extend({},options[type],args))

    amqp.connect(client_options.url, client_options.socketoptions, function (error, connection) {
      if (error) return client_done(error)

      connection.createChannel(function (error, channel) {
        if (error) return client_done(error);

        tu.make_client( seneca, make_send, client_options, client_done )

        function make_send( spec, topic, send_done ) {
          var acttopic = topic+'_act'
          var restopic = topic+'_res'+'/'+seneca.id

          channel.on('error', send_done)

          channel.assertQueue(acttopic)
          channel.assertQueue(restopic)

          seneca.log.debug('client', 'subscribe', restopic, client_options, seneca)

          // Subscribe
          channel.consume(restopic, function ( message ) {
            var content = message.content ? message.content.toString() : undefined
            var input = tu.parseJSON(seneca,'client-'+type,content)

            channel.ack(message)

            tu.handle_response( seneca, input, client_options )
          })

          // Publish
          send_done( null, function ( args, done ) {
            var outmsg = tu.prepare_request( this, args, done )
            var outstr = tu.stringifyJSON( seneca, 'client-rabbitmq', outmsg )
            channel.sendToQueue(acttopic, new Buffer(outstr));
          })

          seneca.add('role:seneca,cmd:close',function( close_args, done ) {
            var closer = this
            channel.close();
            connection.close();
            closer.prior(close_args,done)
          })

        }
      })
    })
  }

  return {
    name: plugin,
  }
}
<commit_msg>Revert "use a different response queue for each client and topic"<commit_after>/* Copyright (c) 2014 Richard Rodger, MIT License */
'use strict';

var _    = require('underscore')
var amqp = require('amqplib/callback_api')

module.exports = function( options ) {
  var seneca = this
  var plugin = 'rabbitmq-transport'

  var so = seneca.options()

  options = seneca.util.deepextend(
    {
      rabbitmq: {
        type: 'rabbitmq',
        url: 'amqp://localhost',
        socketoptions: {}
      }
    },
    so.transport,
    options)

  var tu = seneca.export('transport/utils')

  seneca.add({role:'transport',hook:'listen',type:'rabbitmq'}, hook_listen_rabbitmq)
  seneca.add({role:'transport',hook:'client',type:'rabbitmq'}, hook_client_rabbitmq)

  function hook_listen_rabbitmq( args, done ) {
    var seneca         = this
    var type           = args.type
    var listen_options = seneca.util.clean(_.extend({},options[type],args))

    amqp.connect(listen_options.url, listen_options.socketoptions, function (error, connection) {
      if (error) return done(error)

      connection.createChannel(function (error, channel) {
        if (error) return done(error);

        channel.on('error', done);

        tu.listen_topics( seneca, args, listen_options, function ( topic ) {
          var acttopic = topic+'_act'
          var restopic = topic+'_res'

          seneca.log.debug('listen', 'subscribe', acttopic, listen_options, seneca)

          channel.assertQueue(acttopic)
          channel.assertQueue(restopic)

          // Subscribe
          channel.consume(acttopic, on_message);

          function on_message ( message ) {
            var content = message.content ? message.content.toString() : undefined
            var data = tu.parseJSON( seneca, 'listen-'+type, content )

            channel.ack(message)

            // Publish
            tu.handle_request( seneca, data, listen_options, function(out){
              if( null === out ) return;
              var outstr = tu.stringifyJSON( seneca, 'listen-'+type, out )
              channel.sendToQueue(restopic, new Buffer(outstr));
            })
          }
        });

        seneca.add('role:seneca,cmd:close',function( close_args, done ) {
          var closer = this
          channel.close();
          connection.close();
          closer.prior(close_args,done)
        })

        seneca.log.info('listen', 'open', listen_options, seneca)

        done()
      })
    })
  }

  function hook_client_rabbitmq( args, client_done ) {
    var seneca         = this
    var type           = args.type
    var client_options = seneca.util.clean(_.extend({},options[type],args))

    amqp.connect(client_options.url, client_options.socketoptions, function (error, connection) {
      if (error) return client_done(error)

      connection.createChannel(function (error, channel) {
        if (error) return client_done(error);

        tu.make_client( seneca, make_send, client_options, client_done )

        function make_send( spec, topic, send_done ) {
          var acttopic = topic+'_act'
          var restopic = topic+'_res'

          channel.on('error', send_done)

          channel.assertQueue(acttopic)
          channel.assertQueue(restopic)

          seneca.log.debug('client', 'subscribe', restopic, client_options, seneca)

          // Subscribe
          channel.consume(restopic, function ( message ) {
            var content = message.content ? message.content.toString() : undefined
            var input = tu.parseJSON(seneca,'client-'+type,content)

            channel.ack(message)

            tu.handle_response( seneca, input, client_options )
          })

          // Publish
          send_done( null, function ( args, done ) {
            var outmsg = tu.prepare_request( this, args, done )
            var outstr = tu.stringifyJSON( seneca, 'client-rabbitmq', outmsg )
            channel.sendToQueue(acttopic, new Buffer(outstr));
          })

          seneca.add('role:seneca,cmd:close',function( close_args, done ) {
            var closer = this
            channel.close();
            connection.close();
            closer.prior(close_args,done)
          })

        }
      })
    })
  }

  return {
    name: plugin,
  }
}
<|endoftext|>


<commit_before>const _ = require('lodash/fp')

const db = require('./db')
const pgp = require('pg-promise')()

const getMachineName = require('./machine-loader').getMachineName
const NUM_RESULTS = 1000

/**
 * Get the latest log's timestamp
 *
 * @name getLastSeen
 * @function
 * @async
 *
 * @param {string} deviceId Machine id to get the last timestamp for
 *
 * @returns {date} Last timestamp
 */
function getLastSeen (deviceId) {
  const sql = `select timestamp from logs
  where device_id=$1
  order by timestamp desc limit 1`
  return db.oneOrNone(sql, [deviceId])
  .then(log => log ? log.timestamp : null)
}

/**
 * Update logs in db
 *
 * @name update
 * @function
 * @async
 *
 * @param {string} deviceId Machine Id to which logs belong to
 * @param {array} logLines Logs to be saved
 *
 * @returns {null}
 */
function update (deviceId, logLines) {
  const cs = new pgp.helpers.ColumnSet([
    'id', 'device_id', 'log_level', 'timestamp', 'message'],
    {table: 'logs'})

  const logs = _.map(log => {
    const formatted = {
      id: log.id,
      deviceId: deviceId,
      message: log.msg,
      logLevel: _.contains('error', _.lowerCase(log.msg)) ? 'error' : 'info',
      timestamp: log.timestamp
    }
    return _.mapKeys(_.snakeCase, formatted)
  }, logLines)
  const sql = pgp.helpers.insert(logs, cs)
  return db.none(sql)
}

/**
 * Get all logs by machine id
 * and timestamp
 *
 * @name list
 * @function
 *
 * @param {string} deviceId Machine id to fetch the logs for
 * @param {date} until Show the logs until the date provided, defaults to now
 *
 * @returns {array} Array of logs for the requested machinej
 */
function getMachineLogs (deviceId, until = new Date().toISOString()) {
  const defaults = {
    logs: [],
    currentMachine: {
      name: '',
      deviceId: ''
    }
  }
  if (!deviceId) return defaults

  const sql = `select id, log_level, timestamp, message from logs
  where device_id=$1
  and timestamp <= $3
  order by timestamp asc limit $2`
  return Promise.all([db.any(sql, [ deviceId, NUM_RESULTS, until ]), getMachineName(deviceId)])
  .then(([logs, machineName]) => ({
    logs: _.map(_.mapKeys(_.camelCase), logs),
    currentMachine: {deviceId, name: machineName}
  }))
}

module.exports = { getMachineLogs, update, getLastSeen }
<commit_msg>Logs insert: on conflict do nothing<commit_after>const _ = require('lodash/fp')

const db = require('./db')
const pgp = require('pg-promise')()

const getMachineName = require('./machine-loader').getMachineName
const NUM_RESULTS = 1000

/**
 * Get the latest log's timestamp
 *
 * @name getLastSeen
 * @function
 * @async
 *
 * @param {string} deviceId Machine id to get the last timestamp for
 *
 * @returns {date} Last timestamp
 */
function getLastSeen (deviceId) {
  const sql = `select timestamp from logs
  where device_id=$1
  order by timestamp desc limit 1`
  return db.oneOrNone(sql, [deviceId])
  .then(log => log ? log.timestamp : null)
}

/**
 * Update logs in db
 *
 * @name update
 * @function
 * @async
 *
 * @param {string} deviceId Machine Id to which logs belong to
 * @param {array} logLines Logs to be saved
 *
 * @returns {null}
 */
function update (deviceId, logLines) {
  const cs = new pgp.helpers.ColumnSet([
    'id', 'device_id', 'log_level', 'timestamp', 'message'],
    {table: 'logs'})

  const logs = _.map(log => {
    const formatted = {
      id: log.id,
      deviceId: deviceId,
      message: log.msg,
      logLevel: _.contains('error', _.lowerCase(log.msg)) ? 'error' : 'info',
      timestamp: log.timestamp
    }
    return _.mapKeys(_.snakeCase, formatted)
  }, logLines)
  const sql = pgp.helpers.insert(logs, cs) + 'on conflict do nothing'
  return db.none(sql)
}

/**
 * Get all logs by machine id
 * and timestamp
 *
 * @name list
 * @function
 *
 * @param {string} deviceId Machine id to fetch the logs for
 * @param {date} until Show the logs until the date provided, defaults to now
 *
 * @returns {array} Array of logs for the requested machinej
 */
function getMachineLogs (deviceId, until = new Date().toISOString()) {
  const defaults = {
    logs: [],
    currentMachine: {
      name: '',
      deviceId: ''
    }
  }
  if (!deviceId) return defaults

  const sql = `select id, log_level, timestamp, message from logs
  where device_id=$1
  and timestamp <= $3
  order by timestamp asc limit $2`
  return Promise.all([db.any(sql, [ deviceId, NUM_RESULTS, until ]), getMachineName(deviceId)])
  .then(([logs, machineName]) => ({
    logs: _.map(_.mapKeys(_.camelCase), logs),
    currentMachine: {deviceId, name: machineName}
  }))
}

module.exports = { getMachineLogs, update, getLastSeen }
<|endoftext|>


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

'use strict'

// ----------------------------------------------------------------------------
// Dependencies.
const fs = require('fs')
const path = require('path')

const utilsMisc = require('../../utils/misc.js')

// ----------------------------------------------------------------------------

// The module returns an object, with a method run().
// All other vars are local to this module.
var patch = {}
module.exports = patch

// ----------------------------------------------------------------------------

var ctx
var groupBitFields = []
var svd
var removeNodes = []

// ----------------------------------------------------------------------------

patch.run = function (context, args, callback) {

  ctx = context

  if (args.length < 7) {
    ctx.console.log('Usage:')
    ctx.console.log('  xcdl svd patch --file in.json --patch patch.json --output out.json')

    callback(null)
    return
  }

  ctx.console.log('Modify an XSVD .json file using command line options and a patch file.')

  var inputPath
  var patchPath
  var outputPath

  var i
  for (i = 1; i < args.length; ++i) {
    if (args[i] === '--file') {
      inputPath = args[i + 1]
      ++i
    } else if (args[i] === '--patch') {
      patchPath = args[i + 1]
      ++i
    } else if (args[i] === '--output') {
      outputPath = args[i + 1]
      ++i
    } else if (args[i] === '--group-bitfield') {
      groupBitFields.push(args[i + 1])
      ++i
    } else if (args[i] === '--remove') {
      removeNodes.push(args[i + 1])
    }
  }

  // var inputSvd = path.basename(inputPath)

  var inputData
  try {
    inputData = fs.readFileSync(inputPath, 'utf8')
  } catch (err) {
    // ctx.console.log(er.message)
    return callback(err)
  }
  ctx.console.log(`\nInput file '${inputPath}' read.`)

  svd = JSON.parse(inputData)

  if (!validate()) {
    return callback(null)
  }

  reorderBitfields(svd.device)

  var periph_array = []
  svd.device.peripherals.forEach(periph => periph_array.push(periph.name));
  ctx.console.log(`Peripherals: ${periph_array.join(' ')}`);

  var patchData
  try {
    patchData = fs.readFileSync(patchPath, 'utf8')
  } catch (err) {
    // context.console.log(er.message)
    return callback(err)
  }
  ctx.console.log(`\nPatch file '${patchPath}' read.`)

  var patch = JSON.parse(patchData)

  if (!patchSvd(patch)) {
    return callback(null)
  }

  var dirPath
  var out

  utilsMisc.addGenerator(svd, 'xcdl', ctx.packageJson.version, args)
  out = JSON.stringify(svd, null, '\t')

  var dirPath = path.dirname(outputPath)
  if (!fs.existsSync(dirPath)) {
    fs.mkdirSync(dirPath)
  }
  fs.writeFileSync(outputPath, out, 'utf8')
  ctx.console.log(`\nOutput file '${outputPath}' written.`)

  return callback(null)
}

// ----------------------------------------------------------------------------

var validate = function () {
  if (!svd.device) {
    ctx.console.error(`Mandatory 'device' missing.`)
    return false
  }
  if (!svd.device.peripherals) {
    ctx.console.error(`Mandatory 'device.peripherals' missing.`)
    return false
  }
  return true
}

var reorderBitfields = function (node) {

  if (node.peripherals) {
    node.peripherals.forEach(peripheral => {
      reorderBitfields(peripheral)
    })
  }
  if (node.registers) {
    node.registers.forEach(reg => {
      reorderBitfields(reg)
    })
  }
  if (node.fields) {
    node.fields.sort((f1, f2) => {
      // Return a negative value if f1 < f2; compare bit offsets.
      return parseInt(f1.bitOffset, 10) - parseInt(f2.bitOffset, 10)
    })
  }
}

var patchSvd = function (patch) {
  if (!svd.device || !svd.device.name || !svd.generators) {
    ctx.console.error('Input file not a SVD.')
    return false
  }
  if (!patch.device || !patch.device.name) {
    ctx.console.error('Patch file not a SVD.')
    return false
  }

  if (svd.device.name !== patch.device.name) {
    ctx.console.error('Patch refer to different device.')
    return false
  }

  ctx.console.log('\nChanges:')

  removeNodes.forEach(path => {
    var [element, index, array] = findObject(svd, path.split('/'))
    if (element) {
      ctx.console.log(`- node '${path}' removed`)
      array.splice(index, 1)
    }
  })

  if (patch.device.cpu) {
    // Possibly patch the cpu object.
    if (!svd.device.cpu) {
      // It is not present at all, copy entirely object.
      svd.device.cpu = patch.device.cpu
      ctx.console.log(`- 'cpu' added from patch`)
    } else {
      for (var key in patch.device.cpu) {
        if (!svd.device.cpu[key]) {
          // Copy only missing properties.
          svd.device.cpu[key] = patch.device.cpu[key]
          ctx.console.log(`cpu.${key} added.`)
        }
      }
    }
  }

  compareAndUpdate(patch.device, svd.device)

  for (var i = 0; i < groupBitFields.length; ++i) {
    doGroupBitfield(groupBitFields[i])
  }
  return true
}

var doGroupBitfield = function (path) {
  // ctx.console.log(path)

  var pa = path.split('/')
  if (pa.length < 2) {
    ctx.console.error(`Path ${path} must be at least two levels deep.`)
    return null
  }
  var bitfield_name = pa.pop()
  var path_prefix = pa.join('/') + '/'

  var [register, ,] = findObject(svd, pa.slice())

  if (register.fields) {
    var minOffset = 32
    var maxOffset = 0
    var preservedField;

    for (var i = 0; i < register.fields.length; ++i) {
      var field = register.fields[i];
      var re = new RegExp(bitfield_name + '[0-9]+')
      if (field.name.match(re)) {
        var full_name = path_prefix + field.name

        // ctx.console.log(field.name)
        if (field.bitWidth !== "1") {
          ctx.console.error(`Field ${field} has bitWidth != 1.`)
          return null
        }

        if (preservedField) {
          if (field.access !== preservedField.access) {
            ctx.console.error(`Field ${full_name} has different access.`)
          }
        }

        var offset = parseInt(field.bitOffset, 10)
        if (offset < minOffset) {
          minOffset = offset
        }
        if (offset > maxOffset) {
          maxOffset = offset
        }

        if (preservedField) {
          // Remove subsequent fields in the same group
          // ctx.console.log(`- field ${full_name} removed`)

          register.fields.splice(i, 1)
          i--
        } else {
          preservedField = field
        }
      }
    }
    var prev_name = path_prefix + preservedField.name
    preservedField.name = bitfield_name
    preservedField.bitOffset = minOffset.toString()
    preservedField.bitWidth = (maxOffset - minOffset + 1).toString()
    var name = path_prefix + bitfield_name
    // ctx.console.log(`- field ${prev_name} renamed ${name} and grouped from ${maxOffset - minOffset + 1} single bit fields`)
    ctx.console.log(`- field ${name} grouped from ${maxOffset - minOffset + 1} single bit fields`)

  } else {
    return null
  }
}

// Find peripherals, register, bitfields.
// Return a triplet [value, index, array] or null
var findObject = function (svd_node, path_array, depth = 0) {
  var name = path_array[0]
  path_array.splice(0, 1)

  if (svd_node.device && svd_node.device.peripherals) {
    // Search peripherals
    var peripherals = svd_node.device.peripherals
    for (var i = 0; i < peripherals.length; ++i) {
      var peripheral = peripherals[i];
      if (peripheral.name === name) {
        if (path_array.length == 0) {
          return [peripheral, i, peripherals]
        } else {
          return findObject(peripheral, path_array, depth + 1)
        }
      }
    }
  }

  if (svd_node.registers) {
    for (var i = 0; i < svd_node.registers.length; ++i) {
      var register = svd_node.registers[i];
      if (register.name === name) {
        if (path_array.length == 0) {
          return [register, i, svd_node.registers]
        } else {
          return findObject(register, path_array, depth + 1)
        }
      }
    }
  }

  if (svd_node.fields) {
    for (var i = 0; i < svd_node.fields.length; ++i) {
      var field = svd_node.fields[i];
      if (field.name === name) {
        if (path_array.length == 0) {
          return [field, i, svd_node.fields]
        } else {
          return findObject(field, path_array, depth + 1)
        }
      }
    }
  }
  return [null]
}

// Compare trees and update.
// Only qemuAlignment and qemuGroupName are processed.

var compareAndUpdate = function (patch_node, svd_node, depth = 0) {

  if (patch_node.qemuAlignment && !svd_node.qemuAlignment) {
    svd_node.qemuAlignment = patch_node.qemuAlignment
    ctx.console.log(`- qemuAlignment: '${patch_node.qemuAlignment}' added to ${patch_node.name}`)
  }

  if (patch_node.qemuGroupName && !svd_node.qemuGroupName) {
    svd_node.qemuGroupName = patch_node.qemuGroupName
    ctx.console.log(`- qemuGroupName: '${patch_node.qemuGroupName}' added to ${patch_node.name}`)
  }

  if (patch_node.peripherals) {
    if (svd_node.peripherals) {
      // Search peripherals
      var peripherals = patch_node.peripherals
      for (var i = 0; i < peripherals.length; ++i) {
        var peripheral = peripherals[i];
        var periph_name = peripheral.name
        if (periph_name) {
          var svd_periph = svd_node.peripherals.find(periph => { return periph.name === periph_name })
          if (svd_periph) {
            compareAndUpdate(peripheral, svd_periph, depth + 1)
          }
        } else {
          ctx.console.log(`* peripheral node has no name.`)
        }
      }
    } else {
      ctx.console.log(`* node ${patch_node.name} has no peripherals.`)
    }
  }

  if (patch_node.registers) {
    if (svd_node.registers) {
      // Search peripherals
      var registers = patch_node.registers
      for (var i = 0; i < registers.length; ++i) {
        var register = registers[i];
        var register_name = register.name
        if (register_name) {
          var svd_register = svd_node.registers.find(register => { return register.name === register_name })
          if (svd_register) {
            compareAndUpdate(register, svd_register, depth + 1)
          }
        } else {
          ctx.console.log(`* register node has no name.`)
        }
      }
    } else {
      ctx.console.log(`* node ${patch_node.name} has no registers.`)
    }
  }

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

'use strict'

// ----------------------------------------------------------------------------
// Dependencies.
const fs = require('fs')
const path = require('path')

const utilsMisc = require('../../utils/misc.js')

// ----------------------------------------------------------------------------

// The module returns an object, with a method run().
// All other vars are local to this module.
var patch = {}
module.exports = patch

// ----------------------------------------------------------------------------

var ctx
var groupBitFields = []
var svd
var removeNodes = []

// ----------------------------------------------------------------------------

patch.run = function (context, args, callback) {

  ctx = context

  if (args.length < 7) {
    ctx.console.log('Usage:')
    ctx.console.log('  xcdl svd patch --file in.json --patch patch.json --output out.json')

    callback(null)
    return
  }

  ctx.console.log('Modify an XSVD .json file using command line options and a patch file.')

  var inputPath
  var patchPath
  var outputPath

  var i
  for (i = 1; i < args.length; ++i) {
    if (args[i] === '--file') {
      inputPath = args[i + 1]
      ++i
    } else if (args[i] === '--patch') {
      patchPath = args[i + 1]
      ++i
    } else if (args[i] === '--output') {
      outputPath = args[i + 1]
      ++i
    } else if (args[i] === '--group-bitfield') {
      groupBitFields.push(args[i + 1])
      ++i
    } else if (args[i] === '--remove') {
      removeNodes.push(args[i + 1])
    }
  }

  // var inputSvd = path.basename(inputPath)

  var inputData
  try {
    inputData = fs.readFileSync(inputPath, 'utf8')
  } catch (err) {
    // ctx.console.log(er.message)
    return callback(err)
  }
  ctx.console.log(`\nInput file '${inputPath}' read.`)

  svd = JSON.parse(inputData)

  if (!validate()) {
    return callback(null)
  }

  reorderNodes(svd.device)

  var periph_array = []
  svd.device.peripherals.forEach(periph => periph_array.push(periph.name));
  ctx.console.log(`Peripherals: ${periph_array.join(' ')}`);

  var patchData
  try {
    patchData = fs.readFileSync(patchPath, 'utf8')
  } catch (err) {
    // context.console.log(er.message)
    return callback(err)
  }
  ctx.console.log(`\nPatch file '${patchPath}' read.`)

  var patch = JSON.parse(patchData)

  if (!patchSvd(patch)) {
    return callback(null)
  }

  var dirPath
  var out

  utilsMisc.addGenerator(svd, 'xcdl', ctx.packageJson.version, args)
  out = JSON.stringify(svd, null, '\t')

  var dirPath = path.dirname(outputPath)
  if (!fs.existsSync(dirPath)) {
    fs.mkdirSync(dirPath)
  }
  fs.writeFileSync(outputPath, out, 'utf8')
  ctx.console.log(`\nOutput file '${outputPath}' written.`)

  return callback(null)
}

// ----------------------------------------------------------------------------

var validate = function () {
  if (!svd.device) {
    ctx.console.error(`Mandatory 'device' missing.`)
    return false
  }
  if (!svd.device.peripherals) {
    ctx.console.error(`Mandatory 'device.peripherals' missing.`)
    return false
  }
  return true
}

var reorderNodes = function (node) {

  if (node.peripherals) {
    node.peripherals.sort((f1, f2) => {
      // Return a negative value if f1 < f2; compare names.
      if (f1.name < f2.name) {
        return -1
      } else if (f1.name > f2.name) {
        return 1
      } else {
        return 0
      }
    })
    node.peripherals.forEach(peripheral => {
      reorderNodes(peripheral)
    })
  }
  if (node.registers) {
    node.registers.forEach(reg => {
      reorderNodes(reg)
    })
  }
  if (node.fields) {
    node.fields.sort((f1, f2) => {
      // Return a negative value if f1 < f2; compare bit offsets.
      return parseInt(f1.bitOffset, 10) - parseInt(f2.bitOffset, 10)
    })
  }
}

var patchSvd = function (patch) {
  if (!svd.device || !svd.device.name || !svd.generators) {
    ctx.console.error('Input file not a SVD.')
    return false
  }
  if (!patch.device || !patch.device.name) {
    ctx.console.error('Patch file not a SVD.')
    return false
  }

  if (svd.device.name !== patch.device.name) {
    ctx.console.error('Patch refer to different device.')
    return false
  }

  ctx.console.log('\nChanges:')

  removeNodes.forEach(path => {
    var [element, index, array] = findObject(svd, path.split('/'))
    if (element) {
      ctx.console.log(`- node '${path}' removed`)
      array.splice(index, 1)
    }
  })

  if (patch.device.cpu) {
    // Possibly patch the cpu object.
    if (!svd.device.cpu) {
      // It is not present at all, copy entirely object.
      svd.device.cpu = patch.device.cpu
      ctx.console.log(`- 'cpu' added from patch`)
    } else {
      for (var key in patch.device.cpu) {
        if (!svd.device.cpu[key]) {
          // Copy only missing properties.
          svd.device.cpu[key] = patch.device.cpu[key]
          ctx.console.log(`cpu.${key} added.`)
        }
      }
    }
  }

  compareAndUpdate(patch.device, svd.device)

  for (var i = 0; i < groupBitFields.length; ++i) {
    doGroupBitfield(groupBitFields[i])
  }
  return true
}

var doGroupBitfield = function (path) {
  // ctx.console.log(path)

  var pa = path.split('/')
  if (pa.length < 2) {
    ctx.console.error(`Path ${path} must be at least two levels deep.`)
    return null
  }
  var bitfield_name = pa.pop()
  var path_prefix = pa.join('/') + '/'

  var [register, ,] = findObject(svd, pa.slice())

  if (register.fields) {
    var minOffset = 32
    var maxOffset = 0
    var preservedField;

    for (var i = 0; i < register.fields.length; ++i) {
      var field = register.fields[i];
      var re = new RegExp(bitfield_name + '[0-9]+')
      if (field.name.match(re)) {
        var full_name = path_prefix + field.name

        // ctx.console.log(field.name)
        if (field.bitWidth !== "1") {
          ctx.console.error(`Field ${field} has bitWidth != 1.`)
          return null
        }

        if (preservedField) {
          if (field.access !== preservedField.access) {
            ctx.console.error(`Field ${full_name} has different access.`)
          }
        }

        var offset = parseInt(field.bitOffset, 10)
        if (offset < minOffset) {
          minOffset = offset
        }
        if (offset > maxOffset) {
          maxOffset = offset
        }

        if (preservedField) {
          // Remove subsequent fields in the same group
          // ctx.console.log(`- field ${full_name} removed`)

          register.fields.splice(i, 1)
          i--
        } else {
          preservedField = field
        }
      }
    }
    var prev_name = path_prefix + preservedField.name
    preservedField.name = bitfield_name
    preservedField.bitOffset = minOffset.toString()
    preservedField.bitWidth = (maxOffset - minOffset + 1).toString()
    var name = path_prefix + bitfield_name
    // ctx.console.log(`- field ${prev_name} renamed ${name} and grouped from ${maxOffset - minOffset + 1} single bit fields`)
    ctx.console.log(`- field ${name} grouped from ${maxOffset - minOffset + 1} single bit fields`)

  } else {
    return null
  }
}

// Find peripherals, register, bitfields.
// Return a triplet [value, index, array] or null
var findObject = function (svd_node, path_array, depth = 0) {
  var name = path_array[0]
  path_array.splice(0, 1)

  if (svd_node.device && svd_node.device.peripherals) {
    // Search peripherals
    var peripherals = svd_node.device.peripherals
    for (var i = 0; i < peripherals.length; ++i) {
      var peripheral = peripherals[i];
      if (peripheral.name === name) {
        if (path_array.length == 0) {
          return [peripheral, i, peripherals]
        } else {
          return findObject(peripheral, path_array, depth + 1)
        }
      }
    }
  }

  if (svd_node.registers) {
    for (var i = 0; i < svd_node.registers.length; ++i) {
      var register = svd_node.registers[i];
      if (register.name === name) {
        if (path_array.length == 0) {
          return [register, i, svd_node.registers]
        } else {
          return findObject(register, path_array, depth + 1)
        }
      }
    }
  }

  if (svd_node.fields) {
    for (var i = 0; i < svd_node.fields.length; ++i) {
      var field = svd_node.fields[i];
      if (field.name === name) {
        if (path_array.length == 0) {
          return [field, i, svd_node.fields]
        } else {
          return findObject(field, path_array, depth + 1)
        }
      }
    }
  }
  return [null]
}

// Compare trees and update.
// Only qemuAlignment and qemuGroupName are processed.

var compareAndUpdate = function (patch_node, svd_node, depth = 0) {

  if (patch_node.qemuAlignment && !svd_node.qemuAlignment) {
    svd_node.qemuAlignment = patch_node.qemuAlignment
    ctx.console.log(`- qemuAlignment: '${patch_node.qemuAlignment}' added to ${patch_node.name}`)
  }

  if (patch_node.qemuGroupName && !svd_node.qemuGroupName) {
    svd_node.qemuGroupName = patch_node.qemuGroupName
    ctx.console.log(`- qemuGroupName: '${patch_node.qemuGroupName}' added to ${patch_node.name}`)
  }

  if (patch_node.peripherals) {
    if (svd_node.peripherals) {
      // Search peripherals
      var peripherals = patch_node.peripherals
      for (var i = 0; i < peripherals.length; ++i) {
        var peripheral = peripherals[i];
        var periph_name = peripheral.name
        if (periph_name) {
          var svd_periph = svd_node.peripherals.find(periph => { return periph.name === periph_name })
          if (svd_periph) {
            compareAndUpdate(peripheral, svd_periph, depth + 1)
          }
        } else {
          ctx.console.log(`* peripheral node has no name.`)
        }
      }
    } else {
      ctx.console.log(`* node ${patch_node.name} has no peripherals.`)
    }
  }

  if (patch_node.registers) {
    if (svd_node.registers) {
      // Search peripherals
      var registers = patch_node.registers
      for (var i = 0; i < registers.length; ++i) {
        var register = registers[i];
        var register_name = register.name
        if (register_name) {
          var svd_register = svd_node.registers.find(register => { return register.name === register_name })
          if (svd_register) {
            compareAndUpdate(register, svd_register, depth + 1)
          }
        } else {
          ctx.console.log(`* register node has no name.`)
        }
      }
    } else {
      ctx.console.log(`* node ${patch_node.name} has no registers.`)
    }
  }

}
<|endoftext|>


<commit_before>export const SET_USER = 'SET_USER';
function setUser(user) {
  return {
    type: SET_USER,
    payload: user,
  };
}

export function fetchUser() {
  return dispatch => {
    return fetch(`${process.env.REACT_APP_SERVER_BASE}user`, {
      credentials: 'include',
    })
      .then(response => {
        if (response.status !== 200) {
          if (response.status === 401) {
            // Unauthorized
            return null;
          }
          throw new Error(response.statusText);
        }
        return response.json();
      })
      .then(user => dispatch(setUser(user)));
  };
}
<commit_msg>Don't crash when the user fetch fails<commit_after>import { captureException } from 'common/errorLogger';

export const SET_USER = 'SET_USER';
function setUser(user) {
  return {
    type: SET_USER,
    payload: user,
  };
}

export function fetchUser() {
  return dispatch => {
    return fetch(`${process.env.REACT_APP_SERVER_BASE}user`, {
      credentials: 'include',
    })
      .then(response => {
        if (response.status !== 200) {
          if (response.status === 401) {
            // Unauthorized
            return null;
          }
          throw new Error(response.statusText);
        }
        return response.json();
      })
      .then(user => dispatch(setUser(user)))
      .catch(err => {
        captureException(err);
        console.error(err);
        // fail silently since this only enhances the experience, if we're shortly down it shouldn't *kill* the experience.
      });
  };
}
<|endoftext|>


<commit_before>'use strict';

const testUtils = require('../testUtils');
const chai = require('chai');
const stripe = require('../lib/stripe')(testUtils.getUserStripeKey(), 'latest');
const fs = require('fs');
const path = require('path');
const stream = require('stream');
const expect = chai.expect;

const CUSTOMER_DETAILS = {
  description: 'Some customer',
  card: 'tok_visa',
};

let CURRENCY = '_DEFAULT_CURRENCY_NOT_YET_GOTTEN_';

describe('Flows', function() {
  // Note: These tests must be run as one so we can retrieve the
  // default_currency (required in subsequent tests);

  const cleanup = new testUtils.CleanupUtility();
  this.timeout(30000);

  it('Allows me to retrieve default_currency', () =>
    expect(
      stripe.account.retrieve().then((acct) => {
        CURRENCY = acct.default_currency;
        return acct;
      })
    ).to.eventually.have.property('default_currency'));

  describe('Plan+Subscription flow', () => {
    it('Allows me to: Create a plan and subscribe a customer to it', () =>
      expect(
        Promise.all([
          stripe.plans.create({
            id: `plan${testUtils.getRandomString()}`,
            amount: 1700,
            currency: CURRENCY,
            interval: 'month',
            nickname: 'Gold Super Amazing Tier',
            product: {
              name: `product${testUtils.getRandomString()}`,
            },
          }),
          stripe.customers.create(CUSTOMER_DETAILS),
        ]).then((j) => {
          const plan = j[0];
          const customer = j[1];

          cleanup.deleteCustomer(customer.id);
          cleanup.deletePlan(plan.id);

          return stripe.subscriptions.create({
            customer: customer.id,
            plan: plan.id,
          });
        })
      ).to.eventually.have.property('status', 'active'));

    it('Allows me to: Create a plan and subscribe a customer to it, and update subscription', () => {
      let plan;
      return expect(
        Promise.all([
          stripe.plans.create({
            id: `plan${testUtils.getRandomString()}`,
            amount: 1700,
            currency: CURRENCY,
            interval: 'month',
            nickname: 'Gold Super Amazing Tier',
            product: {
              name: `product${testUtils.getRandomString()}`,
            },
          }),
          stripe.customers.create(CUSTOMER_DETAILS),
        ])
          .then((j) => {
            plan = j[0];
            const customer = j[1];

            cleanup.deleteCustomer(customer.id);
            cleanup.deletePlan(plan.id);

            return stripe.subscriptions.create({
              customer: customer.id,
              plan: plan.id,
            });
          })
          .then((subscription) =>
            stripe.subscriptions.update(subscription.id, {
              plan: plan.id,
              quantity: 3,
            })
          )
          .then((subscription) => [subscription.status, subscription.quantity])
      ).to.eventually.deep.equal(['active', 3]);
    });

    it('Errors when I attempt to subscribe a customer to a non-existent plan', () =>
      expect(
        stripe.customers.create(CUSTOMER_DETAILS).then((customer) => {
          cleanup.deleteCustomer(customer.id);

          return stripe.subscriptions
            .create({
              customer: customer.id,
              plan: `someNonExistentPlan${testUtils.getRandomString()}`,
            })
            .then(
              null,
              (err) =>
                // Resolve with the error so we can inspect it below
                err
            );
        })
      ).to.eventually.satisfy(
        (err) =>
          err.type === 'StripeInvalidRequestError' &&
          err.rawType === 'invalid_request_error'
      ));

    it('Allows me to: subscribe then update with `cancel_at_period_end` defined', () =>
      expect(
        Promise.all([
          stripe.plans.create({
            id: `plan${testUtils.getRandomString()}`,
            amount: 1700,
            currency: CURRENCY,
            interval: 'month',
            nickname: 'Silver Super Amazing Tier',
            product: {
              name: `product${testUtils.getRandomString()}`,
            },
          }),
          stripe.customers.create(CUSTOMER_DETAILS),
        ])
          .then((j) => {
            const plan = j[0];
            const customer = j[1];

            cleanup.deleteCustomer(customer.id);
            cleanup.deletePlan(plan.id);

            return stripe.subscriptions.create({
              customer: customer.id,
              plan: plan.id,
            });
          })
          .then((subscription) =>
            stripe.subscriptions.update(subscription.id, {
              cancel_at_period_end: true,
            })
          )
      ).to.eventually.have.property('cancel_at_period_end', true));

    describe('Plan name variations', () => {
      [
        `34535_355453${testUtils.getRandomString()}`,
        `TEST_239291${testUtils.getRandomString()}`,
        `TEST_a-i${testUtils.getRandomString()}`,
        `foobarbazteston___etwothree${testUtils.getRandomString()}`,
      ].forEach((planID) => {
        it(`Allows me to create and retrieve plan with ID: ${planID}`, () =>
          expect(
            stripe.plans
              .create({
                id: planID,
                amount: 1700,
                currency: CURRENCY,
                interval: 'month',
                nickname: 'generic',
                product: {
                  name: `product${testUtils.getRandomString()}`,
                },
              })
              .then(() => {
                cleanup.deletePlan(planID);
                return stripe.plans.retrieve(planID);
              })
          ).to.eventually.have.property('id', planID));
      });
    });
  });

  describe('Coupon flow', () => {
    let customer;
    let coupon;

    describe('When I create a coupon & customer', () => {
      it('Does so', () =>
        expect(
          Promise.all([
            stripe.coupons.create({
              percent_off: 20,
              duration: 'once',
            }),
            stripe.customers.create(CUSTOMER_DETAILS),
          ]).then((joined) => {
            coupon = joined[0];
            customer = joined[1];
          })
        ).to.not.be.eventually.rejected);
      describe('And I apply the coupon to the customer', () => {
        it('Does so', () =>
          expect(
            stripe.customers.update(customer.id, {
              coupon: coupon.id,
            })
          ).to.not.be.eventually.rejected);
        it('Can be retrieved from that customer', () =>
          expect(
            stripe.customers.retrieve(customer.id)
          ).to.eventually.have.nested.property(
            'discount.coupon.id',
            coupon.id
          ));
        describe('The resulting discount', () => {
          it('Can be removed', () =>
            expect(
              stripe.customers.deleteDiscount(customer.id)
            ).to.eventually.have.property('deleted', true));
          describe('Re-querying it', () => {
            it('Does indeed indicate that it is deleted', () =>
              expect(
                stripe.customers.retrieve(customer.id)
              ).to.eventually.have.property('discount', null));
          });
        });
      });
    });
  });

  describe('Expanding', () => {
    describe('A customer within a charge', () => {
      it('Allows you to expand a customer object', () =>
        expect(
          stripe.customers.create(CUSTOMER_DETAILS).then((cust) => {
            cleanup.deleteCustomer(cust.id);
            return stripe.charges.create({
              customer: cust.id,
              amount: 1700,
              currency: CURRENCY,
              expand: ['customer'],
            });
          })
        ).to.eventually.have.nested.property('customer.created'));
    });
    describe("A customer's default source", () => {
      it('Allows you to expand a default_source', () =>
        expect(
          stripe.customers
            .create({
              description: 'Some customer',
              source: 'tok_visa',
              expand: ['default_source'],
            })
            .then((cust) => {
              cleanup.deleteCustomer(cust.id);
              return cust;
            })
          // Confirm it's expanded by checking that some prop (e.g. exp_year) exists:
        ).to.eventually.have.nested.property('default_source.exp_year'));
    });
  });

  describe('Charge', () => {
    it('Allows you to create a charge', () =>
      expect(
        stripe.charges
          .create({
            amount: 1234,
            currency: CURRENCY,
            card: 'tok_chargeDeclined',
            shipping: {
              name: 'Bobby Tables',
              address: {
                line1: '1 Foo St.',
              },
            },
          })
          .then(null, (error) => error)
      ).to.eventually.have.nested.property('raw.charge'));
  });

  describe('Getting balance', () => {
    it('Allows me to do so', () =>
      expect(stripe.balance.retrieve()).to.eventually.have.property(
        'object',
        'balance'
      ));
    it('Allows me to do so with specified auth key', () =>
      expect(
        stripe.balance.retrieve(testUtils.getUserStripeKey())
      ).to.eventually.have.property('object', 'balance'));
  });

  describe('Request/Response Events', () => {
    let connectedAccountId;

    before((done) => {
      // Pick a random connected account to use in the `Stripe-Account` header
      stripe.accounts
        .list({
          limit: 1,
        })
        .then((accounts) => {
          if (accounts.data.length < 1) {
            return done(
              new Error(
                'Test requires at least one Connected Account in the Test Account'
              )
            );
          }

          connectedAccountId = accounts.data[0].id;

          done();
        });
    });

    it('should emit a `request` event to listeners on request', (done) => {
      const apiVersion = '2017-06-05';
      const idempotencyKey = Math.random()
        .toString(36)
        .slice(2);
      const lowerBoundStartTime = Date.now();

      function onRequest(request) {
        expect(request.api_version).to.equal('latest');
        expect(request.idempotency_key).to.equal(idempotencyKey);
        expect(request.account).to.equal(connectedAccountId);
        expect(request.method).to.equal('POST');
        expect(request.path).to.equal('/v1/charges');
        expect(request.request_start_time).to.be.within(
          lowerBoundStartTime,
          Date.now()
        );

        done();
      }

      stripe.once('request', onRequest);

      stripe.charges
        .create(
          {
            amount: 1234,
            currency: 'usd',
            card: 'tok_chargeDeclined',
          },
          {
            stripe_version: apiVersion,
            idempotency_key: idempotencyKey,
            stripe_account: connectedAccountId,
          }
        )
        .then(null, () => {
          // I expect there to be an error here.
        });
    });

    it('should emit a `response` event to listeners on response', (done) => {
      const apiVersion = '2017-06-05';
      const idempotencyKey = Math.random()
        .toString(36)
        .slice(2);

      function onResponse(response) {
        // On the off chance we're picking up a response from a differentrequest
        // then just ignore this and wait for the right one:
        if (response.idempotency_key !== idempotencyKey) {
          return;
        }

        stripe.off('response', onResponse);

        expect(response.api_version).to.equal(apiVersion);
        expect(response.idempotency_key).to.equal(idempotencyKey);
        expect(response.account).to.equal(connectedAccountId);
        expect(response.method).to.equal('POST');
        expect(response.path).to.equal('/v1/charges');
        expect(response.request_id).to.match(/req_[\w\d]/);
        expect(response.status).to.equal(402);
        expect(response.elapsed).to.equal(
          response.request_end_time - response.request_start_time
        );
        expect(response.request_end_time).to.be.within(
          response.request_end_time,
          Date.now()
        );

        done();
      }

      stripe.on('response', onResponse);

      stripe.charges
        .create(
          {
            amount: 1234,
            currency: 'usd',
            card: 'tok_chargeDeclined',
          },
          {
            stripe_version: apiVersion,
            idempotency_key: idempotencyKey,
            stripe_account: connectedAccountId,
          }
        )
        .then(null, () => {
          // I expect there to be an error here.
        });
    });

    it('should not emit a `response` event to removed listeners on response', (done) => {
      function onResponse(response) {
        done(new Error('How did you get here?'));
      }

      stripe.once('response', onResponse);
      stripe.off('response', onResponse);

      stripe.charges
        .create({
          amount: 1234,
          currency: 'usd',
          card: 'tok_visa',
        })
        .then(() => {
          done();
        });
    });
  });

  describe('File', () => {
    it('Allows you to upload a file as a stream', () => {
      const testFilename = path.join(__dirname, 'resources/data/minimal.pdf');
      const f = fs.createReadStream(testFilename);

      return expect(
        stripe.files
          .create({
            purpose: 'dispute_evidence',
            file: {
              data: f,
              name: 'minimal.pdf',
              type: 'application/octet-stream',
            },
          })
          .then(null, (error) => error)
      ).to.eventually.have.nested.property('size', 739);
    });

    it('Allows you to upload a file synchronously', () => {
      const testFilename = path.join(__dirname, 'resources/data/minimal.pdf');
      const f = fs.readFileSync(testFilename);

      return expect(
        stripe.files
          .create({
            purpose: 'dispute_evidence',
            file: {
              data: f,
              name: 'minimal.pdf',
              type: 'application/octet-stream',
            },
          })
          .then(null, (error) => error)
      ).to.eventually.have.nested.property('size', 739);
    });

    it('Surfaces stream errors correctly', (done) => {
      const mockedStream = new stream.Readable();
      mockedStream._read = () => {};

      const fakeError = new Error('I am a fake error');

      process.nextTick(() => {
        mockedStream.emit('error', fakeError);
      });

      stripe.files
        .create({
          purpose: 'dispute_evidence',
          file: {
            data: mockedStream,
            name: 'minimal.pdf',
            type: 'application/octet-stream',
          },
        })
        .catch((error) => {
          expect(error.message).to.equal(
            'An error occurred while attempting to process the file for upload.'
          );
          expect(error.detail).to.equal(fakeError);

          done();
        });
    });
  });
});
<commit_msg>Fix flows test (#737)<commit_after>'use strict';

const testUtils = require('../testUtils');
const chai = require('chai');
const stripe = require('../lib/stripe')(testUtils.getUserStripeKey(), 'latest');
const fs = require('fs');
const path = require('path');
const stream = require('stream');
const expect = chai.expect;

const CUSTOMER_DETAILS = {
  description: 'Some customer',
  card: 'tok_visa',
};

let CURRENCY = '_DEFAULT_CURRENCY_NOT_YET_GOTTEN_';

describe('Flows', function() {
  // Note: These tests must be run as one so we can retrieve the
  // default_currency (required in subsequent tests);

  const cleanup = new testUtils.CleanupUtility();
  this.timeout(30000);

  it('Allows me to retrieve default_currency', () =>
    expect(
      stripe.account.retrieve().then((acct) => {
        CURRENCY = acct.default_currency;
        return acct;
      })
    ).to.eventually.have.property('default_currency'));

  describe('Plan+Subscription flow', () => {
    it('Allows me to: Create a plan and subscribe a customer to it', () =>
      expect(
        Promise.all([
          stripe.plans.create({
            id: `plan${testUtils.getRandomString()}`,
            amount: 1700,
            currency: CURRENCY,
            interval: 'month',
            nickname: 'Gold Super Amazing Tier',
            product: {
              name: `product${testUtils.getRandomString()}`,
            },
          }),
          stripe.customers.create(CUSTOMER_DETAILS),
        ]).then((j) => {
          const plan = j[0];
          const customer = j[1];

          cleanup.deleteCustomer(customer.id);
          cleanup.deletePlan(plan.id);

          return stripe.subscriptions.create({
            customer: customer.id,
            plan: plan.id,
          });
        })
      ).to.eventually.have.property('status', 'active'));

    it('Allows me to: Create a plan and subscribe a customer to it, and update subscription', () => {
      let plan;
      return expect(
        Promise.all([
          stripe.plans.create({
            id: `plan${testUtils.getRandomString()}`,
            amount: 1700,
            currency: CURRENCY,
            interval: 'month',
            nickname: 'Gold Super Amazing Tier',
            product: {
              name: `product${testUtils.getRandomString()}`,
            },
          }),
          stripe.customers.create(CUSTOMER_DETAILS),
        ])
          .then((j) => {
            plan = j[0];
            const customer = j[1];

            cleanup.deleteCustomer(customer.id);
            cleanup.deletePlan(plan.id);

            return stripe.subscriptions.create({
              customer: customer.id,
              plan: plan.id,
            });
          })
          .then((subscription) =>
            stripe.subscriptions.update(subscription.id, {
              plan: plan.id,
              quantity: 3,
            })
          )
          .then((subscription) => [subscription.status, subscription.quantity])
      ).to.eventually.deep.equal(['active', 3]);
    });

    it('Errors when I attempt to subscribe a customer to a non-existent plan', () =>
      expect(
        stripe.customers.create(CUSTOMER_DETAILS).then((customer) => {
          cleanup.deleteCustomer(customer.id);

          return stripe.subscriptions
            .create({
              customer: customer.id,
              plan: `someNonExistentPlan${testUtils.getRandomString()}`,
            })
            .then(
              null,
              (err) =>
                // Resolve with the error so we can inspect it below
                err
            );
        })
      ).to.eventually.satisfy(
        (err) =>
          err.type === 'StripeInvalidRequestError' &&
          err.rawType === 'invalid_request_error'
      ));

    it('Allows me to: subscribe then update with `cancel_at_period_end` defined', () =>
      expect(
        Promise.all([
          stripe.plans.create({
            id: `plan${testUtils.getRandomString()}`,
            amount: 1700,
            currency: CURRENCY,
            interval: 'month',
            nickname: 'Silver Super Amazing Tier',
            product: {
              name: `product${testUtils.getRandomString()}`,
            },
          }),
          stripe.customers.create(CUSTOMER_DETAILS),
        ])
          .then((j) => {
            const plan = j[0];
            const customer = j[1];

            cleanup.deleteCustomer(customer.id);
            cleanup.deletePlan(plan.id);

            return stripe.subscriptions.create({
              customer: customer.id,
              plan: plan.id,
            });
          })
          .then((subscription) =>
            stripe.subscriptions.update(subscription.id, {
              cancel_at_period_end: true,
            })
          )
      ).to.eventually.have.property('cancel_at_period_end', true));

    describe('Plan name variations', () => {
      [
        `34535_355453${testUtils.getRandomString()}`,
        `TEST_239291${testUtils.getRandomString()}`,
        `TEST_a-i${testUtils.getRandomString()}`,
        `foobarbazteston___etwothree${testUtils.getRandomString()}`,
      ].forEach((planID) => {
        it(`Allows me to create and retrieve plan with ID: ${planID}`, () =>
          expect(
            stripe.plans
              .create({
                id: planID,
                amount: 1700,
                currency: CURRENCY,
                interval: 'month',
                nickname: 'generic',
                product: {
                  name: `product${testUtils.getRandomString()}`,
                },
              })
              .then(() => {
                cleanup.deletePlan(planID);
                return stripe.plans.retrieve(planID);
              })
          ).to.eventually.have.property('id', planID));
      });
    });
  });

  describe('Coupon flow', () => {
    let customer;
    let coupon;

    describe('When I create a coupon & customer', () => {
      it('Does so', () =>
        expect(
          Promise.all([
            stripe.coupons.create({
              percent_off: 20,
              duration: 'once',
            }),
            stripe.customers.create(CUSTOMER_DETAILS),
          ]).then((joined) => {
            coupon = joined[0];
            customer = joined[1];
          })
        ).to.not.be.eventually.rejected);
      describe('And I apply the coupon to the customer', () => {
        it('Does so', () =>
          expect(
            stripe.customers.update(customer.id, {
              coupon: coupon.id,
            })
          ).to.not.be.eventually.rejected);
        it('Can be retrieved from that customer', () =>
          expect(
            stripe.customers.retrieve(customer.id)
          ).to.eventually.have.nested.property(
            'discount.coupon.id',
            coupon.id
          ));
        describe('The resulting discount', () => {
          it('Can be removed', () =>
            expect(
              stripe.customers.deleteDiscount(customer.id)
            ).to.eventually.have.property('deleted', true));
          describe('Re-querying it', () => {
            it('Does indeed indicate that it is deleted', () =>
              expect(
                stripe.customers.retrieve(customer.id)
              ).to.eventually.have.property('discount', null));
          });
        });
      });
    });
  });

  describe('Expanding', () => {
    describe('A customer within a charge', () => {
      it('Allows you to expand a customer object', () =>
        expect(
          stripe.customers.create(CUSTOMER_DETAILS).then((cust) => {
            cleanup.deleteCustomer(cust.id);
            return stripe.charges.create({
              customer: cust.id,
              amount: 1700,
              currency: CURRENCY,
              expand: ['customer'],
            });
          })
        ).to.eventually.have.nested.property('customer.created'));
    });
    describe("A customer's default source", () => {
      it('Allows you to expand a default_source', () =>
        expect(
          stripe.customers
            .create({
              description: 'Some customer',
              source: 'tok_visa',
              expand: ['default_source'],
            })
            .then((cust) => {
              cleanup.deleteCustomer(cust.id);
              return cust;
            })
          // Confirm it's expanded by checking that some prop (e.g. exp_year) exists:
        ).to.eventually.have.nested.property('default_source.exp_year'));
    });
  });

  describe('Charge', () => {
    it('Allows you to create a charge', () =>
      expect(
        stripe.charges
          .create({
            amount: 1234,
            currency: CURRENCY,
            card: 'tok_chargeDeclined',
            shipping: {
              name: 'Bobby Tables',
              address: {
                line1: '1 Foo St.',
              },
            },
          })
          .then(null, (error) => error)
      ).to.eventually.have.nested.property('raw.charge'));
  });

  describe('Getting balance', () => {
    it('Allows me to do so', () =>
      expect(stripe.balance.retrieve()).to.eventually.have.property(
        'object',
        'balance'
      ));
    it('Allows me to do so with specified auth key', () =>
      expect(
        stripe.balance.retrieve(testUtils.getUserStripeKey())
      ).to.eventually.have.property('object', 'balance'));
  });

  describe('Request/Response Events', () => {
    let connectedAccountId;

    before((done) => {
      // Pick a random connected account to use in the `Stripe-Account` header
      stripe.accounts
        .list({
          limit: 1,
        })
        .then((accounts) => {
          if (accounts.data.length < 1) {
            return done(
              new Error(
                'Test requires at least one Connected Account in the Test Account'
              )
            );
          }

          connectedAccountId = accounts.data[0].id;

          done();
        });
    });

    it('should emit a `request` event to listeners on request', (done) => {
      const apiVersion = '2017-06-05';
      const idempotencyKey = Math.random()
        .toString(36)
        .slice(2);
      const lowerBoundStartTime = Date.now();

      function onRequest(request) {
        expect(request.api_version).to.equal('latest');
        expect(request.idempotency_key).to.equal(idempotencyKey);
        expect(request.account).to.equal(connectedAccountId);
        expect(request.method).to.equal('POST');
        expect(request.path).to.equal('/v1/customers');
        expect(request.request_start_time).to.be.within(
          lowerBoundStartTime,
          Date.now()
        );

        done();
      }

      stripe.once('request', onRequest);

      stripe.customers
        .create(
          {
            description: 'stripe-node test customer',
            not_a_param: 'garbage, please 400',
          },
          {
            stripe_version: apiVersion,
            idempotency_key: idempotencyKey,
            stripe_account: connectedAccountId,
          }
        )
        .then(null, () => {
          // I expect there to be an error here.
        });
    });

    it('should emit a `response` event to listeners on response', (done) => {
      const apiVersion = '2017-06-05';
      const idempotencyKey = Math.random()
        .toString(36)
        .slice(2);

      function onResponse(response) {
        // On the off chance we're picking up a response from a differentrequest
        // then just ignore this and wait for the right one:
        if (response.idempotency_key !== idempotencyKey) {
          return;
        }

        stripe.off('response', onResponse);

        expect(response.api_version).to.equal(apiVersion);
        expect(response.idempotency_key).to.equal(idempotencyKey);
        expect(response.account).to.equal(connectedAccountId);
        expect(response.method).to.equal('POST');
        expect(response.path).to.equal('/v1/customers');
        expect(response.request_id).to.match(/req_[\w\d]/);
        expect(response.status).to.equal(400);
        expect(response.elapsed).to.equal(
          response.request_end_time - response.request_start_time
        );
        expect(response.request_end_time).to.be.within(
          response.request_end_time,
          Date.now()
        );

        done();
      }

      stripe.on('response', onResponse);

      stripe.customers
        .create(
          {
            description: 'stripe-node test customer',
            not_a_param: 'garbage, please 400',
          },
          {
            stripe_version: apiVersion,
            idempotency_key: idempotencyKey,
            stripe_account: connectedAccountId,
          }
        )
        .then(null, () => {
          // I expect there to be an error here.
        });
    });

    it('should not emit a `response` event to removed listeners on response', (done) => {
      function onResponse(response) {
        done(new Error('How did you get here?'));
      }

      stripe.once('response', onResponse);
      stripe.off('response', onResponse);

      stripe.customers
        .create({
          description: 'stripe-node test customer',
        })
        .then(() => {
          done();
        });
    });
  });

  describe('File', () => {
    it('Allows you to upload a file as a stream', () => {
      const testFilename = path.join(__dirname, 'resources/data/minimal.pdf');
      const f = fs.createReadStream(testFilename);

      return expect(
        stripe.files
          .create({
            purpose: 'dispute_evidence',
            file: {
              data: f,
              name: 'minimal.pdf',
              type: 'application/octet-stream',
            },
          })
          .then(null, (error) => error)
      ).to.eventually.have.nested.property('size', 739);
    });

    it('Allows you to upload a file synchronously', () => {
      const testFilename = path.join(__dirname, 'resources/data/minimal.pdf');
      const f = fs.readFileSync(testFilename);

      return expect(
        stripe.files
          .create({
            purpose: 'dispute_evidence',
            file: {
              data: f,
              name: 'minimal.pdf',
              type: 'application/octet-stream',
            },
          })
          .then(null, (error) => error)
      ).to.eventually.have.nested.property('size', 739);
    });

    it('Surfaces stream errors correctly', (done) => {
      const mockedStream = new stream.Readable();
      mockedStream._read = () => {};

      const fakeError = new Error('I am a fake error');

      process.nextTick(() => {
        mockedStream.emit('error', fakeError);
      });

      stripe.files
        .create({
          purpose: 'dispute_evidence',
          file: {
            data: mockedStream,
            name: 'minimal.pdf',
            type: 'application/octet-stream',
          },
        })
        .catch((error) => {
          expect(error.message).to.equal(
            'An error occurred while attempting to process the file for upload.'
          );
          expect(error.detail).to.equal(fakeError);

          done();
        });
    });
  });
});
<|endoftext|>


<commit_before>describe('@sanity/default-layout: Navbar', () => {
  it('should render ActionModal on top of Desk Tool’s pane headers', () => {
    cy.visit('/test/desk')

    cy.get('[data-testid="default-layout-global-create-button"]').click()

    cy.get('[data-testid="default-layout-global-create-dialog"]').should(
      'have.css',
      'z-index',
      '500801'
    )

    cy.get(
      '[data-testid="desk-tool-list-pane"] [data-test="components-default-pane-header"]'
    ).should('have.css', 'z-index', '101')
  })
})
<commit_msg>test(default-layout): update e2e test<commit_after>describe('@sanity/default-layout: Navbar', () => {
  it('should render ActionModal on top of Desk Tool’s pane headers', () => {
    cy.visit('/test/desk')

    cy.get('[data-testid="default-layout-global-create-button"]').click()

    cy.get('[data-testid="default-layout-global-create-dialog"]').should(
      'have.css',
      'z-index',
      '500801'
    )

    cy.get('[data-testid="desk-tool-list-pane"] [data-testid="pane-header"]').should(
      'have.css',
      'z-index',
      '101'
    )
  })
})
<|endoftext|>


<commit_before>import React from 'react';
import { connect } from 'react-redux';
import * as UserUtil from '../utils/user';
import * as I from 'immutable';

import Container from '../components/container';
import Button from '../components/button';
import FontAwesome from 'react-fontawesome';
import NitList from '../components/nit-list';
import * as NitActions from '../action-creators/nit';
import * as C from '../constants';
import cx from 'classnames';

function mapStateToProps(state) {
  return {
    loggedInUser: state.session.get('user', I.Map()),
    allNits: state.profile.get('nits', I.List()),
    friendships: state.profile.get('friendships', I.List()),
  };
}

function mapDispatchToProps(dispatch) {
  return {
    saveNitToDb: () => dispatch(NitActions.saveNitToDb()),
    saveNitToState: (nitInfo) => {
      dispatch(NitActions.saveNitToState(nitInfo));
    },
  };
}

function UserProfile({
    params: { profileId },
    saveNitToDb,
    saveNitToState,
    loggedInUser,
    allNits,
    friendships,
  }) {
  const userIsOnHisOwnProfile = loggedInUser.get('id') === profileId;
  const profileUser = friendships
                        .map((friendship) => friendship.get('friend'))
                        .push(loggedInUser)
                        .filter((friend) => friend.get('id') === profileId).get(0, I.Map());

  return (
    <Container size={2} center>

        <div
          className="circle border white"
          style={{
            width: '100px',
            height: '100px',
            margin: 'auto',
            backgroundSize: 'cover',
            backgroundImage: `url(${UserUtil.getUserFbProfileUrl(profileUser.get('facebookId'), 'normal')})`,
            backgroundPosition: 'center center',
          }}/>

          {profileUser.get('name')}

            <div
              className="circle border white"
              style={{
                width: '25px',
                height: '25px',
                minWidth: '25px',
                minHeight: '25px',
                marginTop: '0',
                marginRight: '10px',
                backgroundSize: 'cover',
                backgroundImage: `url(${UserUtil.getUserFbProfileUrl(loggedInUser.get('facebookId'), 'normal')})`,
                backgroundPosition: 'center center',
              }}/>
              <textarea
                className="mb1"
                autoFocus
                rows="7"
                onBlur={(e) => saveNitToState({
                  id: profileId,
                  nitContent: e.target.value,
                })}
                style={{ 'width': '100%', borderWidth: '2px', border: 'none', resize: 'none' }}/>

            <div style={{'width': '100%', 'textAlign': 'right', borderTop: `1px solid ${C.grey200}`}} >
              <Button className="bg-white white" style={{width: '100px', paddingTop: '5px', paddingBottom: '5px', borderRadius: '0px', borderLeft: `1px solid ${C.grey200}`}} onClick={() => saveNitToDb()}>

                  <FontAwesome
                    className="fa-check"
                    name="facebookSignIn"/>

Post

              </Button>

            {
              allNits.length > 0
              ? <NitList nitList={allNits}/>
              :

                  no public nits found

            }

    </Container>
  );
}

UserProfile.propTypes = {
  params: React.PropTypes.object,
  saveNitToDb: React.PropTypes.func,
  saveNitToState: React.PropTypes.func,
  loggedInUser: React.PropTypes.instanceOf(I.Map),
  allNits: React.PropTypes.instanceOf(I.List),
  friendships: React.PropTypes.instanceOf(I.List),
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(UserProfile);
<commit_msg>Make only the relevant nits show up on user profile<commit_after>import React from 'react';
import { connect } from 'react-redux';
import * as UserUtil from '../utils/user';
import * as I from 'immutable';

import Container from '../components/container';
import Button from '../components/button';
import FontAwesome from 'react-fontawesome';
import NitList from '../components/nit-list';
import * as NitActions from '../action-creators/nit';
import * as C from '../constants';
import cx from 'classnames';

function mapStateToProps(state) {
  return {
    loggedInUser: state.session.get('user', I.Map()),
    allNits: state.profile.get('nits', I.List()),
    friendships: state.profile.get('friendships', I.List()),
  };
}

function mapDispatchToProps(dispatch) {
  return {
    saveNitToDb: () => dispatch(NitActions.saveNitToDb()),
    saveNitToState: (nitInfo) => {
      dispatch(NitActions.saveNitToState(nitInfo));
    },
  };
}

function UserProfile({
    params: { profileId },
    saveNitToDb,
    saveNitToState,
    loggedInUser,
    allNits,
    friendships,
  }) {
  const userIsOnHisOwnProfile = loggedInUser.get('id') === profileId;
  const profileUser = friendships
                        .map((friendship) => friendship.get('friend'))
                        .push(loggedInUser)
                        .filter((friend) => friend.get('id') === profileId).get(0, I.Map());
  const nitsForCurrentUser = allNits.filter((nit) => nit.getIn(['user', 'id']) === profileUser.get('id'));
  return (
    <Container size={2} center>

        <div
          className="circle border white"
          style={{
            width: '100px',
            height: '100px',
            margin: 'auto',
            backgroundSize: 'cover',
            backgroundImage: `url(${UserUtil.getUserFbProfileUrl(profileUser.get('facebookId'), 'normal')})`,
            backgroundPosition: 'center center',
          }}/>

          {profileUser.get('name')}

            <div
              className="circle border white"
              style={{
                width: '25px',
                height: '25px',
                minWidth: '25px',
                minHeight: '25px',
                marginTop: '0',
                marginRight: '10px',
                backgroundSize: 'cover',
                backgroundImage: `url(${UserUtil.getUserFbProfileUrl(loggedInUser.get('facebookId'), 'normal')})`,
                backgroundPosition: 'center center',
              }}/>
              <textarea
                className="mb1"
                autoFocus
                rows="7"
                onBlur={(e) => saveNitToState({
                  id: profileId,
                  nitContent: e.target.value,
                })}
                style={{ 'width': '100%', borderWidth: '2px', border: 'none', resize: 'none' }}/>

            <div style={{'width': '100%', 'textAlign': 'right', borderTop: `1px solid ${C.grey200}`}} >
              <Button className="bg-white white" style={{width: '100px', paddingTop: '5px', paddingBottom: '5px', borderRadius: '0px', borderLeft: `1px solid ${C.grey200}`}} onClick={() => saveNitToDb()}>

                  <FontAwesome
                    className="fa-check"
                    name="facebookSignIn"/>

Post

              </Button>

            {
              nitsForCurrentUser.size > 0
              ? <NitList nitList={nitsForCurrentUser}/>
              :

                  no public nits found

            }

    </Container>
  );
}

UserProfile.propTypes = {
  params: React.PropTypes.object,
  saveNitToDb: React.PropTypes.func,
  saveNitToState: React.PropTypes.func,
  loggedInUser: React.PropTypes.instanceOf(I.Map),
  allNits: React.PropTypes.instanceOf(I.List),
  friendships: React.PropTypes.instanceOf(I.List),
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(UserProfile);
<|endoftext|>


<commit_before>import inject from 'aurelia-dependency-injection';
import Platform from 'aurelia-pal';

@inject(Platform)
export class AdalManager {

  user = {
    isAuthenticated: false,
    userName: '',
    loginError: '',
    profile: null
  }

  constructor(platform){
    this.platform = platform; // all operations on pal are for adaljs internals
  }

  // TODO: move to constructor and rethink injection strategy (? factory)
  initialize(authContext) {
    this.adal = authContext;
    this.updateUserFromCache();
  }

  updateUserFromCache() {
    let resource = this.adal.config.loginResource;
    let token = this.adal.getCachedToken(resource);
    let user = this.adal.getCachedUser() || {};

    this.user.isAuthenticated = token !== null && token.length > 0;
    this.user.userName = user.userName || '';
    this.user.profile = user.profile || null;
    this.user.loginError = this.adal.getLoginError();
  }

  hashHandler(hash, redirectHandler, isNotCallbackHandler, nextHandler) {
    if (this.adal.isCallback(hash)) {
      let requestInfo = this.adal.getRequestInfo(hash);

      this.adal.saveTokenFromHash(requestInfo);

      if (requestInfo.requestType !== this.adal.REQUEST_TYPE.LOGIN) {
        this.adal.callback = this.platform.global.parent.AuthenticationContext().callback; //window.parent.AuthenticationContext().callback;
        if (requestInfo.requestType === this.adal.REQUEST_TYPE.RENEW_TOKEN) {
          this.adal.callback = this.platform.global.parent.callBackMappedToRenewStates[requestInfo.stateResponse]; // window.parent.callBackMappedToRenewStates[requestInfo.stateResponse];
        }
      }

      // Return to callback if it is sent from iframe
      if (requestInfo.stateMatch) {
        if (typeof this.adal.callback === 'function') {
          // Call within the same context without full page redirect keeps the callback
          if (requestInfo.requestType === this.adal.REQUEST_TYPE.RENEW_TOKEN) {
            // Idtoken or Accestoken can be renewed
            if (requestInfo.parameters['access_token']) {
              this.adal.callback(this.adal._getItem(this.adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['access_token']);
              return nextHandler();
            } else if (requestInfo.parameters['id_token']) {
              this.adal.callback(this.adal._getItem(this.adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['id_token']);
              return nextHandler();
            }
          }
        } else {
          // normal full login redirect happened on the page
          this.updateUserFromCache();

          if (this.user.userName) {
            //IDtoken is added as token for the app

            // redirect to login requested page
            var loginStartPage = this.adal._getItem(this.adal.CONSTANTS.STORAGE.START_PAGE);
            if (loginStartPage) {
              return redirectHandler(loginStartPage);
            }
            // TODO: broadcast login success?
          } else {
            // TODO: broadcast login failure? (reason: this.adal._getItem(this.adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION))
          }
        }
      }
    } else {
      return isNotCallbackHandler();
    }
  }

  loginHandler(path, redirectHandler, handler) {
    this.adal.info('Login event for:' + path);

    if (this.adal.config && this.adal.config.localLoginUrl) {
      return redirectHandler(this.adal.config.localLoginUrl);
    } else {
      // directly start login flow
      this.adal._saveItem(this.adal.CONSTANTS.STORAGE.START_PAGE, path);
      this.adal.info('Start login at:' + this.platform.location.href); // window.location.href);
      // TODO: broadcast login redirect?
      this.adal.login();
      return handler();
    }
  }

  async loadTokenForRequest(requestUrl, onExistingTokenFound, onNewTokenAcquired) {
    let resource = this.adal.getResourceForEndpoint(requestUrl);
    if (resource == null) {
      return;
    }

    let tokenStored = this.adal.getCachedToken(resource);
    let isEndpoint = false;

    if (tokenStored) {
      this.adal.info('Token is avaliable for this url ' + requestUrl);

      // check endpoint mapping if provided
      onExistingTokenFound(tokenStored)//request.headers.append('Authorization', 'Bearer ' + tokenStored);
    } else {
      if (this.adal.config) {
        isEndpoint = this.adal.config.endpoints.some(url => requestUrl.indexOf(url) > -1);
      }

      // Cancel request if login is starting
      if (this.adal.loginInProgress()) {
        this.adal.info('login already started.');

        throw new Error('login already started');
      } else if (this.adal.config && isEndpoint) {
        // external endpoints
        // delayed request to return after iframe completes
        let token = await this.adal.acquireToken(resource);

        this.adal.verbose('Token is avaliable');
        onNewTokenAcquired(token); // request.headers.set('Authorization', 'Bearer ' + token);
      }
    }
  }

  handleRequestFailed(requestUrl, requestNotAuthorized) {
    this.adal.info('Getting error in the response');

    if (requestNotAuthorized) {
      var resource = this.adal.getResourceForEndpoint(requestUrl);
      this.adal.clearCacheForResource(resource);
      // TODO: broadcast notAuthorized?
    }
  }

}<commit_msg>added logout to adal-manager<commit_after>import inject from 'aurelia-dependency-injection';
import Platform from 'aurelia-pal';

@inject(Platform)
export class AdalManager {

  user = {
    isAuthenticated: false,
    userName: '',
    loginError: '',
    profile: null
  }

  constructor(platform){
    this.platform = platform; // all operations on pal are for adaljs internals
  }

  // TODO: move to constructor and rethink injection strategy (? factory)
  initialize(authContext) {
    this.adal = authContext;
    this.updateUserFromCache();
  }

  updateUserFromCache() {
    let resource = this.adal.config.loginResource;
    let token = this.adal.getCachedToken(resource);
    let user = this.adal.getCachedUser() || {};

    this.user.isAuthenticated = token !== null && token.length > 0;
    this.user.userName = user.userName || '';
    this.user.profile = user.profile || null;
    this.user.loginError = this.adal.getLoginError();
  }

  hashHandler(hash, redirectHandler, isNotCallbackHandler, nextHandler) {
    if (this.adal.isCallback(hash)) {
      let requestInfo = this.adal.getRequestInfo(hash);

      this.adal.saveTokenFromHash(requestInfo);

      if (requestInfo.requestType !== this.adal.REQUEST_TYPE.LOGIN) {
        this.adal.callback = this.platform.global.parent.AuthenticationContext().callback; //window.parent.AuthenticationContext().callback;
        if (requestInfo.requestType === this.adal.REQUEST_TYPE.RENEW_TOKEN) {
          this.adal.callback = this.platform.global.parent.callBackMappedToRenewStates[requestInfo.stateResponse]; // window.parent.callBackMappedToRenewStates[requestInfo.stateResponse];
        }
      }

      // Return to callback if it is sent from iframe
      if (requestInfo.stateMatch) {
        if (typeof this.adal.callback === 'function') {
          // Call within the same context without full page redirect keeps the callback
          if (requestInfo.requestType === this.adal.REQUEST_TYPE.RENEW_TOKEN) {
            // Idtoken or Accestoken can be renewed
            if (requestInfo.parameters['access_token']) {
              this.adal.callback(this.adal._getItem(this.adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['access_token']);
              return nextHandler();
            } else if (requestInfo.parameters['id_token']) {
              this.adal.callback(this.adal._getItem(this.adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['id_token']);
              return nextHandler();
            }
          }
        } else {
          // normal full login redirect happened on the page
          this.updateUserFromCache();

          if (this.user.userName) {
            //IDtoken is added as token for the app

            // redirect to login requested page
            var loginStartPage = this.adal._getItem(this.adal.CONSTANTS.STORAGE.START_PAGE);
            if (loginStartPage) {
              return redirectHandler(loginStartPage);
            }
            // TODO: broadcast login success?
          } else {
            // TODO: broadcast login failure? (reason: this.adal._getItem(this.adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION))
          }
        }
      }
    } else {
      return isNotCallbackHandler();
    }
  }

  loginHandler(path, redirectHandler, handler) {
    this.adal.info('Login event for:' + path);

    if (this.adal.config && this.adal.config.localLoginUrl) {
      return redirectHandler(this.adal.config.localLoginUrl);
    } else {
      // directly start login flow
      this.adal._saveItem(this.adal.CONSTANTS.STORAGE.START_PAGE, path);
      this.adal.info('Start login at:' + this.platform.location.href); // window.location.href);
      // TODO: broadcast login redirect?
      this.adal.login();
      return handler();
    }
  }

  async loadTokenForRequest(requestUrl, onExistingTokenFound, onNewTokenAcquired) {
    let resource = this.adal.getResourceForEndpoint(requestUrl);
    if (resource == null) {
      return;
    }

    let tokenStored = this.adal.getCachedToken(resource);
    let isEndpoint = false;

    if (tokenStored) {
      this.adal.info('Token is avaliable for this url ' + requestUrl);

      // check endpoint mapping if provided
      onExistingTokenFound(tokenStored)//request.headers.append('Authorization', 'Bearer ' + tokenStored);
    } else {
      if (this.adal.config) {
        isEndpoint = this.adal.config.endpoints.some(url => requestUrl.indexOf(url) > -1);
      }

      // Cancel request if login is starting
      if (this.adal.loginInProgress()) {
        this.adal.info('login already started.');

        throw new Error('login already started');
      } else if (this.adal.config && isEndpoint) {
        // external endpoints
        // delayed request to return after iframe completes
        let token = await this.adal.acquireToken(resource);

        this.adal.verbose('Token is avaliable');
        onNewTokenAcquired(token); // request.headers.set('Authorization', 'Bearer ' + token);
      }
    }
  }

  handleRequestFailed(requestUrl, requestNotAuthorized) {
    this.adal.info('Getting error in the response');

    if (requestNotAuthorized) {
      var resource = this.adal.getResourceForEndpoint(requestUrl);
      this.adal.clearCacheForResource(resource);
      // TODO: broadcast notAuthorized?
    }
  }

  logout() {
    this.adal.logOut();
  }

}<|endoftext|>