<commit_before>exports.config = {
    //
    // ==================
    // Specify Test Files
    // ==================
    // Define which test specs should run. The pattern is relative to the
    // directory from which `wdio` was called. Notice that, if you are calling
    // `wdio` from an NPM script (see https://docs.npmjs.com/cli/run-script)
    // then the current working directory is where your package.json resides, so
    // `wdio` will be called from there.
    //
    specs: [
        './src/features/**/*.feature',
    ],
    // Patterns to exclude.
    exclude: [
        // 'path/to/excluded/files'
    ],
    //
    // ============
    // Capabilities
    // ============
    // Define your capabilities here. WebdriverIO can run multiple capabilities
    // at the same time. Depending on the number of capabilities, WebdriverIO
    // launches several test sessions. Within your capabilities you can
    // overwrite the spec and exclude options in order to group specific specs
    // to a specific capability.
    //
    // First, you can define how many instances should be started at the same
    // time. Let's say you have 3 different capabilities (Chrome, Firefox, and
    // Safari) and you have set maxInstances to 1; wdio will spawn 3 processes.
    // Therefore, if you have 10 spec files and you set maxInstances to 10, all
    // spec files will get tested at the same time and 30 processes will get
    // spawned. The property handles how many capabilities from the same test
    // should run tests.
    //
    maxInstances: 5,
    //
    // If you have trouble getting all important capabilities together, check
    // out the Sauce Labs platform configurator - a great tool to configure your
    // capabilities: https://docs.saucelabs.com/reference/platforms-configurator
    //
    capabilities: [{
        // maxInstances can get overwritten per capability. So if you have an
        // in-house Selenium grid with only 5 firefox instance available you can
        // make sure that not more than 5 instance gets started at a time.
        maxInstances: 5,
        //
        browserName: 'firefox',
    }],
    //
    // ===================
    // Test Configurations
    // ===================
    // Define all options that are relevant for the WebdriverIO instance here
    //
    // By default WebdriverIO commands are executed in a synchronous way using
    // the wdio-sync package. If you still want to run your tests in an async
    // way e.g. using promises you can set the sync option to false.
    sync: true,
    //
    // Level of logging verbosity: silent | verbose | command | data | result |
    // error
    logLevel: 'error',
    //
    // Enables colors for log output.
    coloredLogs: true,
    //
    // Saves a screenshot to a given path if a command fails.
    screenshotPath: 'errorScreenShots',
    //
    // Set a base URL in order to shorten url command calls. If your url
    // parameter starts with "/", then the base url gets prepended.
    baseUrl: 'http://www.demo.guru99.com/v4/',
    //
    // Default timeout for all waitFor* commands.
    waitforTimeout: 10000,
    //
    // Default timeout in milliseconds for request
    // if Selenium Grid doesn't send response
    connectionRetryTimeout: 90000,
    //
    // Default request retries count
    connectionRetryCount: 3,
    //
    // Initialize the browser instance with a WebdriverIO plugin. The object
    // should have the plugin name as key and the desired plugin options as
    // properties. Make sure you have the plugin installed before running any
    // tests. The following plugins are currently available:
    // WebdriverCSS: https://github.com/webdriverio/webdrivercss
    // WebdriverRTC: https://github.com/webdriverio/webdriverrtc
    // Browserevent: https://github.com/webdriverio/Browserevent
    // plugins: {
    //     webdrivercss: {
    //         screenshotRoot: 'my-shots',
    //         failedComparisonsRoot: 'diffs',
    //         misMatchTolerance: 0.05,
    //         screenWidth: [320,480,640,1024]
    //     },
    //     webdriverrtc: {},
    //     browserevent: {}
    // },
    //
    // Test runner services
    // Services take over a specific job you don't want to take care of. They
    // enhance your test setup with almost no effort. Unlike plugins, they don't
    // add new commands. Instead, they hook themselves up into the test process.
    services: ['selenium-standalone'],
    //
    // Framework you want to run your specs with.
    // The following are supported: Mocha, Jasmine, and Cucumber
    // see also: http://webdriver.io/guide/testrunner/frameworks.html
    //
    // Make sure you have the wdio adapter package for the specific framework
    // installed before running any tests.
    framework: 'cucumber',
    //
    // Test reporter for stdout.
    // The only one supported by default is 'dot'
    // see also: http://webdriver.io/guide/testrunner/reporters.html
    reporters: ['spec','allure'],
    reporterOptions: {
		allure: {
			outputDir: 'allure-results'
		}
	},

    //
    // If you are using Cucumber you need to specify the location of your step
    // definitions.
    cucumberOpts: {
        // <boolean> show full backtrace for errors
        backtrace: false,
        // <string[]> filetype:compiler used for processing required features
        compiler: [
            'js:babel-register',
        ],
        // <boolean< Treat ambiguous definitions as errors
        failAmbiguousDefinitions: true,
        // <boolean> invoke formatters without executing steps
        // dryRun: false,
        // <boolean> abort the run on first failure
        failFast: false,
        // <boolean> Enable this config to treat undefined definitions as
        // warnings
        ignoreUndefinedDefinitions: false,
        // <string[]> ("extension:module") require files with the given
        // EXTENSION after requiring MODULE (repeatable)
        name: [],
        // <boolean> hide step definition snippets for pending steps
        snippets: true,
        // <boolean> hide source uris
        source: true,
        // <string[]> (name) specify the profile to use
        profile: [],
        // <string[]> (file/dir) require files before executing features
        require: [
            './src/steps/given.js',
            './src/steps/then.js',
            './src/steps/when.js'
        ],
        // <string> specify a custom snippet syntax
        snippetSyntax: undefined,
        // <boolean> fail if there are any undefined or pending steps
        strict: true,
        // <string> (expression) only execute the features or scenarios with
        // tags matching the expression, see
        // https://docs.cucumber.io/tag-expressions/
        tagExpression: 'not @Pending',
        // <boolean> add cucumber tags to feature or scenario name
        tagsInTitle: false,
        // <number> timeout for step definitions
        timeout: 20000,
    },

    //
    // =====
    // Hooks
    // =====
    // WebdriverIO provides several hooks you can use to interfere with the test
    // process in order to enhance it and to build services around it. You can
    // either apply a single function or an array of methods to it. If one of
    // them returns with a promise, WebdriverIO will wait until that promise got
    // resolved to continue.
    //
    // Gets executed once before all workers get launched.
    // onPrepare: function onPrepare(config, capabilities) {
    // },
    //
    // Gets executed before test execution begins. At this point you can access
    // all global variables, such as `browser`. It is the perfect place to
    // define custom commands.
    before: function before() {
        /**
         * Setup the Chai assertion framework
         */
		try{
			var fs = require('fs');

             var config =  require('./src/support/testDataConfig/config.js')();

		  var pathObj = require('path');

			 var deleteFolderRecursive = function(path) {
				if (fs.existsSync(path)) {

					fs.readdirSync(path).forEach(function(file, index) {

					var curPath = path + "/" + file;

						if (fs.lstatSync(curPath).isDirectory()) { // recurse

							//deleteFolderRecursive(curPath);

						} else { // delete file

							fs.unlinkSync(curPath);

						}

					});

					fs.rmdirSync(path);

				}	else {
					console.log(' not exists ');
				}

			};
			deleteFolderRecursive('allure-results');
			deleteFolderRecursive('allure-report');

		 }catch(e){
			 console.log('  err ', e.message);
		 }
	   const chai = require('chai');

        global.expect = chai.expect;
        global.assert = chai.assert;
        global.should = chai.should();

		global.execCommand = require('child_process').exec;

    },
    //
    // Hook that gets executed before the suite starts
    // beforeSuite: function beforeSuite(suite) {
    // },
    //
    // Hook that gets executed _before_ a hook within the suite starts (e.g.
    // runs before calling beforeEach in Mocha)
    // beforeHook: function beforeHook() {
    // },
    //
    // Hook that gets executed _after_ a hook within the suite starts (e.g. runs
    // after calling afterEach in Mocha)
    // afterHook: function afterHook() {
    // },
    //
    // Function to be executed before a test (in Mocha/Jasmine) or a step (in
    // Cucumber) starts.
    // beforeTest: function beforeTest(test) {
    // },
    //
    // Runs before a WebdriverIO command gets executed.
    // beforeCommand: function beforeCommand(commandName, args) {
    // },
    //
    // Runs after a WebdriverIO command gets executed
    // afterCommand: function afterCommand(commandName, args, result, error) {
    // },
    //
    // Function to be executed after a test (in Mocha/Jasmine) or a step (in
    // Cucumber) starts.
    // afterTest: function afterTest(test) {
    // },
    //
    // Hook that gets executed after the suite has ended
    // afterSuite: function afterSuite(suite) {
    // },
    //
    // Gets executed after all tests are done. You still have access to all
    // global variables from the test.
   after: function after(result, capabilities, specs) {

	   /*execCommand('allure generate allure-results --clean', function (err, stdout, stderr) {
			if( err ){
				console.log(' err allure generate ', err );
			} else {
				console.log(' allure generated successfully ');

			}
		})*/
    },
    //
    // Gets executed after all workers got shut down and the process is about to
    // exit. It is not possible to defer the end of the process using a promise.
    // onComplete: function onComplete(exitCode) {
    // }
};
<commit_msg>chrome<commit_after>exports.config = {
    //
    // ==================
    // Specify Test Files
    // ==================
    // Define which test specs should run. The pattern is relative to the
    // directory from which `wdio` was called. Notice that, if you are calling
    // `wdio` from an NPM script (see https://docs.npmjs.com/cli/run-script)
    // then the current working directory is where your package.json resides, so
    // `wdio` will be called from there.
    //
    specs: [
        './src/features/**/*.feature',
    ],
    // Patterns to exclude.
    exclude: [
        // 'path/to/excluded/files'
    ],
    //
    // ============
    // Capabilities
    // ============
    // Define your capabilities here. WebdriverIO can run multiple capabilities
    // at the same time. Depending on the number of capabilities, WebdriverIO
    // launches several test sessions. Within your capabilities you can
    // overwrite the spec and exclude options in order to group specific specs
    // to a specific capability.
    //
    // First, you can define how many instances should be started at the same
    // time. Let's say you have 3 different capabilities (Chrome, Firefox, and
    // Safari) and you have set maxInstances to 1; wdio will spawn 3 processes.
    // Therefore, if you have 10 spec files and you set maxInstances to 10, all
    // spec files will get tested at the same time and 30 processes will get
    // spawned. The property handles how many capabilities from the same test
    // should run tests.
    //
    maxInstances: 5,
    //
    // If you have trouble getting all important capabilities together, check
    // out the Sauce Labs platform configurator - a great tool to configure your
    // capabilities: https://docs.saucelabs.com/reference/platforms-configurator
    //
    capabilities: [{
        // maxInstances can get overwritten per capability. So if you have an
        // in-house Selenium grid with only 5 firefox instance available you can
        // make sure that not more than 5 instance gets started at a time.
        maxInstances: 5,
        //
        browserName: 'chrome',
    }],
    //
    // ===================
    // Test Configurations
    // ===================
    // Define all options that are relevant for the WebdriverIO instance here
    //
    // By default WebdriverIO commands are executed in a synchronous way using
    // the wdio-sync package. If you still want to run your tests in an async
    // way e.g. using promises you can set the sync option to false.
    sync: true,
    //
    // Level of logging verbosity: silent | verbose | command | data | result |
    // error
    logLevel: 'error',
    //
    // Enables colors for log output.
    coloredLogs: true,
    //
    // Saves a screenshot to a given path if a command fails.
    screenshotPath: 'errorScreenShots',
    //
    // Set a base URL in order to shorten url command calls. If your url
    // parameter starts with "/", then the base url gets prepended.
    baseUrl: 'http://www.demo.guru99.com/v4/',
    //
    // Default timeout for all waitFor* commands.
    waitforTimeout: 10000,
    //
    // Default timeout in milliseconds for request
    // if Selenium Grid doesn't send response
    connectionRetryTimeout: 90000,
    //
    // Default request retries count
    connectionRetryCount: 3,
    //
    // Initialize the browser instance with a WebdriverIO plugin. The object
    // should have the plugin name as key and the desired plugin options as
    // properties. Make sure you have the plugin installed before running any
    // tests. The following plugins are currently available:
    // WebdriverCSS: https://github.com/webdriverio/webdrivercss
    // WebdriverRTC: https://github.com/webdriverio/webdriverrtc
    // Browserevent: https://github.com/webdriverio/Browserevent
    // plugins: {
    //     webdrivercss: {
    //         screenshotRoot: 'my-shots',
    //         failedComparisonsRoot: 'diffs',
    //         misMatchTolerance: 0.05,
    //         screenWidth: [320,480,640,1024]
    //     },
    //     webdriverrtc: {},
    //     browserevent: {}
    // },
    //
    // Test runner services
    // Services take over a specific job you don't want to take care of. They
    // enhance your test setup with almost no effort. Unlike plugins, they don't
    // add new commands. Instead, they hook themselves up into the test process.
    services: ['selenium-standalone'],
    //
    // Framework you want to run your specs with.
    // The following are supported: Mocha, Jasmine, and Cucumber
    // see also: http://webdriver.io/guide/testrunner/frameworks.html
    //
    // Make sure you have the wdio adapter package for the specific framework
    // installed before running any tests.
    framework: 'cucumber',
    //
    // Test reporter for stdout.
    // The only one supported by default is 'dot'
    // see also: http://webdriver.io/guide/testrunner/reporters.html
    reporters: ['spec','allure'],
    reporterOptions: {
		allure: {
			outputDir: 'allure-results'
		}
	},

    //
    // If you are using Cucumber you need to specify the location of your step
    // definitions.
    cucumberOpts: {
        // <boolean> show full backtrace for errors
        backtrace: false,
        // <string[]> filetype:compiler used for processing required features
        compiler: [
            'js:babel-register',
        ],
        // <boolean< Treat ambiguous definitions as errors
        failAmbiguousDefinitions: true,
        // <boolean> invoke formatters without executing steps
        // dryRun: false,
        // <boolean> abort the run on first failure
        failFast: false,
        // <boolean> Enable this config to treat undefined definitions as
        // warnings
        ignoreUndefinedDefinitions: false,
        // <string[]> ("extension:module") require files with the given
        // EXTENSION after requiring MODULE (repeatable)
        name: [],
        // <boolean> hide step definition snippets for pending steps
        snippets: true,
        // <boolean> hide source uris
        source: true,
        // <string[]> (name) specify the profile to use
        profile: [],
        // <string[]> (file/dir) require files before executing features
        require: [
            './src/steps/given.js',
            './src/steps/then.js',
            './src/steps/when.js'
        ],
        // <string> specify a custom snippet syntax
        snippetSyntax: undefined,
        // <boolean> fail if there are any undefined or pending steps
        strict: true,
        // <string> (expression) only execute the features or scenarios with
        // tags matching the expression, see
        // https://docs.cucumber.io/tag-expressions/
        tagExpression: 'not @Pending',
        // <boolean> add cucumber tags to feature or scenario name
        tagsInTitle: false,
        // <number> timeout for step definitions
        timeout: 20000,
    },

    //
    // =====
    // Hooks
    // =====
    // WebdriverIO provides several hooks you can use to interfere with the test
    // process in order to enhance it and to build services around it. You can
    // either apply a single function or an array of methods to it. If one of
    // them returns with a promise, WebdriverIO will wait until that promise got
    // resolved to continue.
    //
    // Gets executed once before all workers get launched.
    // onPrepare: function onPrepare(config, capabilities) {
    // },
    //
    // Gets executed before test execution begins. At this point you can access
    // all global variables, such as `browser`. It is the perfect place to
    // define custom commands.
    before: function before() {
        /**
         * Setup the Chai assertion framework
         */
		try{
			var fs = require('fs');

             var config =  require('./src/support/testDataConfig/config.js')();

		  var pathObj = require('path');

			 var deleteFolderRecursive = function(path) {
				if (fs.existsSync(path)) {

					fs.readdirSync(path).forEach(function(file, index) {

					var curPath = path + "/" + file;

						if (fs.lstatSync(curPath).isDirectory()) { // recurse

							//deleteFolderRecursive(curPath);

						} else { // delete file

							fs.unlinkSync(curPath);

						}

					});

					fs.rmdirSync(path);

				}	else {
					console.log(' not exists ');
				}

			};
			deleteFolderRecursive('allure-results');
			deleteFolderRecursive('allure-report');

		 }catch(e){
			 console.log('  err ', e.message);
		 }
	   const chai = require('chai');

        global.expect = chai.expect;
        global.assert = chai.assert;
        global.should = chai.should();

		global.execCommand = require('child_process').exec;

    },
    //
    // Hook that gets executed before the suite starts
    // beforeSuite: function beforeSuite(suite) {
    // },
    //
    // Hook that gets executed _before_ a hook within the suite starts (e.g.
    // runs before calling beforeEach in Mocha)
    // beforeHook: function beforeHook() {
    // },
    //
    // Hook that gets executed _after_ a hook within the suite starts (e.g. runs
    // after calling afterEach in Mocha)
    // afterHook: function afterHook() {
    // },
    //
    // Function to be executed before a test (in Mocha/Jasmine) or a step (in
    // Cucumber) starts.
    // beforeTest: function beforeTest(test) {
    // },
    //
    // Runs before a WebdriverIO command gets executed.
    // beforeCommand: function beforeCommand(commandName, args) {
    // },
    //
    // Runs after a WebdriverIO command gets executed
    // afterCommand: function afterCommand(commandName, args, result, error) {
    // },
    //
    // Function to be executed after a test (in Mocha/Jasmine) or a step (in
    // Cucumber) starts.
    // afterTest: function afterTest(test) {
    // },
    //
    // Hook that gets executed after the suite has ended
    // afterSuite: function afterSuite(suite) {
    // },
    //
    // Gets executed after all tests are done. You still have access to all
    // global variables from the test.
   after: function after(result, capabilities, specs) {

	   /*execCommand('allure generate allure-results --clean', function (err, stdout, stderr) {
			if( err ){
				console.log(' err allure generate ', err );
			} else {
				console.log(' allure generated successfully ');

			}
		})*/
    },
    //
    // Gets executed after all workers got shut down and the process is about to
    // exit. It is not possible to defer the end of the process using a promise.
    // onComplete: function onComplete(exitCode) {
    // }
};
<|endoftext|>


<commit_before><commit_msg>Update TemplateView.js<commit_after><|endoftext|>


<commit_before>function findByIds(items, ids) {
  return ids
    .map((id) => {
      return items.find((item) => item.id === id)
    })
    .filter((item) => item)
}

function findOneById(items, id) {
  return items.find((item) => item.id === id)
}

function findOneByAliases(items, aliases) {
  if (Array.isArray(aliases)) {
    return items.find((item) => {
      let { name, alias } = item
      return aliases.find((n) => n === name || (alias && alias.includes(n)))
    })
  }

  return items.find((item) => {
    return item.name === aliases || (item.alias && item.alias.includes(aliases))
  })
}

module.exports = {
  findByIds, findOneById, findOneByAliases,
}
<commit_msg>Add findOneByName for usage with nested names<commit_after>function findByIds(items, ids) {
  return ids
    .map((id) => {
      return items.find((item) => item.id === id)
    })
    .filter((item) => item)
}

function findOneById(items, id) {
  return items.find((item) => item.id === id)
}

function findOneByAliases(items, aliases) {
  if (Array.isArray(aliases)) {
    return items.find((item) => {
      let { name, alias } = item
      return aliases.find((n) => n === name || (alias && alias.includes(n)))
    })
  }

  return items.find((item) => {
    return item.name === aliases || (item.alias && item.alias.includes(aliases))
  })
}

function findOneByName(items, field, name) {
  if (arguments.length === 2) {
    return findOneByAliases(items, field)
  } else if (typeof name === 'string') {
    return findOneByAliases(items, name)
  }

  let result

  for (let i = 0; i < name.length && items.length; i++) {
    result = findOneByName(items, name[i])

    if (result) {
      items = findByIds(items, result[field])
    }
  }

  return result
}

module.exports = {
  findByIds, findOneById, findOneByAliases, findOneByName,
}
<|endoftext|>


<commit_before>if (typeof(module) !== 'undefined' && typeof(exports) !== 'undefined') {
    module.exports = OAuth;
    var CryptoJS = require("crypto-js");
}

/**
 * Constructor
 * @param {Object} opts consumer key and secret
 */
function OAuth(opts) {
    if(!(this instanceof OAuth)) {
        return new OAuth(opts);
    }

    this.consumer = opts.consumer;
    this.signature_method = opts.signature_method || 'HMAC-SHA1';
    this.nonce_length = opts.nonce_length || 32;

    switch (this.signature_method) {
        case 'HMAC-SHA1':
            this.hash = function(base_string, key) {
                return CryptoJS.HmacSHA1(base_string, key).toString(CryptoJS.enc.Base64);
            };
            break;
        case 'PLAINTEXT':
            this.hash = function(base_string, key) {
                return key;
            };
            break;
        case 'RSA-SHA1':
            throw new Error('oauth-1.0a does not support this signature method right now. Coming Soon...');
            break;
        default:
            throw new Error('The OAuth 1.0a protocol defines three signature methods: HMAC-SHA1, RSA-SHA1, and PLAINTEXT only');
            break;
    }
}

/**
 * OAuth request authorize
 * @param  {Object} request data
 * {
 *     method,
 *     url,
 *     data
 * }
 * @param  {Object} public and secret token
 * @return {Object} OAuth Authorized data
 */
OAuth.prototype.authorize = function(request, token) {
    var oauth_data = {
        oauth_consumer_key: this.consumer.public,
        oauth_nonce: this.getNonce(this.nonce_length),
        oauth_signature_method: this.signature_method,
        oauth_timestamp: this.getTimeStamp(),
        oauth_version: '1.0'
    };

    if(!token) {
        token = {};
    }

    if(token.public) {
        oauth_data.oauth_token = token.public;
    }

    oauth_data.oauth_signature = this.getSignature(request, token.secret, oauth_data);

    return oauth_data;
};

/**
 * Create a OAuth Signature
 * @param  {Object} request data
 * @param  {Object} token_secret public and secret token
 * @param  {Object} oauth_data   OAuth data
 * @return {String} Signature
 */
OAuth.prototype.getSignature = function(request, token_secret, oauth_data) {
    return this.hash(this.getBaseString(request, oauth_data), this.getSigningKey(token_secret));
};

/**
 * Base String = Method + Base Url + ParameterString
 * @param  {Object} request data
 * @param  {Object} OAuth data
 * @return {String} Base String
 */
OAuth.prototype.getBaseString = function(request, oauth_data) {
    return request.method.toUpperCase() + '&' + this.percentEncode(this.getBaseUrl(request.url)) + '&' + this.percentEncode(this.getParameterString(request, oauth_data));
};

/**
 * Get data from url
 * -> merge with oauth data
 * -> percent encode key & value
 * -> sort
 *
 * @param  {Object} request data
 * @param  {Object} OAuth data
 * @return {Object} Parameter string data
 */
OAuth.prototype.getParameterString = function(request, oauth_data) {
    var base_string_data = this.sortObject(this.percentEncodeData(this.mergeObject(oauth_data, this.mergeObject(request.data, this.deParamUrl(request.url)))));

    var data_str = '';

    //base_string_data to string
    for(var key in base_string_data) {
        data_str += key + '=' + base_string_data[key] + '&';
    }

    //remove the last character
    data_str = data_str.substr(0, data_str.length - 1);
    return data_str;
};

/**
 * Create a Signing Key
 * @param  {String} token_secret Secret Token
 * @return {String} Signing Key
 */
OAuth.prototype.getSigningKey = function(token_secret) {
    token_secret = token_secret || '';
    return this.percentEncode(this.consumer.secret) + '&' + this.percentEncode(token_secret);
};

/**
 * Get base url
 * @param  {String} url
 * @return {String}
 */
OAuth.prototype.getBaseUrl = function(url) {
    return url.split('?')[0];
};

/**
 * Get data from String
 * @param  {String} string
 * @return {Object}
 */
OAuth.prototype.deParam = function(string) {
    var arr = decodeURIComponent(string).split('&');
    var data = {};

    for(var i = 0; i < arr.length; i++) {
        var item = arr[i].split('=');
        data[item[0]] = item[1];
    }
    return data;
};

/**
 * Get data from url
 * @param  {String} url
 * @return {Object}
 */
OAuth.prototype.deParamUrl = function(url) {
    var tmp = url.split('?');

    if (tmp.length === 1)
        return {};

    return this.deParam(tmp[1]);
};

/**
 * Percent Encode
 * @param  {String} str
 * @return {String} percent encoded string
 */
OAuth.prototype.percentEncode = function(str) {
    return encodeURIComponent(str)
        .replace(/\!/g, "%21")
        .replace(/\*/g, "%2A")
        .replace(/\'/g, "%27")
        .replace(/\(/g, "%28")
        .replace(/\)/g, "%29");
};

/**
 * Percent Encode Object
 * @param  {Object} data
 * @return {Object} percent encoded data
 */
OAuth.prototype.percentEncodeData = function(data) {
    var result = {};

    for(var key in data) {
        result[this.percentEncode(key)] = this.percentEncode(data[key]);
    }

    return result;
};

/**
 * Get OAuth data as Header
 * @param  {Object} oauth_data
 * @return {String} Header data key - value
 */
OAuth.prototype.toHeader = function(oauth_data) {
    oauth_data = this.sortObject(oauth_data);

    var header_value = 'OAuth ';

    for(var key in oauth_data) {
        if (key.indexOf('oauth_') === -1)
            continue;
        header_value += this.percentEncode(key) + '="' + this.percentEncode(oauth_data[key]) + '", ';
    }

    return {
        Authorization: header_value.substr(0, header_value.length - 2) //cut the last 2 chars
    };
};

/**
 * Create a random word characters string with input length
 * @param  {Int} length
 * @return {String} a random word characters string
 */
OAuth.prototype.getNonce = function(length) {
    var word_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    var result = '';

    for(var i = 0; i < length; i++) {
        result += word_characters[parseInt(Math.random() * word_characters.length, 10)];
    }

    return result;
};

/**
 * Get Current Unix TimeStamp
 * @return {Int} current unix timestamp
 */
OAuth.prototype.getTimeStamp = function() {
    return parseInt(new Date().getTime()/1000, 10);
};

////////////////////// HELPER FUNCTIONS //////////////////////

/**
 * Merge object
 * @param  {Object} obj1
 * @param  {Object} obj2
 * @return {Object}
 */
OAuth.prototype.mergeObject = function(obj1, obj2) {
    var merged_obj = obj1;
    for(var key in obj2) {
        merged_obj[key] = obj2[key];
    }
    return merged_obj;
};

/**
 * Sort object by key
 * @param  {Object} data
 * @return {Object} sorted object
 */
OAuth.prototype.sortObject = function(data) {
    var keys = Object.keys(data);
    var result = {};

    keys.sort();

    for(var i = 0; i < keys.length; i++) {
        var key = keys[i];
        result[key] = data[key];
    }

    return result;
};
<commit_msg>add add version option<commit_after>if (typeof(module) !== 'undefined' && typeof(exports) !== 'undefined') {
    module.exports = OAuth;
    var CryptoJS = require("crypto-js");
}

/**
 * Constructor
 * @param {Object} opts consumer key and secret
 */
function OAuth(opts) {
    if(!(this instanceof OAuth)) {
        return new OAuth(opts);
    }

    this.consumer = opts.consumer;
    this.signature_method = opts.signature_method || 'HMAC-SHA1';
    this.nonce_length = opts.nonce_length || 32;

    switch (this.signature_method) {
        case 'HMAC-SHA1':
            this.hash = function(base_string, key) {
                return CryptoJS.HmacSHA1(base_string, key).toString(CryptoJS.enc.Base64);
            };
            break;
        case 'PLAINTEXT':
            this.hash = function(base_string, key) {
                return key;
            };
            break;
        case 'RSA-SHA1':
            throw new Error('oauth-1.0a does not support this signature method right now. Coming Soon...');
            break;
        default:
            throw new Error('The OAuth 1.0a protocol defines three signature methods: HMAC-SHA1, RSA-SHA1, and PLAINTEXT only');
            break;
    }
}

/**
 * OAuth request authorize
 * @param  {Object} request data
 * {
 *     method,
 *     url,
 *     data
 * }
 * @param  {Object} public and secret token
 * @return {Object} OAuth Authorized data
 */
OAuth.prototype.authorize = function(request, token) {
    var oauth_data = {
        oauth_consumer_key: this.consumer.public,
        oauth_nonce: this.getNonce(this.nonce_length),
        oauth_signature_method: this.signature_method,
        oauth_timestamp: this.getTimeStamp(),
        oauth_version: this.version
    };

    if(!token) {
        token = {};
    }

    if(token.public) {
        oauth_data.oauth_token = token.public;
    }

    oauth_data.oauth_signature = this.getSignature(request, token.secret, oauth_data);

    return oauth_data;
};

/**
 * Create a OAuth Signature
 * @param  {Object} request data
 * @param  {Object} token_secret public and secret token
 * @param  {Object} oauth_data   OAuth data
 * @return {String} Signature
 */
OAuth.prototype.getSignature = function(request, token_secret, oauth_data) {
    return this.hash(this.getBaseString(request, oauth_data), this.getSigningKey(token_secret));
};

/**
 * Base String = Method + Base Url + ParameterString
 * @param  {Object} request data
 * @param  {Object} OAuth data
 * @return {String} Base String
 */
OAuth.prototype.getBaseString = function(request, oauth_data) {
    return request.method.toUpperCase() + '&' + this.percentEncode(this.getBaseUrl(request.url)) + '&' + this.percentEncode(this.getParameterString(request, oauth_data));
};

/**
 * Get data from url
 * -> merge with oauth data
 * -> percent encode key & value
 * -> sort
 *
 * @param  {Object} request data
 * @param  {Object} OAuth data
 * @return {Object} Parameter string data
 */
OAuth.prototype.getParameterString = function(request, oauth_data) {
    var base_string_data = this.sortObject(this.percentEncodeData(this.mergeObject(oauth_data, this.mergeObject(request.data, this.deParamUrl(request.url)))));

    var data_str = '';

    //base_string_data to string
    for(var key in base_string_data) {
        data_str += key + '=' + base_string_data[key] + '&';
    }

    //remove the last character
    data_str = data_str.substr(0, data_str.length - 1);
    return data_str;
};

/**
 * Create a Signing Key
 * @param  {String} token_secret Secret Token
 * @return {String} Signing Key
 */
OAuth.prototype.getSigningKey = function(token_secret) {
    token_secret = token_secret || '';
    return this.percentEncode(this.consumer.secret) + '&' + this.percentEncode(token_secret);
};

/**
 * Get base url
 * @param  {String} url
 * @return {String}
 */
OAuth.prototype.getBaseUrl = function(url) {
    return url.split('?')[0];
};

/**
 * Get data from String
 * @param  {String} string
 * @return {Object}
 */
OAuth.prototype.deParam = function(string) {
    var arr = decodeURIComponent(string).split('&');
    var data = {};

    for(var i = 0; i < arr.length; i++) {
        var item = arr[i].split('=');
        data[item[0]] = item[1];
    }
    return data;
};

/**
 * Get data from url
 * @param  {String} url
 * @return {Object}
 */
OAuth.prototype.deParamUrl = function(url) {
    var tmp = url.split('?');

    if (tmp.length === 1)
        return {};

    return this.deParam(tmp[1]);
};

/**
 * Percent Encode
 * @param  {String} str
 * @return {String} percent encoded string
 */
OAuth.prototype.percentEncode = function(str) {
    return encodeURIComponent(str)
        .replace(/\!/g, "%21")
        .replace(/\*/g, "%2A")
        .replace(/\'/g, "%27")
        .replace(/\(/g, "%28")
        .replace(/\)/g, "%29");
};

/**
 * Percent Encode Object
 * @param  {Object} data
 * @return {Object} percent encoded data
 */
OAuth.prototype.percentEncodeData = function(data) {
    var result = {};

    for(var key in data) {
        result[this.percentEncode(key)] = this.percentEncode(data[key]);
    }

    return result;
};

/**
 * Get OAuth data as Header
 * @param  {Object} oauth_data
 * @return {String} Header data key - value
 */
OAuth.prototype.toHeader = function(oauth_data) {
    oauth_data = this.sortObject(oauth_data);

    var header_value = 'OAuth ';

    for(var key in oauth_data) {
        if (key.indexOf('oauth_') === -1)
            continue;
        header_value += this.percentEncode(key) + '="' + this.percentEncode(oauth_data[key]) + '", ';
    }

    return {
        Authorization: header_value.substr(0, header_value.length - 2) //cut the last 2 chars
    };
};

/**
 * Create a random word characters string with input length
 * @param  {Int} length
 * @return {String} a random word characters string
 */
OAuth.prototype.getNonce = function(length) {
    var word_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    var result = '';

    for(var i = 0; i < length; i++) {
        result += word_characters[parseInt(Math.random() * word_characters.length, 10)];
    }

    return result;
};

/**
 * Get Current Unix TimeStamp
 * @return {Int} current unix timestamp
 */
OAuth.prototype.getTimeStamp = function() {
    return parseInt(new Date().getTime()/1000, 10);
};

////////////////////// HELPER FUNCTIONS //////////////////////

/**
 * Merge object
 * @param  {Object} obj1
 * @param  {Object} obj2
 * @return {Object}
 */
OAuth.prototype.mergeObject = function(obj1, obj2) {
    var merged_obj = obj1;
    for(var key in obj2) {
        merged_obj[key] = obj2[key];
    }
    return merged_obj;
};

/**
 * Sort object by key
 * @param  {Object} data
 * @return {Object} sorted object
 */
OAuth.prototype.sortObject = function(data) {
    var keys = Object.keys(data);
    var result = {};

    keys.sort();

    for(var i = 0; i < keys.length; i++) {
        var key = keys[i];
        result[key] = data[key];
    }

    return result;
};
<|endoftext|>


<commit_before>'use strict';

class Aliases {
	constructor( storage ) {
		this.data = storage.data;
		this.save = storage.save;
	}

	getValue( alias ) {
		return this.data[ alias ];
	}

	set( alias, value ) {
		this.data[ alias ] = value;
		this.save();
	}

	delete( alias ) {
		delete this.data[ alias ];
		this.save();
	}

	*[ Symbol.iterator ]() {
		for ( let alias in this.data ) {
			yield alias;
		}
	}

	resolve( text ) {
		for ( let alias of this ) {
			text = text.replace( new RegExp( alias, 'g' ), this.getValue( alias ) );
		}

		return text;
	}
}

module.exports = Aliases;
<commit_msg>Fix alias model.<commit_after>'use strict';

class Aliases {
	constructor( storage ) {
		this.storage = storage;
	}

	getValue( alias ) {
		return this.storage.data[ alias ];
	}

	set( alias, value ) {
		this.storage.data[ alias ] = value;
		this.storage.save();
	}

	delete( alias ) {
		delete this.storage.data[ alias ];
		this.storage.save();
	}

	*[ Symbol.iterator ]() {
		for ( let alias in this.storage.data ) {
			yield alias;
		}
	}

	resolve( text ) {
		for ( let alias of this ) {
			text = text.replace( new RegExp( alias, 'g' ), this.getValue( alias ) );
		}

		return text;
	}
}

module.exports = Aliases;
<|endoftext|>


<commit_before>/* eslint-disable import/no-mutable-exports */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import RNFS from 'react-native-fs';

import { SETTINGS_KEYS } from '../settings';
import { formatDate, requestPermission, backupValidation } from '../utilities';

const { THIS_STORE_NAME_ID } = SETTINGS_KEYS;

const translateToCoreDatabaseType = type => {
  switch (type) {
    case 'CustomerInvoice':
    case 'Prescription':
    case 'SupplierInvoice':
    case 'Receipt':
    case 'CustomerCredit':
    case 'Payment':
    case 'CashTransaction':
    case 'SupplierTransaction':
      return 'Transaction';
    case 'CashTransactionName':
    case 'Customer':
    case 'Supplier':
    case 'InternalSupplier':
    case 'ExternalSupplier':
    case 'Patient':
      return 'Name';
    case 'CashTransactionReason':
      return 'Options';
    case 'RequestRequisition':
    case 'ResponseRequisition':
      return 'Requisition';
    case 'RequisitionReason':
    case 'NegativeAdjustmentReason':
    case 'PositiveAdjustmentReason':
      return 'Options';
    case 'Policy':
      return 'InsurancePolicy';
    case 'Provider':
      return 'InsuranceProvider';
    case 'PrescriptionCategory':
    case 'SupplierCreditCategory':
      return 'TransactionCategory';
    default:
      return type;
  }
};

class UIDatabase {
  constructor(database) {
    this.database = database;
    this.EXPORT_DIRECTORY = '/Download/mSupplyMobile_data';
    this.DEFAULT_EXPORT_FILE = 'msupply-mobile-data';
  }

  ERRORS = {
    ERROR_IN_TRANSACTION: { code: 'ERROR_IN_TRANSACTION', message: 'Database is in a transaction' },
    ERROR_NO_PERMISSION: { code: 'ERROR_NO_PERMISSION', message: 'Storage permission not granted' },
    ERROR_UNKNOWN: { code: 'ERROR_UNKNOWN', message: 'Unkown error occurred' },
  };

  /**
   * Exports the realm file to '/Download/mSupplyMobile\ data' on device file system.
   * Ensures there is enough space, the realm exists and requests storage permission,
   * if required.
   */

  async exportData(filename = this.DEFAULT_EXPORT_FILE) {
    const { realm } = this.database;
    const { path: realmPath } = realm;
    const exportFolder = `${RNFS.ExternalStorageDirectoryPath}${this.EXPORT_DIRECTORY}`;
    // Replace all invalid characters in the android file system with an empty string.
    const copyFileName = `${filename}${formatDate(new Date(), 'dashes')}`.replace(
      /[~\\\\/|?*<:>"+]/g,
      ''
    );

    const permissionParameters = {
      permissionType: 'WRITE_EXTERNAL_STORAGE',
      message: 'Export database',
    };

    // Before requesting permissions, ensure there is enough space and the realm
    // file exists.
    const exportValidation = await backupValidation(realmPath);
    const { success } = exportValidation;
    if (!success) return exportValidation;
    // Request permissions for external storage before trying to backup the realm file.
    const { success: permissionSuccess } = await requestPermission(permissionParameters);
    // If permission was granted, ensure the realm is not in a transaction and backup
    // the realm file.
    if (!permissionSuccess) return { success: false, ...this.ERRORS.ERROR_NO_PERMISSION };
    if (realm.isInTransaction) return { success: false, ...this.ERRORS.ERROR_IN_TRANSACTION };

    // Finally try to create the backup/exported realm
    try {
      await RNFS.mkdir(exportFolder);
      await RNFS.copyFile(realmPath, `${exportFolder}/${copyFileName}.realm`);
    } catch (error) {
      return { success: false, ...this.ERRORS.ERROR_UNKNOWN, error };
    }

    return { success: true };
  }

  objects(type) {
    const results = this.database.objects(translateToCoreDatabaseType(type));
    const thisStoreNameIdSetting = this.database
      .objects('Setting')
      .filtered('key == $0', THIS_STORE_NAME_ID)[0];
    // |ownStoreIdSetting| will not exist if not initialised.
    const thisStoreNameId = thisStoreNameIdSetting && thisStoreNameIdSetting.value;

    switch (type) {
      case 'CustomerInvoice':
        // Only show invoices generated from requisitions once finalised.
        return results.filtered(
          'type == $0 AND (linkedRequisition == $1 OR status == $2)',
          'customer_invoice',
          null,
          'finalised'
        );
      case 'SupplierTransaction': {
        const queryString =
          // eslint-disable-next-line no-multi-str
          '((type == $0 AND mode == $2) OR (type == $1 AND status == $3))\
           AND otherParty.type != $4';
        return results.filtered(
          queryString,
          'supplier_invoice',
          'supplier_credit',
          'store',
          'finalised',
          'inventory_adjustment'
        );
      }
      case 'SupplierInvoice':
        return results.filtered(
          'type == $0 AND mode == $1 AND otherParty.type != $2',
          'supplier_invoice',
          'store',
          'inventory_adjustment'
        );
      case 'Receipt':
        return results.filtered('type == $0', 'receipt');
      case 'Payment':
        return results.filtered('type == $0', 'payment');
      case 'CashTransaction':
        return results.filtered('type == $0 OR type == $1', 'receipt', 'payment');
      case 'CashTransactionName':
        return results
          .filtered('isVisible == true && id != $0', thisStoreNameId)
          .filtered('isSupplier == true || isCustomer == true || isPatient == true');
      case 'CashTransactionReason':
        return results.filtered('type == $0', 'newCashOutTransaction');
      case 'CustomerCredit':
        return results.filtered('type == $0', 'customer_credit');
      case 'Policy':
        return results.filtered(
          'insuranceProvider.isActive == $0 && expiryDate > $1',
          true,
          new Date()
        );
      case 'Provider':
        return results.filtered('isActive == $0', true);
      case 'Customer':
        return results.filtered(
          'isVisible == true AND isCustomer == true AND id != $0 AND isPatient == false',
          thisStoreNameId
        );
      case 'Supplier':
        return results.filtered(
          'isVisible == true AND isSupplier == true AND id != $0',
          thisStoreNameId
        );
      case 'Patient':
        return results.filtered(
          'isVisible == true AND isPatient == true AND id != $0',
          thisStoreNameId
        );
      case 'InternalSupplier':
        return results.filtered(
          'isVisible == true AND isSupplier == true AND type == "store" AND id != $0',
          thisStoreNameId
        );
      case 'ExternalSupplier':
        return results.filtered('isVisible == true AND isSupplier == true AND type == "facility"');
      case 'Item':
        return results.filtered('isVisible == true');
      case 'RequestRequisition':
        return results.filtered('type == "request"');
      case 'ResponseRequisition':
        return results.filtered('serialNumber != "-1" AND type == "response"');
      case 'NegativeAdjustmentReason':
        return results.filtered('type == $0 && isActive == true', 'negativeInventoryAdjustment');
      case 'PositiveAdjustmentReason':
        return results.filtered('type == $0 && isActive == true', 'positiveInventoryAdjustment');
      case 'Prescription':
        return results.filtered(
          'type == $0 AND otherParty.type == $1 AND (linkedRequisition == $2 OR status == $3)',
          'customer_invoice',
          'patient',
          null,
          'finalised'
        );
      case 'PrescriptionCategory':
        return results.filtered('type == $0', 'prescription');
      case 'SupplierCreditCategory':
        return results.filtered('type == $0', 'supplier_credit');
      case 'RequisitionReason':
        return results.filtered('type == $0 && isActive == true', 'requisitionLineVariance');
      default:
        return results;
    }
  }

  get(...args) {
    return this.database.get(...args);
  }

  addListener(...args) {
    return this.database.addListener(...args);
  }

  removeListener(...args) {
    return this.database.removeListener(...args);
  }

  alertListeners(...args) {
    return this.database.alertListeners(...args);
  }

  create(...args) {
    return this.database.create(...args);
  }

  getOrCreate(...args) {
    return this.database.getOrCreate(...args);
  }

  delete(...args) {
    return this.database.delete(...args);
  }

  deleteAll(...args) {
    return this.database.deleteAll(...args);
  }

  save(...args) {
    return this.database.save(...args);
  }

  update(...args) {
    return this.database.update(...args);
  }

  write(...args) {
    return this.database.write(...args);
  }

  getPreference(key) {
    const preference = this.database.get('Pref', key);
    return preference?.data ?? '';
  }

  getSetting(key) {
    const setting = this.database.get('Setting', key, 'key');
    return setting?.value ?? '';
  }
}

let UIDatabaseInstance;

export const getUIDatabaseInstance = database => {
  if (!UIDatabaseInstance) {
    UIDatabaseInstance = new UIDatabase(database);
  }
  return UIDatabaseInstance;
};

// Factory function for custom UIDatabase PropTypes.
const createUIDatabasePropType = isRequired => (props, propName, componentName) => {
  const { [propName]: prop } = props;

  if (prop == null) {
    if (isRequired) {
      return new TypeError(`Missing database prop in ${componentName}`);
    }
    return null;
  }

  if (prop instanceof UIDatabase) return null;
  return new TypeError(`Invalid database prop in ${componentName}`);
};

export const UIDatabaseType = createUIDatabasePropType(false);
UIDatabaseType.isRequired = createUIDatabasePropType(true);

export default getUIDatabaseInstance;
<commit_msg>Update database preference getter<commit_after>/* eslint-disable import/no-mutable-exports */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import RNFS from 'react-native-fs';

import { SETTINGS_KEYS } from '../settings';
import { formatDate, requestPermission, backupValidation } from '../utilities';

const { THIS_STORE_NAME_ID } = SETTINGS_KEYS;

const translateToCoreDatabaseType = type => {
  switch (type) {
    case 'CustomerInvoice':
    case 'Prescription':
    case 'SupplierInvoice':
    case 'Receipt':
    case 'CustomerCredit':
    case 'Payment':
    case 'CashTransaction':
    case 'SupplierTransaction':
      return 'Transaction';
    case 'CashTransactionName':
    case 'Customer':
    case 'Supplier':
    case 'InternalSupplier':
    case 'ExternalSupplier':
    case 'Patient':
      return 'Name';
    case 'CashTransactionReason':
      return 'Options';
    case 'RequestRequisition':
    case 'ResponseRequisition':
      return 'Requisition';
    case 'RequisitionReason':
    case 'NegativeAdjustmentReason':
    case 'PositiveAdjustmentReason':
      return 'Options';
    case 'Policy':
      return 'InsurancePolicy';
    case 'Provider':
      return 'InsuranceProvider';
    case 'PrescriptionCategory':
    case 'SupplierCreditCategory':
      return 'TransactionCategory';
    default:
      return type;
  }
};

class UIDatabase {
  constructor(database) {
    this.database = database;
    this.EXPORT_DIRECTORY = '/Download/mSupplyMobile_data';
    this.DEFAULT_EXPORT_FILE = 'msupply-mobile-data';
  }

  ERRORS = {
    ERROR_IN_TRANSACTION: { code: 'ERROR_IN_TRANSACTION', message: 'Database is in a transaction' },
    ERROR_NO_PERMISSION: { code: 'ERROR_NO_PERMISSION', message: 'Storage permission not granted' },
    ERROR_UNKNOWN: { code: 'ERROR_UNKNOWN', message: 'Unkown error occurred' },
  };

  /**
   * Exports the realm file to '/Download/mSupplyMobile\ data' on device file system.
   * Ensures there is enough space, the realm exists and requests storage permission,
   * if required.
   */

  async exportData(filename = this.DEFAULT_EXPORT_FILE) {
    const { realm } = this.database;
    const { path: realmPath } = realm;
    const exportFolder = `${RNFS.ExternalStorageDirectoryPath}${this.EXPORT_DIRECTORY}`;
    // Replace all invalid characters in the android file system with an empty string.
    const copyFileName = `${filename}${formatDate(new Date(), 'dashes')}`.replace(
      /[~\\\\/|?*<:>"+]/g,
      ''
    );

    const permissionParameters = {
      permissionType: 'WRITE_EXTERNAL_STORAGE',
      message: 'Export database',
    };

    // Before requesting permissions, ensure there is enough space and the realm
    // file exists.
    const exportValidation = await backupValidation(realmPath);
    const { success } = exportValidation;
    if (!success) return exportValidation;
    // Request permissions for external storage before trying to backup the realm file.
    const { success: permissionSuccess } = await requestPermission(permissionParameters);
    // If permission was granted, ensure the realm is not in a transaction and backup
    // the realm file.
    if (!permissionSuccess) return { success: false, ...this.ERRORS.ERROR_NO_PERMISSION };
    if (realm.isInTransaction) return { success: false, ...this.ERRORS.ERROR_IN_TRANSACTION };

    // Finally try to create the backup/exported realm
    try {
      await RNFS.mkdir(exportFolder);
      await RNFS.copyFile(realmPath, `${exportFolder}/${copyFileName}.realm`);
    } catch (error) {
      return { success: false, ...this.ERRORS.ERROR_UNKNOWN, error };
    }

    return { success: true };
  }

  objects(type) {
    const results = this.database.objects(translateToCoreDatabaseType(type));
    const thisStoreNameIdSetting = this.database
      .objects('Setting')
      .filtered('key == $0', THIS_STORE_NAME_ID)[0];
    // |ownStoreIdSetting| will not exist if not initialised.
    const thisStoreNameId = thisStoreNameIdSetting && thisStoreNameIdSetting.value;

    switch (type) {
      case 'CustomerInvoice':
        // Only show invoices generated from requisitions once finalised.
        return results.filtered(
          'type == $0 AND (linkedRequisition == $1 OR status == $2)',
          'customer_invoice',
          null,
          'finalised'
        );
      case 'SupplierTransaction': {
        const queryString =
          // eslint-disable-next-line no-multi-str
          '((type == $0 AND mode == $2) OR (type == $1 AND status == $3))\
           AND otherParty.type != $4';
        return results.filtered(
          queryString,
          'supplier_invoice',
          'supplier_credit',
          'store',
          'finalised',
          'inventory_adjustment'
        );
      }
      case 'SupplierInvoice':
        return results.filtered(
          'type == $0 AND mode == $1 AND otherParty.type != $2',
          'supplier_invoice',
          'store',
          'inventory_adjustment'
        );
      case 'Receipt':
        return results.filtered('type == $0', 'receipt');
      case 'Payment':
        return results.filtered('type == $0', 'payment');
      case 'CashTransaction':
        return results.filtered('type == $0 OR type == $1', 'receipt', 'payment');
      case 'CashTransactionName':
        return results
          .filtered('isVisible == true && id != $0', thisStoreNameId)
          .filtered('isSupplier == true || isCustomer == true || isPatient == true');
      case 'CashTransactionReason':
        return results.filtered('type == $0', 'newCashOutTransaction');
      case 'CustomerCredit':
        return results.filtered('type == $0', 'customer_credit');
      case 'Policy':
        return results.filtered(
          'insuranceProvider.isActive == $0 && expiryDate > $1',
          true,
          new Date()
        );
      case 'Provider':
        return results.filtered('isActive == $0', true);
      case 'Customer':
        return results.filtered(
          'isVisible == true AND isCustomer == true AND id != $0 AND isPatient == false',
          thisStoreNameId
        );
      case 'Supplier':
        return results.filtered(
          'isVisible == true AND isSupplier == true AND id != $0',
          thisStoreNameId
        );
      case 'Patient':
        return results.filtered(
          'isVisible == true AND isPatient == true AND id != $0',
          thisStoreNameId
        );
      case 'InternalSupplier':
        return results.filtered(
          'isVisible == true AND isSupplier == true AND type == "store" AND id != $0',
          thisStoreNameId
        );
      case 'ExternalSupplier':
        return results.filtered('isVisible == true AND isSupplier == true AND type == "facility"');
      case 'Item':
        return results.filtered('isVisible == true');
      case 'RequestRequisition':
        return results.filtered('type == "request"');
      case 'ResponseRequisition':
        return results.filtered('serialNumber != "-1" AND type == "response"');
      case 'NegativeAdjustmentReason':
        return results.filtered('type == $0 && isActive == true', 'negativeInventoryAdjustment');
      case 'PositiveAdjustmentReason':
        return results.filtered('type == $0 && isActive == true', 'positiveInventoryAdjustment');
      case 'Prescription':
        return results.filtered(
          'type == $0 AND otherParty.type == $1 AND (linkedRequisition == $2 OR status == $3)',
          'customer_invoice',
          'patient',
          null,
          'finalised'
        );
      case 'PrescriptionCategory':
        return results.filtered('type == $0', 'prescription');
      case 'SupplierCreditCategory':
        return results.filtered('type == $0', 'supplier_credit');
      case 'RequisitionReason':
        return results.filtered('type == $0 && isActive == true', 'requisitionLineVariance');
      default:
        return results;
    }
  }

  get(...args) {
    return this.database.get(...args);
  }

  addListener(...args) {
    return this.database.addListener(...args);
  }

  removeListener(...args) {
    return this.database.removeListener(...args);
  }

  alertListeners(...args) {
    return this.database.alertListeners(...args);
  }

  create(...args) {
    return this.database.create(...args);
  }

  getOrCreate(...args) {
    return this.database.getOrCreate(...args);
  }

  delete(...args) {
    return this.database.delete(...args);
  }

  deleteAll(...args) {
    return this.database.deleteAll(...args);
  }

  save(...args) {
    return this.database.save(...args);
  }

  update(...args) {
    return this.database.update(...args);
  }

  write(...args) {
    return this.database.write(...args);
  }

  getPreference(key) {
    const preference = this.database.get('Pref', key);
    return preference?.value;
  }

  getSetting(key) {
    const setting = this.database.get('Setting', key, 'key');
    return setting?.value ?? '';
  }
}

let UIDatabaseInstance;

export const getUIDatabaseInstance = database => {
  if (!UIDatabaseInstance) {
    UIDatabaseInstance = new UIDatabase(database);
  }
  return UIDatabaseInstance;
};

// Factory function for custom UIDatabase PropTypes.
const createUIDatabasePropType = isRequired => (props, propName, componentName) => {
  const { [propName]: prop } = props;

  if (prop == null) {
    if (isRequired) {
      return new TypeError(`Missing database prop in ${componentName}`);
    }
    return null;
  }

  if (prop instanceof UIDatabase) return null;
  return new TypeError(`Invalid database prop in ${componentName}`);
};

export const UIDatabaseType = createUIDatabasePropType(false);
UIDatabaseType.isRequired = createUIDatabasePropType(true);

export default getUIDatabaseInstance;
<|endoftext|>


<commit_before>function initialize() {
  var encounterIds = {};
  var latlng = new google.maps.LatLng(35.643757,139.826647);
  if (localStorage) {
    var lat = parseFloat(localStorage.getItem('lat'));
    var lng = parseFloat(localStorage.getItem('lng'));
    if (lat && lng) {
      console.log('latlng');
      latlng = new google.maps.LatLng(lat,lng);
      console.log(latlng);
    }
  }
  var opts = {
    zoom: 18,
    center: latlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  var map = new google.maps.Map(document.getElementById("mypoke"), opts);
  map.addListener('center_changed', function() {
    //console.log(map.getCenter());
    if(localStorage) {
      var center = map.getCenter();
      localStorage.setItem('lat', center.lat().toString());
      localStorage.setItem('lng', center.lng().toString());
    }
  });
  var circle = new google.maps.Circle({
    strokeColor: '#FF0000',
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: '#FF0000',
    fillOpacity: 0.35,
    radius: 50
  });

  var socket = io.connect();
  $('#search').click(function() {
    if ($('#search').hasClass('blink')) {
      socket.emit('search', null);
    } else {
      var center = map.getCenter();
      socket.emit('search', { latitude: center.lat(), longitude: center.lng() });
    }
  });

  socket.on('searching', function(status) {
    if (status == 'stop') {
      $('#search').removeClass('blink');
      circle.setMap(null);
    } else {
      $('#search').addClass('blink');
      circle.setCenter({lat: status.latitude, lng: status.longitude});
      circle.setMap(map);
    }
  });

  $('#current').click(function() {
    if (navigator.geolocation) {
      $('#current').addClass('active');
      setTimeout(function() {$('#current').removeClass('active');}, 1000);
      navigator.geolocation.getCurrentPosition(
        function(position) {
          latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
          map.setCenter(latlng);
        }
      );
    }
  });

  setInterval(function() {
    $.each(encounterIds, function(eid, pokemon) {
      if (Date.now() > pokemon.raw.expiration_time) {
        console.log("pokemon was deleted by cleaner")
        pokemon.marker.setMap(null);
        delete encounterIds[eid];
      }
    });
  }, 5000);

  // fetch first pokemons
  socket.emit('search', 'cache');
  setInterval(function() {
    socket.emit('search', 'cache');
  }, 5000);

  socket.on('pokemons', function(pokes) {
    $.each(pokes, function(eid, rawPokemon) {
      var pokemon = pokemons[rawPokemon.pokemon_id.toString()];
      pokemon.raw = rawPokemon;
      console.log(eid);
      console.log(pokemon);
      if (!encounterIds[eid]) {
        var latlng = new google.maps.LatLng(rawPokemon.lat ,rawPokemon.lng);
        var image = {
          url : pokemon.img,
          scaledSize : new google.maps.Size(32, 32)
        }
        var mopts = {
          position: latlng,
          map: map,
          icon: image,
          title: pokemon.ja
        };
        var marker = new google.maps.Marker(mopts);
        pokemon.marker = marker;
        var vanishDate = new Date(rawPokemon.expiration_time);
        var content = "Name: " + pokemon.ja + "
" + "Vanished: " + vanishDate.toLocaleString();
        var infowindow = new google.maps.InfoWindow({
          content: content
        });
        marker.addListener('click', function() {
          var map = infowindow.getMap();
          if (map !== null && typeof map !== "undefined") {
            infowindow.close();
          } else {
            infowindow.open(map, marker);
          }
        });
        console.log(rawPokemon.expiration_time - Date.now())
        setTimeout(function() {
          marker.setMap(null);
        }, rawPokemon.expiration_time - Date.now());
        encounterIds[eid] = pokemon;
      }
    })
  });

}
<commit_msg>Save zoom size<commit_after>function initialize() {
  var encounterIds = {};
  var latlng = new google.maps.LatLng(35.643757,139.826647);
  var zoom = 18;
  if (localStorage) {
    var lat = parseFloat(localStorage.getItem('lat'));
    var lng = parseFloat(localStorage.getItem('lng'));
    var _zoom = parseInt(localStorage.getItem('zoom'));
    if (lat && lng) {
      console.log('latlng');
      latlng = new google.maps.LatLng(lat,lng);
      console.log(latlng);
    }
    if (_zoom) {
      zoom = _zoom;
    }
  }
  var opts = {
    zoom: zoom,
    center: latlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  var map = new google.maps.Map(document.getElementById("mypoke"), opts);
  map.addListener('center_changed', function() {
    //console.log(map.getCenter());
    if(localStorage) {
      var center = map.getCenter();
      localStorage.setItem('lat', center.lat().toString());
      localStorage.setItem('lng', center.lng().toString());
    }
  });
  map.addListener('zoom_changed', function() {
    if(localStorage) {
      localStorage.setItem('zoom', map.getZoom().toString());
    }
  });
  var circle = new google.maps.Circle({
    strokeColor: '#FF0000',
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: '#FF0000',
    fillOpacity: 0.35,
    radius: 50
  });

  var socket = io.connect();
  $('#search').click(function() {
    if ($('#search').hasClass('blink')) {
      socket.emit('search', null);
    } else {
      var center = map.getCenter();
      socket.emit('search', { latitude: center.lat(), longitude: center.lng() });
    }
  });

  socket.on('searching', function(status) {
    if (status == 'stop') {
      $('#search').removeClass('blink');
      circle.setMap(null);
    } else {
      $('#search').addClass('blink');
      circle.setCenter({lat: status.latitude, lng: status.longitude});
      circle.setMap(map);
    }
  });

  $('#current').click(function() {
    if (navigator.geolocation) {
      $('#current').addClass('active');
      setTimeout(function() {$('#current').removeClass('active');}, 1000);
      navigator.geolocation.getCurrentPosition(
        function(position) {
          latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
          map.setCenter(latlng);
        }
      );
    }
  });

  setInterval(function() {
    $.each(encounterIds, function(eid, pokemon) {
      if (Date.now() > pokemon.raw.expiration_time) {
        console.log("pokemon was deleted by cleaner")
        pokemon.marker.setMap(null);
        delete encounterIds[eid];
      }
    });
  }, 5000);

  // fetch first pokemons
  socket.emit('search', 'cache');
  setInterval(function() {
    socket.emit('search', 'cache');
  }, 5000);

  socket.on('pokemons', function(pokes) {
    $.each(pokes, function(eid, rawPokemon) {
      var pokemon = pokemons[rawPokemon.pokemon_id.toString()];
      pokemon.raw = rawPokemon;
      console.log(eid);
      console.log(pokemon);
      if (!encounterIds[eid]) {
        var latlng = new google.maps.LatLng(rawPokemon.lat ,rawPokemon.lng);
        var image = {
          url : pokemon.img,
          scaledSize : new google.maps.Size(32, 32)
        }
        var mopts = {
          position: latlng,
          map: map,
          icon: image,
          title: pokemon.ja
        };
        var marker = new google.maps.Marker(mopts);
        pokemon.marker = marker;
        var vanishDate = new Date(rawPokemon.expiration_time);
        var content = "Name: " + pokemon.ja + "
" + "Vanished: " + vanishDate.toLocaleString();
        var infowindow = new google.maps.InfoWindow({
          content: content
        });
        marker.addListener('click', function() {
          var map = infowindow.getMap();
          if (map !== null && typeof map !== "undefined") {
            infowindow.close();
          } else {
            infowindow.open(map, marker);
          }
        });
        console.log(rawPokemon.expiration_time - Date.now())
        setTimeout(function() {
          marker.setMap(null);
        }, rawPokemon.expiration_time - Date.now());
        encounterIds[eid] = pokemon;
      }
    })
  });

}
<|endoftext|>


<commit_before>odoo.define('website_sale_wishlist.wishlist', function (require) {
"use strict";

var sAnimations = require('website.content.snippets.animation');
var wSaleUtils = require('website_sale.utils');
var ProductConfiguratorMixin = require('sale.ProductConfiguratorMixin');

// ProductConfiguratorMixin events are overridden on purpose here
// to avoid registering them more than once since they are already registered
// in website_sale.js
sAnimations.registry.ProductWishlist = sAnimations.Class.extend(ProductConfiguratorMixin, {
    selector: '.oe_website_sale',
    read_events: {
        'click #my_wish': '_onClickMyWish',
        'click .o_add_wishlist, .o_add_wishlist_dyn': '_onClickAddWish',
        'change input.product_id': '_onChangeVariant',
        'change input.js_product_change': '_onChangeProduct',
        'click .wishlist-section .o_wish_rm': '_onClickWishRemove',
        'click .wishlist-section .o_wish_add': '_onClickWishAdd',
    },
    events: sAnimations.Class.events,

    start: function () {
        var self = this;
        var def = this._super.apply(this, arguments);
        if (this.editableMode) {
            return def;
        }

        this.wishlistProductIDs = [];

        var wishDef = $.get('/shop/wishlist', {
            count: 1,
        }).then(function (res) {
            self.wishlistProductIDs = JSON.parse(res);
            self._updateWishlistView();
            if ($('input.js_product_change').length) { // manage "List View of variants"
                $('input.js_product_change:checked').first().trigger('change');
            } else {
                $('input.js_variant_change').trigger('change');
            }
        });

        return $.when(def, wishDef);
    },

    //--------------------------------------------------------------------------
    // Private
    //--------------------------------------------------------------------------

    /**
     * @private
     */
    _addNewProducts: function ($el) {
        var self = this;
        var productID = $el.data('product-product-id');
        if ($el.hasClass('o_add_wishlist_dyn')) {
            productID = $el.parent().find('.product_id').val();
            if (!productID) { // case List View Variants
                productID = $el.parent().find('input:checked').first().val();
            }
            productID = parseInt(productID, 10);
        }

        var productReady = this.selectOrCreateProduct(
            $el.closest('form'),
            productID,
            $el.closest('form').find('.product_template_id').val(),
            false
        );

        productReady.done(function (productId) {
            productId = parseInt(productId, 10);

            if (productId && !_.contains(self.wishlistProductIDs, productId)) {
                return self._rpc({
                    route: '/shop/wishlist/add',
                    params: {
                        product_id: productId,
                    },
                }).then(function () {
                    self.wishlistProductIDs.push(productId);
                    self._updateWishlistView();
                    wSaleUtils.animateClone($('#my_wish'), $el.closest('form'), 25, 40);
                    $el.prop("disabled", true).addClass('disabled');
                });
            }
        });
    },
    /**
     * @private
     */
    _updateWishlistView: function () {
        if (this.wishlistProductIDs.length > 0) {
            $('#my_wish').show();
            $('.my_wish_quantity').text(this.wishlistProductIDs.length);
        } else {
            $('#my_wish').hide();
        }
    },
    /**
     * @private
     */
    _removeWish: function (e, deferred_redirect){
        var tr = $(e.currentTarget).parents('tr');
        var wish = tr.data('wish-id');
        var product = tr.data('product-id');
        var self = this;

        this._rpc({
            route: '/shop/wishlist/remove/' + wish,
        }).done(function () {
            $(tr).hide();
        });

        this.wishlistProductIDs = _.without(this.wishlistProductIDs, product);
        if (this.wishlistProductIDs.length === 0) {
            deferred_redirect = deferred_redirect ? deferred_redirect : $.Deferred();
            deferred_redirect.then(function () {
                self._redirectNoWish();
            });
        }
        this._updateWishlistView();
    },
    /**
     * @private
     */
    _addOrMoveWish: function (e) {
        var tr = $(e.currentTarget).parents('tr');
        var product = tr.data('product-id');
        $('#my_cart').removeClass('d-none');
        wSaleUtils.animateClone($('#my_cart'), tr, 25, 40);

        if ($('#b2b_wish').is(':checked')) {
            return this._addToCart(product, tr.find('qty').val() || 1);
        } else {
            var adding_deffered = this._addToCart(product, tr.find('qty').val() || 1);
            this._removeWish(e, adding_deffered);
            return adding_deffered;
        }
    },
    /**
     * @private
     */
    _addToCart: function (productID, qty_id) {
        return this._rpc({
            route: "/shop/cart/update_json",
            params: {
                product_id: parseInt(productID, 10),
                add_qty: parseInt(qty_id, 10),
                display: false,
            },
        }).then(function (resp) {
            if (resp.warning) {
                if (! $('#data_warning').length) {
                    $('.wishlist-section').prepend('

');
                }
                var cart_alert = $('.wishlist-section').parent().find('#data_warning');
                cart_alert.html('<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + resp.warning);
            }
            $('.my_cart_quantity').html(resp.cart_quantity || ' ');
        });
    },
    /**
     * @private
     */
    _redirectNoWish: function () {
        window.location.href = '/shop/cart';
    },

    //--------------------------------------------------------------------------
    // Handlers
    //--------------------------------------------------------------------------

    /**
     * @private
     */
    _onClickMyWish: function () {
        if (this.wishlistProductIDs.length === 0) {
            this._updateWishlistView();
            this._redirectNoWish();
            return;
        }
        window.location = '/shop/wishlist';
    },
    /**
     * @private
     * @param {Event} ev
     */
    _onClickAddWish: function (ev) {
        this._addNewProducts($(ev.currentTarget));
    },
    /**
     * @private
     * @param {Event} ev
     */
    _onChangeVariant: function (ev) {
        var $input = $(ev.target);
        var $parent = $input.closest('.js_product');
        var $el = $parent.find("[data-action='o_wishlist']");
        if (!_.contains(this.wishlistProductIDs, parseInt($input.val(), 10))) {
            $el.prop("disabled", false).removeClass('disabled').removeAttr('disabled');
        } else {
            $el.prop("disabled", true).addClass('disabled').attr('disabled', 'disabled');
        }
        $el.data('product-product-id', parseInt($input.val(), 10));
    },
    /**
     * @private
     * @param {Event} ev
     */
    _onChangeProduct: function (ev) {
        var productID = ev.currentTarget.value;
        var $el = $(ev.target).closest('.js_add_cart_variants').find("[data-action='o_wishlist']");

        if (!_.contains(this.wishlistProductIDs, parseInt(productID, 10))) {
            $el.prop("disabled", false).removeClass('disabled').removeAttr('disabled');
        } else {
            $el.prop("disabled", true).addClass('disabled').attr('disabled', 'disabled');
        }
        $el.data('product-product-id', productID);
    },
    /**
     * @private
     * @param {Event} ev
     */
    _onClickWishRemove: function (ev) {
        this._removeWish(ev, false);
    },
    /**
     * @private
     * @param {Event} ev
     */
    _onClickWishAdd: function (ev) {
        var self = this;
        this.$('.wishlist-section .o_wish_add').addClass('disabled');
        this._addOrMoveWish(ev).then(function () {
            self.$('.wishlist-section .o_wish_add').removeClass('disabled');
        });
    },
});
});
<commit_msg>[FIX] website_sale_wishlist: prevent product to be added more than once<commit_after>odoo.define('website_sale_wishlist.wishlist', function (require) {
"use strict";

var sAnimations = require('website.content.snippets.animation');
var wSaleUtils = require('website_sale.utils');
var ProductConfiguratorMixin = require('sale.ProductConfiguratorMixin');

// ProductConfiguratorMixin events are overridden on purpose here
// to avoid registering them more than once since they are already registered
// in website_sale.js
sAnimations.registry.ProductWishlist = sAnimations.Class.extend(ProductConfiguratorMixin, {
    selector: '.oe_website_sale',
    read_events: {
        'click #my_wish': '_onClickMyWish',
        'click .o_add_wishlist, .o_add_wishlist_dyn': '_onClickAddWish',
        'change input.product_id': '_onChangeVariant',
        'change input.js_product_change': '_onChangeProduct',
        'click .wishlist-section .o_wish_rm': '_onClickWishRemove',
        'click .wishlist-section .o_wish_add': '_onClickWishAdd',
    },
    events: sAnimations.Class.events,

    start: function () {
        var self = this;
        var def = this._super.apply(this, arguments);
        if (this.editableMode) {
            return def;
        }

        this.wishlistProductIDs = [];

        var wishDef = $.get('/shop/wishlist', {
            count: 1,
        }).then(function (res) {
            self.wishlistProductIDs = JSON.parse(res);
            self._updateWishlistView();
            if ($('input.js_product_change').length) { // manage "List View of variants"
                $('input.js_product_change:checked').first().trigger('change');
            } else {
                $('input.js_variant_change').trigger('change');
            }
        });

        return $.when(def, wishDef);
    },

    //--------------------------------------------------------------------------
    // Private
    //--------------------------------------------------------------------------

    /**
     * @private
     */
    _addNewProducts: function ($el) {
        var self = this;
        var productID = $el.data('product-product-id');
        if ($el.hasClass('o_add_wishlist_dyn')) {
            productID = $el.parent().find('.product_id').val();
            if (!productID) { // case List View Variants
                productID = $el.parent().find('input:checked').first().val();
            }
            productID = parseInt(productID, 10);
        }

        $el.prop("disabled", true).addClass('disabled');
        var productReady = this.selectOrCreateProduct(
            $el.closest('form'),
            productID,
            $el.closest('form').find('.product_template_id').val(),
            false
        );

        productReady.done(function (productId) {
            productId = parseInt(productId, 10);

            if (productId && !_.contains(self.wishlistProductIDs, productId)) {
                return self._rpc({
                    route: '/shop/wishlist/add',
                    params: {
                        product_id: productId,
                    },
                }).then(function () {
                    self.wishlistProductIDs.push(productId);
                    self._updateWishlistView();
                    wSaleUtils.animateClone($('#my_wish'), $el.closest('form'), 25, 40);
                }).fail(function () {
                    $el.prop("disabled", false).removeClass('disabled');
                });
            }
        }).fail(function () {
            $el.prop("disabled", false).removeClass('disabled');
        });
    },
    /**
     * @private
     */
    _updateWishlistView: function () {
        if (this.wishlistProductIDs.length > 0) {
            $('#my_wish').show();
            $('.my_wish_quantity').text(this.wishlistProductIDs.length);
        } else {
            $('#my_wish').hide();
        }
    },
    /**
     * @private
     */
    _removeWish: function (e, deferred_redirect){
        var tr = $(e.currentTarget).parents('tr');
        var wish = tr.data('wish-id');
        var product = tr.data('product-id');
        var self = this;

        this._rpc({
            route: '/shop/wishlist/remove/' + wish,
        }).done(function () {
            $(tr).hide();
        });

        this.wishlistProductIDs = _.without(this.wishlistProductIDs, product);
        if (this.wishlistProductIDs.length === 0) {
            deferred_redirect = deferred_redirect ? deferred_redirect : $.Deferred();
            deferred_redirect.then(function () {
                self._redirectNoWish();
            });
        }
        this._updateWishlistView();
    },
    /**
     * @private
     */
    _addOrMoveWish: function (e) {
        var tr = $(e.currentTarget).parents('tr');
        var product = tr.data('product-id');
        $('#my_cart').removeClass('d-none');
        wSaleUtils.animateClone($('#my_cart'), tr, 25, 40);

        if ($('#b2b_wish').is(':checked')) {
            return this._addToCart(product, tr.find('qty').val() || 1);
        } else {
            var adding_deffered = this._addToCart(product, tr.find('qty').val() || 1);
            this._removeWish(e, adding_deffered);
            return adding_deffered;
        }
    },
    /**
     * @private
     */
    _addToCart: function (productID, qty_id) {
        return this._rpc({
            route: "/shop/cart/update_json",
            params: {
                product_id: parseInt(productID, 10),
                add_qty: parseInt(qty_id, 10),
                display: false,
            },
        }).then(function (resp) {
            if (resp.warning) {
                if (! $('#data_warning').length) {
                    $('.wishlist-section').prepend('

');
                }
                var cart_alert = $('.wishlist-section').parent().find('#data_warning');
                cart_alert.html('<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + resp.warning);
            }
            $('.my_cart_quantity').html(resp.cart_quantity || ' ');
        });
    },
    /**
     * @private
     */
    _redirectNoWish: function () {
        window.location.href = '/shop/cart';
    },

    //--------------------------------------------------------------------------
    // Handlers
    //--------------------------------------------------------------------------

    /**
     * @private
     */
    _onClickMyWish: function () {
        if (this.wishlistProductIDs.length === 0) {
            this._updateWishlistView();
            this._redirectNoWish();
            return;
        }
        window.location = '/shop/wishlist';
    },
    /**
     * @private
     * @param {Event} ev
     */
    _onClickAddWish: function (ev) {
        this._addNewProducts($(ev.currentTarget));
    },
    /**
     * @private
     * @param {Event} ev
     */
    _onChangeVariant: function (ev) {
        var $input = $(ev.target);
        var $parent = $input.closest('.js_product');
        var $el = $parent.find("[data-action='o_wishlist']");
        if (!_.contains(this.wishlistProductIDs, parseInt($input.val(), 10))) {
            $el.prop("disabled", false).removeClass('disabled').removeAttr('disabled');
        } else {
            $el.prop("disabled", true).addClass('disabled').attr('disabled', 'disabled');
        }
        $el.data('product-product-id', parseInt($input.val(), 10));
    },
    /**
     * @private
     * @param {Event} ev
     */
    _onChangeProduct: function (ev) {
        var productID = ev.currentTarget.value;
        var $el = $(ev.target).closest('.js_add_cart_variants').find("[data-action='o_wishlist']");

        if (!_.contains(this.wishlistProductIDs, parseInt(productID, 10))) {
            $el.prop("disabled", false).removeClass('disabled').removeAttr('disabled');
        } else {
            $el.prop("disabled", true).addClass('disabled').attr('disabled', 'disabled');
        }
        $el.data('product-product-id', productID);
    },
    /**
     * @private
     * @param {Event} ev
     */
    _onClickWishRemove: function (ev) {
        this._removeWish(ev, false);
    },
    /**
     * @private
     * @param {Event} ev
     */
    _onClickWishAdd: function (ev) {
        var self = this;
        this.$('.wishlist-section .o_wish_add').addClass('disabled');
        this._addOrMoveWish(ev).then(function () {
            self.$('.wishlist-section .o_wish_add').removeClass('disabled');
        });
    },
});
});
<|endoftext|>


<commit_before>import React from "react";
import { Observable } from "rxjs/Observable";
import { BehaviorSubject } from "rxjs/BehaviorSubject";
import "rxjs/add/operator/switchMap";

// Recompose helps handle data down and event up as streams
import { componentFromStream } from "#PACKAGES/data-service/recomposeRx";

// Our in-house solution to resolve graphql queries using streams
import { graphqlObservable } from "#PACKAGES/data-service/graphqlObservable";

// tools to make easier to create schemas and queries
import { makeExecutableSchema } from "graphql-tools";
import gql from "graphql-tag";

// Streams we get our data from
import { liveFetchRepositories } from "#PLUGINS/catalog/src/js/repositories/repositoriesStream";
import RepositoryList from "#SRC/js/structs/RepositoryList";

// The graphql schema and resolvers for those streams;
import { typeDefs, resolvers } from "./repositoriesModel";

// UI components
import RepositoriesTabUI from "./RepositoriesTabUI";

// Using the data layer

// 1. We first make an schema out of the resolvers and typeDefinitions
const schema = makeExecutableSchema({
  typeDefs,
  resolvers
});

// 2. We declare which data our component needs in graphql (data down)
const packageRepositoryQuery = filter => gql`
  query {
    packageRepository(filter: "${filter}") {
      name
      uri
    }
  }
`;

// 3. We create an event handler as a stream to deal with search (events up)
const searchTerm$ = new BehaviorSubject("");

// 4. We compose the result with the query, and massage it down the pipe until
// we get the props for our component.
// The idea is from an Observable of data and events, compose a stream o React.Components

const packageRepository$ = liveFetchRepositories();

const components$ = searchTerm$
  .switchMap(searchTerm => {
    const query = packageRepositoryQuery(searchTerm);
    const liveQuery = graphqlObservable(query, schema, {
      query: packageRepository$
    }).map(result => {
      // Backwards compatible with the previous struct/RepositoryList for packages
      return new RepositoryList({
        items: result.packageRepository
      });
    });

    return liveQuery.map(packageRepository => {
      return { packageRepository, searchTerm };
    });
  })
  // We map over the data and return a component to render
  .map(data => {

    return (
      <RepositoriesTabUI
        repositories={data.packageRepository}
        searchTerm={data.searchTerm}
        // onSearch has arity 2 which prevents to pass `next` as reference
        onSearch={(value) => {
          searchTerm$.next(value);
        }}
      />
    );
  })
  // The first component is the loading
  .startWith(<RepositoriesTabUI.Loading />)
  // If anything goes wrong, we render an error component
  .catch(err => {
    console.error(err);

    return Observable.of(<RepositoriesTabUI.Error err={err} />);
  });

// componentFromStream create a single component who render the latest emitted
// component from the stream
const RepositoriesTab = componentFromStream(() => components$);

// the reason we don`t `export componentFromStream()` is so you can add those
// router specific things
RepositoriesTab.routeConfig = {
  label: "Package Repositories",
  matches: /^\/settings\/repositories/
};

module.exports = RepositoriesTab;
<commit_msg>fix: reorganize dependencies to work with package structure<commit_after>import React from "react";
import { Observable } from "rxjs/Observable";
import { BehaviorSubject } from "rxjs/BehaviorSubject";
import "rxjs/add/operator/switchMap";

// graphqlObservable is our in house implementation of the graphql (not spec compliant yet)
// componentFromStream transforms a stream of data into a React Component
import { componentFromStream, graphqlObservable } from "data-service";

// tools to make easier to create schemas and queries
import { makeExecutableSchema } from "graphql-tools";
import gql from "graphql-tag";

// Streams we get our data from
import {
  liveFetchRepositories
} from "#PLUGINS/catalog/src/js/repositories/repositoriesStream";
import RepositoryList from "#SRC/js/structs/RepositoryList";

// The graphql schema and resolvers for those streams;
import { typeDefs, resolvers } from "./repositoriesModel";

// UI components
import RepositoriesTabUI from "./RepositoriesTabUI";

// Using the data layer

// 1. We first make an schema out of the resolvers and typeDefinitions
const schema = makeExecutableSchema({
  typeDefs,
  resolvers
});

// 2. We declare which data our component needs in graphql (data down)
const packageRepositoryQuery = filter => gql`
  query {
    packageRepository(filter: "${filter}") {
      name
      uri
    }
  }
`;

// 3. We create an event handler as a stream to deal with search (events up)
const searchTerm$ = new BehaviorSubject("");

// 4. We compose the result with the query, and massage it down the pipe until
// we get the props for our component.
// The idea is from an Observable of data and events, compose a stream o React.Components

const packageRepository$ = liveFetchRepositories();

const components$ = searchTerm$
  .switchMap(searchTerm => {
    const query = packageRepositoryQuery(searchTerm);
    const liveQuery = graphqlObservable(query, schema, {
      query: packageRepository$
    }).map(result => {
      // Backwards compatible with the previous struct/RepositoryList for packages
      return new RepositoryList({
        items: result.packageRepository
      });
    });

    return liveQuery.map(packageRepository => {
      return { packageRepository, searchTerm };
    });
  })
  // We map over the data and return a component to render
  .map(data => {
    return (
      <RepositoriesTabUI
        repositories={data.packageRepository}
        searchTerm={data.searchTerm}
        // onSearch has arity 2 which prevents to pass `next` as reference
        onSearch={value => {
          searchTerm$.next(value);
        }}
      />
    );
  })
  // The first component is the loading
  .startWith(<RepositoriesTabUI.Loading />)
  // If anything goes wrong, we render an error component
  .catch(err => {
    console.error(err);

    return Observable.of(<RepositoriesTabUI.Error err={err} />);
  });

// componentFromStream create a single component who render the latest emitted
// component from the stream
const RepositoriesTab = componentFromStream(() => components$);

// the reason we don`t `export componentFromStream()` is so you can add those
// router specific things
RepositoriesTab.routeConfig = {
  label: "Package Repositories",
  matches: /^\/settings\/repositories/
};

module.exports = RepositoriesTab;
<|endoftext|>


<commit_before>new Test.Unit.Runner({

  'testIsRunningFromRake':  function() {
    if (Fuse.String.startsWith(window.location.href, 'http')) {
      this.assert(this.isRunningFromRake);
      this.info('These tests are running from rake.')
    }
    else {
      this.assert(!this.isRunningFromRake);
      this.info('These tests are *not* running from rake.')
    }
  },

  'testBuildMessage':  function() {
    this.assertEqual("'foo' 'bar'", this.buildMessage('', '? ?', 'foo', 'bar'))
  },

  'testAssertEqual': function() {
    this.assertEqual(0, 0);
    this.assertEqual(0, 0, 'test');

    this.assertEqual(0,'0');
    this.assertEqual(65.0, 65);

    this.assertEqual('a', 'a');
    this.assertEqual('a', 'a', 'test');

    this.assertNotEqual(0, 1);
    this.assertNotEqual('a', 'b');
    this.assertNotEqual({ }, { });
    this.assertNotEqual([],  []);
    this.assertNotEqual([],  { });
  },

  'testAssertEnumEqual': function() {
    this.assertEnumEqual([], []);
    this.assertEnumEqual(['a', 'b'], ['a', 'b']);
    this.assertEnumEqual(['1', '2'], [1, 2]);
    this.assertEnumNotEqual(['1', '2'], [1, 2, 3]);
  },

  'testAssertHashEqual': function() {
    this.assertHashEqual({}, {});
    this.assertHashEqual({ 'a': 'b'}, {'a': 'b' });
    this.assertHashEqual({ 'a': 'b', 'c': 'd' }, { 'c': 'd', 'a': 'b' });
    this.assertHashNotEqual({ 'a': 'b', 'c': 'd' }, { 'c': 'd', 'a': 'boo!' });
  },

  'testAssertRespondsTo': function() {
    this.assertRespondsTo('isNice',   testObj);
    this.assertRespondsTo('isBroken', testObj);
  },

  'testAssertIdentical': function() {
    this.assertIdentical(0, 0);
    this.assertIdentical(0, 0, 'test');
    this.assertIdentical(1, 1);
    this.assertIdentical('a', 'a');
    this.assertIdentical('a', 'a', 'test');
    this.assertIdentical('', '');
    this.assertIdentical(undef, undef);
    this.assertIdentical(null, null);
    this.assertIdentical(true, true);
    this.assertIdentical(false, false);

    var obj = { 'a': 'b' };
    this.assertIdentical(obj, obj);

    this.assertNotIdentical({ '1': 2, '3': 4 }, { '1': 2, '3': 4 });

    this.assertIdentical(1, 1.0); // both are typeof == 'number'

    this.assertNotIdentical(1, '1');
    this.assertNotIdentical(1, '1.0');
  },

  'testAssertNullAndAssertUndefined': function() {
    this.assertNull(null);

    this.assertNotNull(undef);
    this.assertNotNull(0);
    this.assertNotNull('');

    this.assertNotUndefined(null);
    this.assertNotUndefined(0);
    this.assertNotUndefined('');

    this.assertNullOrUndefined(null);
    this.assertNullOrUndefined(undef);

    this.assertNotNullOrUndefined(0);
    this.assertNotNullOrUndefined('');

    this.assertUndefined(undef);
  },

  'testAssertMatch': function() {
    this.assertMatch(/knowmad.jpg$/, 'http://script.aculo.us/images/knowmad.jpg');
    this.assertMatch(/Fuc/, 'Thomas Fuchs');

    this.assertMatch(/^\$(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$/,
      '$19.95');

    this.assertMatch(/(\d{3}\) ?)|(\d{3}[- \.])?\d{3}[- \.]\d{4}(\s(x\d+)?){0,1}$/,
      '704-343-9330');

    this.assertMatch(/^(?:(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(\/|-|\.)(?:0?2\1(?:29)))|(?:(?:(?:1[6-9]|[2-9]\d)?\d{2})(\/|-|\.)(?:(?:(?:0?[13578]|1[02])\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\2(?:0?[1-9]|1\d|2[0-8]))))$/,
      '2001-06-16');

    this.assertMatch(/^((0?[123456789])|(1[012]))\s*:\s*([012345]\d)(\s*:\s*([012345]\d))?\s*[ap]m\s*-\s*((0?[123456789])|(1[012]))\s*:\s*([012345]\d)(\s*:\s*([012345]\d))?\s*[ap]m$/i,
      '2:00PM-2:15PM');

    this.assertNoMatch(/zubar/, 'foo bar');
  },

  'testAssertInstanceOf': function() {
    this.assertInstanceOf(String, new String);
    this.assertInstanceOf(RegExp, /foo/);
    this.assertNotInstanceOf(String, { });
  },

  'testAssertVisible': function() {
    this.assertVisible('testcss1');
    this.assertNotVisible('testcss1_span');
    //this.assertNotVisible('testcss2', 'Due to a Safari bug, this test fails in Safari.');

    $('testcss1').hide();
    this.assertNotVisible('testcss1');
    this.assertNotVisible('testcss1_span');

    $('testcss1').show();
    console.log($('testcss1').isVisible())
    this.assertVisible('testcss1');
    this.assertNotVisible('testcss1_span');

    $('testcss1_span').show();
    this.assertVisible('testcss1_span');

    $('testcss1').hide();
    this.assertNotVisible('testcss1_span'); // hidden by parent
  },

  'testAssertElementsMatch': function() {
    this.assertElementsMatch($$('#tlist'), '#tlist');
    this.assertElementMatches($('tlist'),  '#tlist');
  }
});

/*--------------------------------------------------------------------------*/

new Test.Unit.Runner({
  'testDummy': function() {
    this.assert(true);
  },

  'testMultipleTestRunner': function() {
    this.assertEqual('passed', $('testlog_2').down('td', 1).raw.innerHTML);
  }
}, { 'testLog': 'testlog_2' });<commit_msg>unittest: Remove console.log() call from unittest_test.js. [jddalton]<commit_after>new Test.Unit.Runner({

  'testIsRunningFromRake':  function() {
    if (Fuse.String.startsWith(window.location.href, 'http')) {
      this.assert(this.isRunningFromRake);
      this.info('These tests are running from rake.')
    }
    else {
      this.assert(!this.isRunningFromRake);
      this.info('These tests are *not* running from rake.')
    }
  },

  'testBuildMessage':  function() {
    this.assertEqual("'foo' 'bar'", this.buildMessage('', '? ?', 'foo', 'bar'))
  },

  'testAssertEqual': function() {
    this.assertEqual(0, 0);
    this.assertEqual(0, 0, 'test');

    this.assertEqual(0,'0');
    this.assertEqual(65.0, 65);

    this.assertEqual('a', 'a');
    this.assertEqual('a', 'a', 'test');

    this.assertNotEqual(0, 1);
    this.assertNotEqual('a', 'b');
    this.assertNotEqual({ }, { });
    this.assertNotEqual([],  []);
    this.assertNotEqual([],  { });
  },

  'testAssertEnumEqual': function() {
    this.assertEnumEqual([], []);
    this.assertEnumEqual(['a', 'b'], ['a', 'b']);
    this.assertEnumEqual(['1', '2'], [1, 2]);
    this.assertEnumNotEqual(['1', '2'], [1, 2, 3]);
  },

  'testAssertHashEqual': function() {
    this.assertHashEqual({}, {});
    this.assertHashEqual({ 'a': 'b'}, {'a': 'b' });
    this.assertHashEqual({ 'a': 'b', 'c': 'd' }, { 'c': 'd', 'a': 'b' });
    this.assertHashNotEqual({ 'a': 'b', 'c': 'd' }, { 'c': 'd', 'a': 'boo!' });
  },

  'testAssertRespondsTo': function() {
    this.assertRespondsTo('isNice',   testObj);
    this.assertRespondsTo('isBroken', testObj);
  },

  'testAssertIdentical': function() {
    this.assertIdentical(0, 0);
    this.assertIdentical(0, 0, 'test');
    this.assertIdentical(1, 1);
    this.assertIdentical('a', 'a');
    this.assertIdentical('a', 'a', 'test');
    this.assertIdentical('', '');
    this.assertIdentical(undef, undef);
    this.assertIdentical(null, null);
    this.assertIdentical(true, true);
    this.assertIdentical(false, false);

    var obj = { 'a': 'b' };
    this.assertIdentical(obj, obj);

    this.assertNotIdentical({ '1': 2, '3': 4 }, { '1': 2, '3': 4 });

    this.assertIdentical(1, 1.0); // both are typeof == 'number'

    this.assertNotIdentical(1, '1');
    this.assertNotIdentical(1, '1.0');
  },

  'testAssertNullAndAssertUndefined': function() {
    this.assertNull(null);

    this.assertNotNull(undef);
    this.assertNotNull(0);
    this.assertNotNull('');

    this.assertNotUndefined(null);
    this.assertNotUndefined(0);
    this.assertNotUndefined('');

    this.assertNullOrUndefined(null);
    this.assertNullOrUndefined(undef);

    this.assertNotNullOrUndefined(0);
    this.assertNotNullOrUndefined('');

    this.assertUndefined(undef);
  },

  'testAssertMatch': function() {
    this.assertMatch(/knowmad.jpg$/, 'http://script.aculo.us/images/knowmad.jpg');
    this.assertMatch(/Fuc/, 'Thomas Fuchs');

    this.assertMatch(/^\$(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$/,
      '$19.95');

    this.assertMatch(/(\d{3}\) ?)|(\d{3}[- \.])?\d{3}[- \.]\d{4}(\s(x\d+)?){0,1}$/,
      '704-343-9330');

    this.assertMatch(/^(?:(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(\/|-|\.)(?:0?2\1(?:29)))|(?:(?:(?:1[6-9]|[2-9]\d)?\d{2})(\/|-|\.)(?:(?:(?:0?[13578]|1[02])\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\2(?:0?[1-9]|1\d|2[0-8]))))$/,
      '2001-06-16');

    this.assertMatch(/^((0?[123456789])|(1[012]))\s*:\s*([012345]\d)(\s*:\s*([012345]\d))?\s*[ap]m\s*-\s*((0?[123456789])|(1[012]))\s*:\s*([012345]\d)(\s*:\s*([012345]\d))?\s*[ap]m$/i,
      '2:00PM-2:15PM');

    this.assertNoMatch(/zubar/, 'foo bar');
  },

  'testAssertInstanceOf': function() {
    this.assertInstanceOf(String, new String);
    this.assertInstanceOf(RegExp, /foo/);
    this.assertNotInstanceOf(String, { });
  },

  'testAssertVisible': function() {
    this.assertVisible('testcss1');
    this.assertNotVisible('testcss1_span');
    //this.assertNotVisible('testcss2', 'Due to a Safari bug, this test fails in Safari.');

    $('testcss1').hide();
    this.assertNotVisible('testcss1');
    this.assertNotVisible('testcss1_span');

    $('testcss1').show();
    this.assertVisible('testcss1');
    this.assertNotVisible('testcss1_span');

    $('testcss1_span').show();
    this.assertVisible('testcss1_span');

    $('testcss1').hide();
    this.assertNotVisible('testcss1_span'); // hidden by parent
  },

  'testAssertElementsMatch': function() {
    this.assertElementsMatch($$('#tlist'), '#tlist');
    this.assertElementMatches($('tlist'),  '#tlist');
  }
});

/*--------------------------------------------------------------------------*/

new Test.Unit.Runner({
  'testDummy': function() {
    this.assert(true);
  },

  'testMultipleTestRunner': function() {
    this.assertEqual('passed', $('testlog_2').down('td', 1).raw.innerHTML);
  }
}, { 'testLog': 'testlog_2' });<|endoftext|>