<commit_before>'use strict';

require('../test_helper');

var request = require('request');

describe('ApiUmbrellaGatekeper', function() {
  describe('api matching', function() {
    describe('host matching', function() {
      shared.runServer({
        gatekeeper: {
          default_frontend_host: 'default-host-config.example.com',
        },
        apis: [
          {
            'frontend_host': 'localhost:7777',
            'backend_host': 'example.com',
            '_id': 'localhost-non-matching-port',
            'url_matches': [
              {
                'frontend_prefix': '/info/matching/',
                'backend_prefix': '/info/matching/'
              }
            ]
          },
          {
            'frontend_host': 'localhost:9333',
            'backend_host': 'example.com',
            '_id': 'localhost-with-port',
            'url_matches': [
              {
                'frontend_prefix': '/info/matching/',
                'backend_prefix': '/info/matching/'
              }
            ]
          },
          {
            'frontend_host': 'localhost:80',
            'backend_host': 'example.com',
            '_id': 'localhost-default-port',
            'url_matches': [
              {
                'frontend_prefix': '/info/matching/',
                'backend_prefix': '/info/matching/'
              }
            ]
          },
          {
            'frontend_host': 'localhost:443',
            'backend_host': 'example.com',
            '_id': 'localhost-ssl-port',
            'url_matches': [
              {
                'frontend_prefix': '/info/matching/',
                'backend_prefix': '/info/matching/'
              }
            ]
          },
          {
            'frontend_host': 'fallback.example.com',
            'backend_host': 'example.com',
            '_id': 'fallback-no-port',
            'url_matches': [
              {
                'frontend_prefix': '/info/matching/',
                'backend_prefix': '/info/matching/'
              }
            ]
          },
          {
            'frontend_host': 'fallback.example.com:80',
            'backend_host': 'example.com',
            '_id': 'fallback-no-port',
            'url_matches': [
              {
                'frontend_prefix': '/info/matching/',
                'backend_prefix': '/info/matching/'
              }
            ]
          },
          {
            'frontend_host': '*',
            'backend_host': 'example.com',
            '_id': 'wildcard',
            'url_matches': [
              {
                'frontend_prefix': '/info/wildcard/',
                'backend_prefix': '/info/wildcard/'
              }
            ]
          },
          {
            'frontend_host': 'wildcard-coexist.example.com',
            'backend_host': 'example.com',
            '_id': 'host-over-wildcard',
            'url_matches': [
              {
                'frontend_prefix': '/info/wildcard-coexist/',
                'backend_prefix': '/info/wildcard-coexist/'
              }
            ]
          },
          {
            'frontend_host': 'default-host-config.example.com',
            'backend_host': 'example.com',
            '_id': 'default-host-config',
            'url_matches': [
              {
                'frontend_prefix': '/info/default-host-config/',
                'backend_prefix': '/info/default-host-config/'
              }
            ]
          },

        ],
      });

      it('uses full host with port to find the matching api', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey);
        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('localhost-with-port');
          done();
        });
      });

      it('prefers the host header', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey, {
          headers: {
            'Host': 'localhost:80',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('localhost-default-port');
          done();
        });
      });

      it('fills in host headers with missing ports with defaults', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey, {
          headers: {
            'Host': 'localhost',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('localhost-default-port');
          done();
        });
      });

      it('determines the default ports based on the protocol', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey, {
          headers: {
            'Host': 'localhost',
            'X-Forwarded-Proto': 'https',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('localhost-ssl-port');
          done();
        });
      });

      it('falls back to the hostname when using a standard port', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey, {
          headers: {
            'Host': 'fallback.example.com:80',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('fallback-no-port');
          done();
        });
      });

      it('falls back to the hostname when using a non-standard port', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey, {
          headers: {
            'Host': 'fallback.example.com:123',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('fallback-no-port');
          done();
        });
      });

      it('falls back to wildcard hostnames if no other hostname matches', function(done) {
        var opts = shared.buildRequestOptions('/info/wildcard/', this.apiKey, {
          headers: {
            'Host': 'google.com:789',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('wildcard');
          done();
        });
      });

      it('can still fallback to wildcard apis even if a matching host is present for other apis', function(done) {
        var opts = shared.buildRequestOptions('/info/wildcard/', this.apiKey, {
          headers: {
            'Host': 'wildcard-coexist.example.com',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('wildcard');
          done();
        });
      });

      it('allows a configurable default host to fallback to', function(done) {
        var opts = shared.buildRequestOptions('/info/default-host-config/', this.apiKey, {
          headers: {
            'Host': 'google.com:890',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('default-host-config');
          done();
        });
      });

      describe('non-matching host', function() {
        shared.itBehavesLikeGatekeeperBlocked('/info/matching/', 404, 'NOT_FOUND', {
          headers: {
            'Host': 'unmatched.example.com',
          },
        });
      });
    });

    describe('prefix matching', function() {
      shared.runServer({
        apis: [
          {
            'frontend_host': 'localhost',
            'backend_host': 'example.com',
            '_id': 'other-prefix',
            'url_matches': [
              {
                'frontend_prefix': '/info/other/',
                'backend_prefix': '/info/other/'
              }
            ],
          },
          {
            'frontend_host': 'unused.example.com',
            'backend_host': 'example.com',
            '_id': 'specific-prefix-different-host',
            'url_matches': [
              {
                'frontend_prefix': '/info/specific/',
                'backend_prefix': '/info/specific/'
              }
            ],
          },
          {
            'frontend_host': 'localhost',
            'backend_host': 'example.com',
            '_id': 'specific-prefix',
            'url_matches': [
              {
                'frontend_prefix': '/info/specific/',
                'backend_prefix': '/info/specific/'
              }
            ],
          },
        ],
      });

      it('matches based on host and prefix combination', function(done) {
        var opts = shared.buildRequestOptions('/info/specific/', this.apiKey);
        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('specific-prefix');
          done();
        });
      });

      it('ignores everything past the matching prefix', function(done) {
        var opts = shared.buildRequestOptions('/info/specific/abc/xyz', this.apiKey);
        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('specific-prefix');
          done();
        });
      });

      describe('non-matching prefixes', function() {
        describe('mismatched trailing slash', function() {
          shared.itBehavesLikeGatekeeperBlocked('/info/specific', 404, 'NOT_FOUND');
        });

        describe('mismatched case sensitivity', function() {
          shared.itBehavesLikeGatekeeperBlocked('/info/SPECIFIC/', 404, 'NOT_FOUND');
        });
      });
    });

    describe('request rewriting', function() {
      shared.runServer({
        apis: [
          {
            'frontend_host': 'localhost',
            'backend_host': 'example.com',
            '_id': 'rewrites',
            'url_matches': [
              {
                'frontend_prefix': '/info/incoming/',
                'backend_prefix': '/info/outgoing/'
              }
            ],
          },
        ],
      });

      it('rewrites the prefix', function(done) {
        var opts = shared.buildRequestOptions('/info/incoming/example', this.apiKey);
        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.url.path.should.eql('/info/outgoing/example');
          done();
        });
      });

      it('maintains query string parameters when rewriting the prefix', function(done) {
        var opts = shared.buildRequestOptions('/info/incoming/example?param1=value1&param2=value2', this.apiKey);
        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.url.path.should.eql('/info/outgoing/example?param1=value1&param2=value2');
          done();
        });
      });
    });
  });
});
<commit_msg>Fix duplicate API backend present in test.<commit_after>'use strict';

require('../test_helper');

var request = require('request');

describe('ApiUmbrellaGatekeper', function() {
  describe('api matching', function() {
    describe('host matching', function() {
      shared.runServer({
        gatekeeper: {
          default_frontend_host: 'default-host-config.example.com',
        },
        apis: [
          {
            'frontend_host': 'localhost:7777',
            'backend_host': 'example.com',
            '_id': 'localhost-non-matching-port',
            'url_matches': [
              {
                'frontend_prefix': '/info/matching/',
                'backend_prefix': '/info/matching/'
              }
            ]
          },
          {
            'frontend_host': 'localhost:9333',
            'backend_host': 'example.com',
            '_id': 'localhost-with-port',
            'url_matches': [
              {
                'frontend_prefix': '/info/matching/',
                'backend_prefix': '/info/matching/'
              }
            ]
          },
          {
            'frontend_host': 'localhost:80',
            'backend_host': 'example.com',
            '_id': 'localhost-default-port',
            'url_matches': [
              {
                'frontend_prefix': '/info/matching/',
                'backend_prefix': '/info/matching/'
              }
            ]
          },
          {
            'frontend_host': 'localhost:443',
            'backend_host': 'example.com',
            '_id': 'localhost-ssl-port',
            'url_matches': [
              {
                'frontend_prefix': '/info/matching/',
                'backend_prefix': '/info/matching/'
              }
            ]
          },
          {
            'frontend_host': 'fallback.example.com',
            'backend_host': 'example.com',
            '_id': 'fallback-no-port',
            'url_matches': [
              {
                'frontend_prefix': '/info/matching/',
                'backend_prefix': '/info/matching/'
              }
            ]
          },
          {
            'frontend_host': '*',
            'backend_host': 'example.com',
            '_id': 'wildcard',
            'url_matches': [
              {
                'frontend_prefix': '/info/wildcard/',
                'backend_prefix': '/info/wildcard/'
              }
            ]
          },
          {
            'frontend_host': 'wildcard-coexist.example.com',
            'backend_host': 'example.com',
            '_id': 'host-over-wildcard',
            'url_matches': [
              {
                'frontend_prefix': '/info/wildcard-coexist/',
                'backend_prefix': '/info/wildcard-coexist/'
              }
            ]
          },
          {
            'frontend_host': 'default-host-config.example.com',
            'backend_host': 'example.com',
            '_id': 'default-host-config',
            'url_matches': [
              {
                'frontend_prefix': '/info/default-host-config/',
                'backend_prefix': '/info/default-host-config/'
              }
            ]
          },

        ],
      });

      it('uses full host with port to find the matching api', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey);
        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('localhost-with-port');
          done();
        });
      });

      it('prefers the host header', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey, {
          headers: {
            'Host': 'localhost:80',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('localhost-default-port');
          done();
        });
      });

      it('fills in host headers with missing ports with defaults', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey, {
          headers: {
            'Host': 'localhost',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('localhost-default-port');
          done();
        });
      });

      it('determines the default ports based on the protocol', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey, {
          headers: {
            'Host': 'localhost',
            'X-Forwarded-Proto': 'https',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('localhost-ssl-port');
          done();
        });
      });

      it('falls back to the hostname when using a standard port', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey, {
          headers: {
            'Host': 'fallback.example.com:80',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('fallback-no-port');
          done();
        });
      });

      it('falls back to the hostname when using a non-standard port', function(done) {
        var opts = shared.buildRequestOptions('/info/matching/', this.apiKey, {
          headers: {
            'Host': 'fallback.example.com:123',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('fallback-no-port');
          done();
        });
      });

      it('falls back to wildcard hostnames if no other hostname matches', function(done) {
        var opts = shared.buildRequestOptions('/info/wildcard/', this.apiKey, {
          headers: {
            'Host': 'google.com:789',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('wildcard');
          done();
        });
      });

      it('can still fallback to wildcard apis even if a matching host is present for other apis', function(done) {
        var opts = shared.buildRequestOptions('/info/wildcard/', this.apiKey, {
          headers: {
            'Host': 'wildcard-coexist.example.com',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('wildcard');
          done();
        });
      });

      it('allows a configurable default host to fallback to', function(done) {
        var opts = shared.buildRequestOptions('/info/default-host-config/', this.apiKey, {
          headers: {
            'Host': 'google.com:890',
          },
        });

        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('default-host-config');
          done();
        });
      });

      describe('non-matching host', function() {
        shared.itBehavesLikeGatekeeperBlocked('/info/matching/', 404, 'NOT_FOUND', {
          headers: {
            'Host': 'unmatched.example.com',
          },
        });
      });
    });

    describe('prefix matching', function() {
      shared.runServer({
        apis: [
          {
            'frontend_host': 'localhost',
            'backend_host': 'example.com',
            '_id': 'other-prefix',
            'url_matches': [
              {
                'frontend_prefix': '/info/other/',
                'backend_prefix': '/info/other/'
              }
            ],
          },
          {
            'frontend_host': 'unused.example.com',
            'backend_host': 'example.com',
            '_id': 'specific-prefix-different-host',
            'url_matches': [
              {
                'frontend_prefix': '/info/specific/',
                'backend_prefix': '/info/specific/'
              }
            ],
          },
          {
            'frontend_host': 'localhost',
            'backend_host': 'example.com',
            '_id': 'specific-prefix',
            'url_matches': [
              {
                'frontend_prefix': '/info/specific/',
                'backend_prefix': '/info/specific/'
              }
            ],
          },
        ],
      });

      it('matches based on host and prefix combination', function(done) {
        var opts = shared.buildRequestOptions('/info/specific/', this.apiKey);
        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('specific-prefix');
          done();
        });
      });

      it('ignores everything past the matching prefix', function(done) {
        var opts = shared.buildRequestOptions('/info/specific/abc/xyz', this.apiKey);
        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.headers['x-api-umbrella-backend-id'].should.eql('specific-prefix');
          done();
        });
      });

      describe('non-matching prefixes', function() {
        describe('mismatched trailing slash', function() {
          shared.itBehavesLikeGatekeeperBlocked('/info/specific', 404, 'NOT_FOUND');
        });

        describe('mismatched case sensitivity', function() {
          shared.itBehavesLikeGatekeeperBlocked('/info/SPECIFIC/', 404, 'NOT_FOUND');
        });
      });
    });

    describe('request rewriting', function() {
      shared.runServer({
        apis: [
          {
            'frontend_host': 'localhost',
            'backend_host': 'example.com',
            '_id': 'rewrites',
            'url_matches': [
              {
                'frontend_prefix': '/info/incoming/',
                'backend_prefix': '/info/outgoing/'
              }
            ],
          },
        ],
      });

      it('rewrites the prefix', function(done) {
        var opts = shared.buildRequestOptions('/info/incoming/example', this.apiKey);
        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.url.path.should.eql('/info/outgoing/example');
          done();
        });
      });

      it('maintains query string parameters when rewriting the prefix', function(done) {
        var opts = shared.buildRequestOptions('/info/incoming/example?param1=value1&param2=value2', this.apiKey);
        request.get(opts, function(error, response, body) {
          var data = JSON.parse(body);
          data.url.path.should.eql('/info/outgoing/example?param1=value1&param2=value2');
          done();
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>// main.js
<commit_msg>clean file<commit_after><|endoftext|>


<commit_before>'use strict'

var React = require('react')
var to_title_case = require('app/to_title_case.js')
var DateInput = require('./date')

var Field = React.createClass({
  render: function () {
    if (this.props.value && this.props.mode !== 'edit') {
      return (

          {this.props.name}
          {this.props.value}

      )
    } else if (this.props.mode === 'edit') {
      return (

          {this.props.name}
          { input_or_select(this.props) }

      )
    } else {
      return (

 )}}})

function input_or_select (props) {
  var select_options = {
    standing_order: ['true', 'false'],
    membership_type: ['Annual Single', 'Annual Double', 'Annual Family',
        'Annual Group', 'Annual Corporate', 'Life Single', 'Life Double'],
    type: ['Cash', 'Cheque', 'BACs', 'SO', 'HO', 'CAF']
  }
  return select_options[props.id] ?
      make_select(props, select_options[props.id]) :
      make_input(props) }

function make_input (props) {
  return <input
    placeholder={make_placeholder(props.name)}
    className={props.error ? 'red' : ''}
    {...props} /> }

function make_select (props, options) {
  return (
    <select {...props} value={'' + props.value} >
      <option disabled value={''}> -- select an option -- </option>
      { options.map(function (option, i) {
        return <option
            value={option}
            key={i}>{option}</option> }) }
    </select>)}

function make_placeholder (name) {
  return name.match(/[dD]ate/) ? 'dd/mm/yyyy' : name }

module.exports = Field
<commit_msg>news type is a dropdown<commit_after>'use strict'

var React = require('react')
var to_title_case = require('app/to_title_case.js')
var DateInput = require('./date')

var Field = React.createClass({
  render: function () {
    if (this.props.value && this.props.mode !== 'edit') {
      return (

          {this.props.name}
          {this.props.value}

      )
    } else if (this.props.mode === 'edit') {
      return (

          {this.props.name}
          { input_or_select(this.props) }

      )
    } else {
      return (

 )}}})

function input_or_select (props) {
  var select_options = {
    standing_order: ['true', 'false'],
    membership_type: ['Annual Single', 'Annual Double', 'Annual Family',
        'Annual Group', 'Annual Corporate', 'Life Single', 'Life Double'],
    type: ['Cash', 'Cheque', 'BACs', 'SO', 'HO', 'CAF'],
    news_type: ['Post', 'Email']
  }
  return select_options[props.id] ?
      make_select(props, select_options[props.id]) :
      make_input(props) }

function make_input (props) {
  return <input
    placeholder={make_placeholder(props.name)}
    className={props.error ? 'red' : ''}
    {...props} /> }

function make_select (props, options) {
  return (
    <select {...props} value={'' + props.value} >
      <option disabled value={''}> -- select an option -- </option>
      { options.map(function (option, i) {
        return <option
            value={option}
            key={i}>{option}</option> }) }
    </select>)}

function make_placeholder (name) {
  return name.match(/[dD]ate/) ? 'dd/mm/yyyy' : name }

module.exports = Field
<|endoftext|>


<commit_before>function telaInicial(){
	context.save();
	drawArena("BELIZARIO'S SCAPE");
	context.fillStyle="#C71585";

	context.font=window.innerWidth/25+"px arial";
	context.fillText("Clique Aqui para iniciar o Game",window.innerWidth/5,window.innerHeight/10);
	context.fillStyle="black";
	context.font=window.innerWidth/50+"px arial";
	context.fillText("Fuja do Belizário e recolha a maior quantidade de pilhas!",window.innerWidth/4,window.innerHeight/1.2);
	context.restore();
}<commit_msg>commit<commit_after>function telaInicial(){
	context.save();
	drawArena("BELIZARIO'S SCAPE");

	context.restore();
}<|endoftext|>


<commit_before>import RedditModel from './RedditModel';

import { ACCOUNT } from './thingTypes';

const T = RedditModel.Types;

export default class Subreddit extends RedditModel {
  static type = ACCOUNT;

  static PROPERTIES = {
    commentKarma: T.number,
    createdUTC: T.number,
    features: T.nop,
    goldCreddits: T.number,
    goldExpiration: T.number,
    hasMail: T.bool,
    hasModMail: T.bool,
    hasVerifiedEmail: T.bool,
    hideFromRobots: T.bool,
    id: T.string,
    inBeta: T.bool,
    inboxCount: T.number,
    isEmployee: T.bool,
    isGold: T.bool,
    isMod: T.bool,
    isSuspended: T.bool,
    linkKarma: T.number,
    loid: T.string,
    loidCreated: T.number,
    name: T.string,
    over18: T.bool,
    suspensionExpirationUTC: T.number,
  }

  static API_ALIASES = {
    comment_karm: 'commentKarma',
    created_utc: 'createdUTC',
    gold_creddits: 'goldCreddits',
    gold_expiration: 'goldExpiration',
    has_mail: 'hasMail',
    has_mod_mail: 'hasModMail',
    has_verified_email: 'hasVerifiedEmail',
    hide_from_robots: 'hideFromRobots',
    in_beta: 'inBeta',
    is_employee: 'isEmployee',
    is_gold: 'isGold',
    is_mod: 'isMod',
    is_suspended: 'isSuspended',
    link_karma: 'linkKarma',
    loid_created: 'loidCreated',
    over_18: 'over18',
    suspension_expiration_utc: 'suspensionExpirationUTC',
  }

  makeUUID(data) {
    return data.name;
  }
}
<commit_msg>Add oauth client id to account endpoint (#193)<commit_after>import RedditModel from './RedditModel';

import { ACCOUNT } from './thingTypes';

const T = RedditModel.Types;

export default class Subreddit extends RedditModel {
  static type = ACCOUNT;

  static PROPERTIES = {
    commentKarma: T.number,
    createdUTC: T.number,
    features: T.nop,
    goldCreddits: T.number,
    goldExpiration: T.number,
    hasMail: T.bool,
    hasModMail: T.bool,
    hasVerifiedEmail: T.bool,
    hideFromRobots: T.bool,
    id: T.string,
    inBeta: T.bool,
    inboxCount: T.number,
    isEmployee: T.bool,
    isGold: T.bool,
    isMod: T.bool,
    isSuspended: T.bool,
    linkKarma: T.number,
    loid: T.string,
    loidCreated: T.number,
    name: T.string,
    oauthClientId: T.string,
    over18: T.bool,
    suspensionExpirationUTC: T.number,
  }

  static API_ALIASES = {
    comment_karm: 'commentKarma',
    created_utc: 'createdUTC',
    gold_creddits: 'goldCreddits',
    gold_expiration: 'goldExpiration',
    has_mail: 'hasMail',
    has_mod_mail: 'hasModMail',
    has_verified_email: 'hasVerifiedEmail',
    hide_from_robots: 'hideFromRobots',
    in_beta: 'inBeta',
    is_employee: 'isEmployee',
    is_gold: 'isGold',
    is_mod: 'isMod',
    is_suspended: 'isSuspended',
    link_karma: 'linkKarma',
    loid_created: 'loidCreated',
    oauth_client_id: 'oauthClientId',
    over_18: 'over18',
    suspension_expiration_utc: 'suspensionExpirationUTC',
  }

  makeUUID(data) {
    return data.name;
  }
}
<|endoftext|>


<commit_before>$.fn.slide.defaults.duration = 0;
var testx = function() {};

suite('buttons', function() {

  var slider1;

  setup(function() {
    $('#fixture').empty().html($('#clone').clone());

    slider1 = $('#fixture .slider1');
  });

  test('buttons created', function() {
    slider1.slide().slideButtons();
    assert.ok(slider1.find('button').length);
  });

  test('click prev button', function() {
    slider1.slide().slideButtons();
    $('#fixture .slide-next').click();
    $('#fixture .slide-previous').click();
    assert.equal(slider1.slide('getCurrentPage'), 1);
  });

  test('click next button', function() {
    slider1.slide().slideButtons();
    $('#fixture .slide-next').click();
    assert.equal(slider1.slide('getCurrentPage'), 2);
  });

  test('hide previous button on first page', function() {
    slider1.slide().slideButtons();
    assert.equal($('#fixture .slide-previous').css('visibility'), 'hidden');
  });

  test('hide next button on last page', function(done) {
    slider1.slide().slideButtons();
    slider1.slide('goLast', function() {
      assert.equal($('#fixture .slide-next').css('visibility'), 'hidden');
      done();
    });
  });

  test('show previous button on 2nd page', function(done) {
    slider1.slide().slideButtons();
    slider1.slide('goNext', function() {
      assert.equal($('#fixture .slide-previous').css('visibility'), 'visible');
      done();
    });
  });

  test('show previous on first page if wrap enabled', function() {
    $('#fixture,#clone').css('visibility', 'visible');
    slider1.slide({ wrap: true }).slideButtons();
    console.log(slider1.data('slide').wrap);
    assert.equal($('#fixture .slide-previous').css('visibility'), 'visible');
    $('#fixture,#clone').css('visibility', 'hidden');
  });

  test('show next on last page if wrap enabled', function(done) {
    $('#fixture,#clone').css('visibility', 'visible');
    slider1.slide({ wrap: true }).slideButtons();
    slider1.slide('goLast', function() {
      assert.equal($('#fixture .slide-next').css('visibility'), 'visible');
      $('#fixture,#clone').css('visibility', 'hidden');
      done();
    });
  });

});
<commit_msg>removed console.log<commit_after>$.fn.slide.defaults.duration = 0;
var testx = function() {};

suite('buttons', function() {

  var slider1;

  setup(function() {
    $('#fixture').empty().html($('#clone').clone());

    slider1 = $('#fixture .slider1');
  });

  test('buttons created', function() {
    slider1.slide().slideButtons();
    assert.ok(slider1.find('button').length);
  });

  test('click prev button', function() {
    slider1.slide().slideButtons();
    $('#fixture .slide-next').click();
    $('#fixture .slide-previous').click();
    assert.equal(slider1.slide('getCurrentPage'), 1);
  });

  test('click next button', function() {
    slider1.slide().slideButtons();
    $('#fixture .slide-next').click();
    assert.equal(slider1.slide('getCurrentPage'), 2);
  });

  test('hide previous button on first page', function() {
    slider1.slide().slideButtons();
    assert.equal($('#fixture .slide-previous').css('visibility'), 'hidden');
  });

  test('hide next button on last page', function(done) {
    slider1.slide().slideButtons();
    slider1.slide('goLast', function() {
      assert.equal($('#fixture .slide-next').css('visibility'), 'hidden');
      done();
    });
  });

  test('show previous button on 2nd page', function(done) {
    slider1.slide().slideButtons();
    slider1.slide('goNext', function() {
      assert.equal($('#fixture .slide-previous').css('visibility'), 'visible');
      done();
    });
  });

  test('show previous on first page if wrap enabled', function() {
    $('#fixture,#clone').css('visibility', 'visible');
    slider1.slide({ wrap: true }).slideButtons();
    assert.equal($('#fixture .slide-previous').css('visibility'), 'visible');
    $('#fixture,#clone').css('visibility', 'hidden');
  });

  test('show next on last page if wrap enabled', function(done) {
    $('#fixture,#clone').css('visibility', 'visible');
    slider1.slide({ wrap: true }).slideButtons();
    slider1.slide('goLast', function() {
      assert.equal($('#fixture .slide-next').css('visibility'), 'visible');
      $('#fixture,#clone').css('visibility', 'hidden');
      done();
    });
  });

});
<|endoftext|>


<commit_before>'use strict';

/**
 * Types.js service
 *
 * @description: A set of functions to make the schema easier to build.
 */

const _ = require('lodash');
const { GraphQLUpload } = require('apollo-server-koa');
const graphql = require('graphql');
const GraphQLJSON = require('graphql-type-json');
const GraphQLDateTime = require('graphql-type-datetime');
const GraphQLLong = require('graphql-type-long');
const pluralize = require('pluralize');
/* eslint-disable no-unused-vars */

module.exports = {
  /**
   * Convert Strapi type to GraphQL type.
   * @param {Object} attribute Information about the attribute.
   * @param {Object} attribute.definition Definition of the attribute.
   * @param {String} attribute.modelName Name of the model which owns the attribute.
   * @param {String} attribute.attributeName Name of the attribute.
   * @return String
   */

  convertType: function({
    definition = {},
    modelName = '',
    attributeName = '',
    rootType = 'query',
    action = ''
  }) {
    // Type
    if (definition.type) {
      let type = 'String';

      switch (definition.type) {
        // TODO: Handle fields of type Array, Perhaps default to [Int] or [String] ...
        case 'boolean':
          type = 'Boolean';
          break;
        case 'integer':
          type = 'Int';
          break;
        case 'biginteger':
          type = 'Long';
          break;
        case 'decimal':
          type = 'Float';
          break;
        case 'float':
          type = 'Float';
          break;
        case 'json':
          type = 'JSON';
          break;
        case 'time':
        case 'date':
        case 'datetime':
        case 'timestamp':
          type = 'DateTime';
          break;
        case 'enumeration':
          type = this.convertEnumType(definition, modelName, attributeName);
          break;
      }

      if (definition.required && action !== 'update') {
        type += '!';
      }

      return type;
    }

    const ref = definition.model || definition.collection;

    // Association
    if (ref && ref !== '*') {
      // Add bracket or not
      const globalId = definition.plugin
        ? strapi.plugins[definition.plugin].models[ref].globalId
        : strapi.models[ref].globalId;
      const plural = !_.isEmpty(definition.collection);

      if (plural) {
        if (rootType === 'mutation') {
          return '[ID]';
        }

        return `[${globalId}]`;
      }

      if (rootType === 'mutation') {
        return 'ID';
      }

      return globalId;
    }

    if (rootType === 'mutation') {
      return definition.model ? 'ID' : '[ID]';
    }

    return definition.model ? 'Morph' : '[Morph]';
  },

  /**
   * Convert Strapi enumeration to GraphQL Enum.
   * @param {Object} definition Definition of the attribute.
   * @param {String} model Name of the model which owns the attribute.
   * @param {String} field Name of the attribute.
   * @return String
   */

  convertEnumType: (definition, model, field) =>
    definition.enumName
      ? definition.enumName
      : `ENUM_${model.toUpperCase()}_${field.toUpperCase()}`,

  /**
   * Remove custom scalar type such as Upload because Apollo automatically adds it in the schema.
   * but we need to add it to print the schema on our side.
   *
   * @return void
   */

  removeCustomScalar: (typeDefs, resolvers) => {
    delete resolvers.Upload;
    return typeDefs.replace('scalar Upload', '');
  },

  /**
   * Add custom scalar type such as JSON.
   *
   * @return void
   */

  addCustomScalar: resolvers => {
    Object.assign(resolvers, {
      JSON: GraphQLJSON,
      DateTime: GraphQLDateTime,
      Long: GraphQLLong,
      Upload: GraphQLUpload,
    });

    return 'scalar JSON \n scalar DateTime \n scalar Upload';
  },

  /**
   * Add Union Type that contains the types defined by the user.
   *
   * @return string
   */

  addPolymorphicUnionType: (customDefs, defs) => {
    const types = graphql
      .parse(customDefs + defs)
      .definitions.filter(
        def =>
          def.kind === 'ObjectTypeDefinition' && def.name.value !== 'Query',
      )
      .map(def => def.name.value);

    if (types.length > 0) {
      return {
        polymorphicDef: `union Morph = ${types.join(' | ')}`,
        polymorphicResolver: {
          Morph: {
            __resolveType(obj, context, info) {
              // eslint-disable-line no-unused-vars
              return obj.kind || obj._type;
            },
          },
        },
      };
    }

    return {
      polymorphicDef: '',
      polymorphicResolver: {},
    };
  },

  addInput: function() {
    return `
      input InputID { id: ID!}
    `;
  },

  generateInputModel: function(model, name) {
    const globalId = model.globalId;
    const inputName = `${_.capitalize(name)}Input`;

    /* eslint-disable */
    return `
      input ${inputName} {
        ${Object.keys(model.attributes)
          .map(attribute => {
            return `${attribute}: ${this.convertType({
              definition: model.attributes[attribute],
              modelName: globalId,
              attributeName: attribute,
              rootType: 'mutation',
            })}`;
          })
          .join('\n')}
      }

      input edit${inputName} {
        ${Object.keys(model.attributes)
          .map(attribute => {
            return `${attribute}: ${this.convertType({
              definition: model.attributes[attribute],
              modelName: globalId,
              attributeName: attribute,
              rootType: 'mutation',
              action: 'update'
            })}`;
          })
          .join('\n')}
      }
    `;
    /* eslint-enable */
  },

  generateInputPayloadArguments: function(model, name, type, resolver) {
    if (_.get(resolver, `Mutation.${type}${_.capitalize(name)}`) === false) {
      return '';
    }

    const inputName = `${_.capitalize(name)}Input`;
    const payloadName = `${_.capitalize(name)}Payload`;
    /* eslint-disable indent */
    switch (type) {
      case 'create':
        return `
          input ${type}${inputName} { data: ${inputName} }
          type ${type}${payloadName} { ${pluralize.singular(name)}: ${
          model.globalId
        } }
        `;
      case 'update':
        return `
          input ${type}${inputName}  { where: InputID, data: edit${inputName} }
          type ${type}${payloadName} { ${pluralize.singular(name)}: ${
          model.globalId
        } }
        `;
      case 'delete':
        return `
          input ${type}${inputName}  { where: InputID }
          type ${type}${payloadName} { ${pluralize.singular(name)}: ${
          model.globalId
        } }
        `;
      default:
      // Nothing
    }
    /* eslint-enable indent */
  },
};
<commit_msg>Fix return of long type<commit_after>'use strict';

/**
 * Types.js service
 *
 * @description: A set of functions to make the schema easier to build.
 */

const _ = require('lodash');
const { GraphQLUpload } = require('apollo-server-koa');
const graphql = require('graphql');
const GraphQLJSON = require('graphql-type-json');
const GraphQLDateTime = require('graphql-type-datetime');
const GraphQLLong = require('graphql-type-long');
const pluralize = require('pluralize');
/* eslint-disable no-unused-vars */

module.exports = {
  /**
   * Convert Strapi type to GraphQL type.
   * @param {Object} attribute Information about the attribute.
   * @param {Object} attribute.definition Definition of the attribute.
   * @param {String} attribute.modelName Name of the model which owns the attribute.
   * @param {String} attribute.attributeName Name of the attribute.
   * @return String
   */

  convertType: function({
    definition = {},
    modelName = '',
    attributeName = '',
    rootType = 'query',
    action = ''
  }) {
    // Type
    if (definition.type) {
      let type = 'String';

      switch (definition.type) {
        // TODO: Handle fields of type Array, Perhaps default to [Int] or [String] ...
        case 'boolean':
          type = 'Boolean';
          break;
        case 'integer':
          type = 'Int';
          break;
        case 'biginteger':
          type = 'Long';
          break;
        case 'decimal':
          type = 'Float';
          break;
        case 'float':
          type = 'Float';
          break;
        case 'json':
          type = 'JSON';
          break;
        case 'time':
        case 'date':
        case 'datetime':
        case 'timestamp':
          type = 'DateTime';
          break;
        case 'enumeration':
          type = this.convertEnumType(definition, modelName, attributeName);
          break;
      }

      if (definition.required && action !== 'update') {
        type += '!';
      }

      return type;
    }

    const ref = definition.model || definition.collection;

    // Association
    if (ref && ref !== '*') {
      // Add bracket or not
      const globalId = definition.plugin
        ? strapi.plugins[definition.plugin].models[ref].globalId
        : strapi.models[ref].globalId;
      const plural = !_.isEmpty(definition.collection);

      if (plural) {
        if (rootType === 'mutation') {
          return '[ID]';
        }

        return `[${globalId}]`;
      }

      if (rootType === 'mutation') {
        return 'ID';
      }

      return globalId;
    }

    if (rootType === 'mutation') {
      return definition.model ? 'ID' : '[ID]';
    }

    return definition.model ? 'Morph' : '[Morph]';
  },

  /**
   * Convert Strapi enumeration to GraphQL Enum.
   * @param {Object} definition Definition of the attribute.
   * @param {String} model Name of the model which owns the attribute.
   * @param {String} field Name of the attribute.
   * @return String
   */

  convertEnumType: (definition, model, field) =>
    definition.enumName
      ? definition.enumName
      : `ENUM_${model.toUpperCase()}_${field.toUpperCase()}`,

  /**
   * Remove custom scalar type such as Upload because Apollo automatically adds it in the schema.
   * but we need to add it to print the schema on our side.
   *
   * @return void
   */

  removeCustomScalar: (typeDefs, resolvers) => {
    delete resolvers.Upload;
    return typeDefs.replace('scalar Upload', '');
  },

  /**
   * Add custom scalar type such as JSON.
   *
   * @return void
   */

  addCustomScalar: resolvers => {
    Object.assign(resolvers, {
      JSON: GraphQLJSON,
      DateTime: GraphQLDateTime,
      Long: GraphQLLong,
      Upload: GraphQLUpload,
    });

    return 'scalar JSON \n scalar DateTime \n scalar Long \n scalar Upload';
  },

  /**
   * Add Union Type that contains the types defined by the user.
   *
   * @return string
   */

  addPolymorphicUnionType: (customDefs, defs) => {
    const types = graphql
      .parse(customDefs + defs)
      .definitions.filter(
        def =>
          def.kind === 'ObjectTypeDefinition' && def.name.value !== 'Query',
      )
      .map(def => def.name.value);

    if (types.length > 0) {
      return {
        polymorphicDef: `union Morph = ${types.join(' | ')}`,
        polymorphicResolver: {
          Morph: {
            __resolveType(obj, context, info) {
              // eslint-disable-line no-unused-vars
              return obj.kind || obj._type;
            },
          },
        },
      };
    }

    return {
      polymorphicDef: '',
      polymorphicResolver: {},
    };
  },

  addInput: function() {
    return `
      input InputID { id: ID!}
    `;
  },

  generateInputModel: function(model, name) {
    const globalId = model.globalId;
    const inputName = `${_.capitalize(name)}Input`;

    /* eslint-disable */
    return `
      input ${inputName} {
        ${Object.keys(model.attributes)
          .map(attribute => {
            return `${attribute}: ${this.convertType({
              definition: model.attributes[attribute],
              modelName: globalId,
              attributeName: attribute,
              rootType: 'mutation',
            })}`;
          })
          .join('\n')}
      }

      input edit${inputName} {
        ${Object.keys(model.attributes)
          .map(attribute => {
            return `${attribute}: ${this.convertType({
              definition: model.attributes[attribute],
              modelName: globalId,
              attributeName: attribute,
              rootType: 'mutation',
              action: 'update'
            })}`;
          })
          .join('\n')}
      }
    `;
    /* eslint-enable */
  },

  generateInputPayloadArguments: function(model, name, type, resolver) {
    if (_.get(resolver, `Mutation.${type}${_.capitalize(name)}`) === false) {
      return '';
    }

    const inputName = `${_.capitalize(name)}Input`;
    const payloadName = `${_.capitalize(name)}Payload`;
    /* eslint-disable indent */
    switch (type) {
      case 'create':
        return `
          input ${type}${inputName} { data: ${inputName} }
          type ${type}${payloadName} { ${pluralize.singular(name)}: ${
          model.globalId
        } }
        `;
      case 'update':
        return `
          input ${type}${inputName}  { where: InputID, data: edit${inputName} }
          type ${type}${payloadName} { ${pluralize.singular(name)}: ${
          model.globalId
        } }
        `;
      case 'delete':
        return `
          input ${type}${inputName}  { where: InputID }
          type ${type}${payloadName} { ${pluralize.singular(name)}: ${
          model.globalId
        } }
        `;
      default:
      // Nothing
    }
    /* eslint-enable indent */
  },
};
<|endoftext|>


<commit_before>import { execSync } from 'child_process';
import fs from 'fs-promise';
import os from 'os';
import path from 'path';

import { expect } from 'chai';
import proxyquire from 'proxyquire';

import installDeps from '../../src/util/install-dependencies';
import readPackageJSON from '../../src/util/read-package-json';

const installer = process.argv.find(arg => arg.startsWith('--installer=')) || '--installer=system default';
const forge = proxyquire.noCallThru().load('../../src/api', {
  './install': async () => {},
});

describe(`electron-forge API (with installer=${installer.substr(12)})`, () => {
  let dirID = Date.now();
  const forLintingMethod = (lintStyle) => {
    describe(`init (with lintStyle=${lintStyle})`, () => {
      let dir;

      before(async () => {
        dir = path.resolve(os.tmpdir(), `electron-forge-test-${dirID}`);
        dirID += 1;
        await fs.remove(dir);
        await forge.init({
          dir,
          lintstyle: lintStyle,
        });
      });

      it('should create a new folder with a npm module inside', async () => {
        expect(await fs.exists(dir), 'the target dir should have been created').to.equal(true);
        expect(await fs.exists(path.resolve(dir, 'package.json')), 'the package.json file should exist').to.equal(true);
      });

      it('should have initialized a git repository', async () => {
        expect(await fs.exists(path.resolve(dir, '.git')), 'the .git folder should exist').to.equal(true);
      });

      it('should have installed the initial node_modules', async () => {
        expect(await fs.exists(path.resolve(dir, 'node_modules')), 'node_modules folder should exist').to.equal(true);
        expect(await fs.exists(path.resolve(dir, 'node_modules/electron-prebuilt-compile')), 'electron-prebuilt-compile should exist').to.equal(true);
        expect(await fs.exists(path.resolve(dir, 'node_modules/babel-core')), 'babel-core should exist').to.equal(true);
      });

      describe('lint', () => {
        it('should initially pass the linting process', () => forge.lint({ dir }));
      });

      after(() => fs.remove(dir));
    });
  };
  forLintingMethod('airbnb');
  forLintingMethod('standard');

  describe('init (with custom templater)', () => {
    let dir;

    before(async () => {
      dir = path.resolve(os.tmpdir(), `electron-forge-test-${dirID}`);
      dirID += 1;
      await fs.remove(dir);
      execSync('npm link', {
        cwd: path.resolve(__dirname, '../fixture/custom_init'),
      });
      await forge.init({
        dir,
        template: 'dummy',
      });
    });

    it('should create dot files correctly', async () => {
      expect(await fs.exists(dir), 'the target dir should have been created').to.equal(true);
      expect(await fs.exists(path.resolve(dir, '.bar')), 'the .bar file should exist').to.equal(true);
    });

    it('should create deep files correctly', async () => {
      expect(await fs.exists(path.resolve(dir, 'src/foo.js')), 'the src/foo.js file should exist').to.equal(true);
    });

    describe('lint', () => {
      it('should initially pass the linting process', () => forge.lint({ dir }));
    });

    after(async () => {
      await fs.remove(dir);
      execSync('npm unlink', {
        cwd: path.resolve(__dirname, '../fixture/custom_init'),
      });
    });
  });

  describe('init (with built-in templater)', () => {
    let dir;

    before(async () => {
      dir = path.resolve(os.tmpdir(), `electron-forge-test-${dirID}`);
      dirID += 1;
      await fs.remove(dir);
    });

    it('should succeed in initializing', async () => {
      await forge.init({
        dir,
        template: 'react-typescript',
      });
    });

    it('should succeed in initializing an already initialized directory', async () => {
      await forge.init({
        dir,
        template: 'react-typescript',
      });
    });

    it('should add a dependency on react', async () => {
      expect(Object.keys(require(path.resolve(dir, 'package.json')).dependencies)).to.contain('react');
    });

    after(async () => {
      await fs.remove(dir);
    });
  });

  describe('init (with a nonexistent templater)', () => {
    let dir;

    before(async () => {
      dir = path.resolve(os.tmpdir(), `electron-forge-test-${dirID}`);
      dirID += 1;
      await fs.remove(dir);
    });

    it('should fail in initializing', async () => {
      await expect(forge.init({
        dir,
        template: 'does-not-exist',
      })).to.eventually.be.rejectedWith('Failed to locate custom template');
    });

    after(async () => {
      await fs.remove(dir);
    });
  });

  describe('after init', () => {
    let dir;

    before(async () => {
      dir = path.resolve(os.tmpdir(), `electron-forge-test-${dirID}/electron-forge-test`);
      dirID += 1;
      await forge.init({ dir });

      const packageJSON = await readPackageJSON(dir);
      packageJSON.name = 'testapp';
      packageJSON.productName = 'Test App';
      packageJSON.config.forge.electronPackagerConfig.asar = false;
      packageJSON.config.forge.windowsStoreConfig.packageName = 'TestApp';
      packageJSON.homepage = 'http://www.example.com/';
      packageJSON.author = 'Test Author';
      await fs.writeFile(path.resolve(dir, 'package.json'), JSON.stringify(packageJSON, null, 2));
    });

    it('can package without errors', async () => {
      await forge.package({ dir });
    });

    it('can package without errors with native pre-gyp deps installed', async () => {
      await installDeps(dir, ['ref']);
      await forge.package({ dir });
    });

    describe('after package', () => {
      let resourcesPath = 'Test App.app/Contents/Resources';
      if (process.platform !== 'darwin') {
        resourcesPath = 'resources';
      }

      it('should have deleted the forge config from the packaged app', async () => {
        const cleanPackageJSON = await readPackageJSON(
          path.resolve(dir, 'out', `Test App-${process.platform}-${process.arch}`, resourcesPath, 'app')
        );
        expect(cleanPackageJSON).to.not.have.deep.property('config.forge');
      });

      it('should not affect the actual forge config', async () => {
        const normalPackageJSON = await readPackageJSON(dir);
        expect(normalPackageJSON).to.have.deep.property('config.forge');
      });

      let targets = [];
      if (fs.existsSync(path.resolve(__dirname, `../../src/makers/${process.platform}`))) {
        targets = fs.readdirSync(path.resolve(__dirname, `../../src/makers/${process.platform}`)).map(file => path.parse(file).name);
      }
      const genericTargets = fs.readdirSync(path.resolve(__dirname, '../../src/makers/generic')).map(file => path.parse(file).name);

      [].concat(targets).concat(genericTargets).forEach((target) => {
        describe(`make (with target=${target})`, () => {
          before(async () => {
            const packageJSON = await readPackageJSON(dir);
            packageJSON.config.forge.make_targets[process.platform] = [target];
            await fs.writeFile(path.resolve(dir, 'package.json'), JSON.stringify(packageJSON));
          });

          it('successfully makes with default config', async () => {
            await forge.make({ dir, skipPackage: true });
          });
        });
      });
    });

    after(() => fs.remove(dir));
  });
});
<commit_msg>test(tests): add tests for packager & maker outDir support<commit_after>import { execSync } from 'child_process';
import fs from 'fs-promise';
import os from 'os';
import path from 'path';

import { expect } from 'chai';
import proxyquire from 'proxyquire';

import installDeps from '../../src/util/install-dependencies';
import readPackageJSON from '../../src/util/read-package-json';

const installer = process.argv.find(arg => arg.startsWith('--installer=')) || '--installer=system default';
const forge = proxyquire.noCallThru().load('../../src/api', {
  './install': async () => {},
});

describe(`electron-forge API (with installer=${installer.substr(12)})`, () => {
  let dirID = Date.now();
  const forLintingMethod = (lintStyle) => {
    describe(`init (with lintStyle=${lintStyle})`, () => {
      let dir;

      before(async () => {
        dir = path.resolve(os.tmpdir(), `electron-forge-test-${dirID}`);
        dirID += 1;
        await fs.remove(dir);
        await forge.init({
          dir,
          lintstyle: lintStyle,
        });
      });

      it('should create a new folder with a npm module inside', async () => {
        expect(await fs.exists(dir), 'the target dir should have been created').to.equal(true);
        expect(await fs.exists(path.resolve(dir, 'package.json')), 'the package.json file should exist').to.equal(true);
      });

      it('should have initialized a git repository', async () => {
        expect(await fs.exists(path.resolve(dir, '.git')), 'the .git folder should exist').to.equal(true);
      });

      it('should have installed the initial node_modules', async () => {
        expect(await fs.exists(path.resolve(dir, 'node_modules')), 'node_modules folder should exist').to.equal(true);
        expect(await fs.exists(path.resolve(dir, 'node_modules/electron-prebuilt-compile')), 'electron-prebuilt-compile should exist').to.equal(true);
        expect(await fs.exists(path.resolve(dir, 'node_modules/babel-core')), 'babel-core should exist').to.equal(true);
      });

      describe('lint', () => {
        it('should initially pass the linting process', () => forge.lint({ dir }));
      });

      after(() => fs.remove(dir));
    });
  };
  forLintingMethod('airbnb');
  forLintingMethod('standard');

  describe('init (with custom templater)', () => {
    let dir;

    before(async () => {
      dir = path.resolve(os.tmpdir(), `electron-forge-test-${dirID}`);
      dirID += 1;
      await fs.remove(dir);
      execSync('npm link', {
        cwd: path.resolve(__dirname, '../fixture/custom_init'),
      });
      await forge.init({
        dir,
        template: 'dummy',
      });
    });

    it('should create dot files correctly', async () => {
      expect(await fs.exists(dir), 'the target dir should have been created').to.equal(true);
      expect(await fs.exists(path.resolve(dir, '.bar')), 'the .bar file should exist').to.equal(true);
    });

    it('should create deep files correctly', async () => {
      expect(await fs.exists(path.resolve(dir, 'src/foo.js')), 'the src/foo.js file should exist').to.equal(true);
    });

    describe('lint', () => {
      it('should initially pass the linting process', () => forge.lint({ dir }));
    });

    after(async () => {
      await fs.remove(dir);
      execSync('npm unlink', {
        cwd: path.resolve(__dirname, '../fixture/custom_init'),
      });
    });
  });

  describe('init (with built-in templater)', () => {
    let dir;

    before(async () => {
      dir = path.resolve(os.tmpdir(), `electron-forge-test-${dirID}`);
      dirID += 1;
      await fs.remove(dir);
    });

    it('should succeed in initializing', async () => {
      await forge.init({
        dir,
        template: 'react-typescript',
      });
    });

    it('should succeed in initializing an already initialized directory', async () => {
      await forge.init({
        dir,
        template: 'react-typescript',
      });
    });

    it('should add a dependency on react', async () => {
      expect(Object.keys(require(path.resolve(dir, 'package.json')).dependencies)).to.contain('react');
    });

    after(async () => {
      await fs.remove(dir);
    });
  });

  describe('init (with a nonexistent templater)', () => {
    let dir;

    before(async () => {
      dir = path.resolve(os.tmpdir(), `electron-forge-test-${dirID}`);
      dirID += 1;
      await fs.remove(dir);
    });

    it('should fail in initializing', async () => {
      await expect(forge.init({
        dir,
        template: 'does-not-exist',
      })).to.eventually.be.rejectedWith('Failed to locate custom template');
    });

    after(async () => {
      await fs.remove(dir);
    });
  });

  describe('after init', () => {
    let dir;

    before(async () => {
      dir = path.resolve(os.tmpdir(), `electron-forge-test-${dirID}/electron-forge-test`);
      dirID += 1;
      await forge.init({ dir });

      const packageJSON = await readPackageJSON(dir);
      packageJSON.name = 'testapp';
      packageJSON.productName = 'Test App';
      packageJSON.config.forge.electronPackagerConfig.asar = false;
      packageJSON.config.forge.windowsStoreConfig.packageName = 'TestApp';
      packageJSON.homepage = 'http://www.example.com/';
      packageJSON.author = 'Test Author';
      await fs.writeFile(path.resolve(dir, 'package.json'), JSON.stringify(packageJSON, null, 2));
    });

    it('can package without errors', async () => {
      await forge.package({ dir });
    });

    it('can package to outDir without errors', async () => {
      const outDir = `${dir}/foo`;

      expect(fs.existsSync(outDir)).to.equal(false);

      await forge.package({ dir, outDir });

      expect(fs.existsSync(outDir)).to.equal(true);
    });

    it('can package without errors with native pre-gyp deps installed', async () => {
      await installDeps(dir, ['ref']);
      await forge.package({ dir });
    });

    describe('after package', () => {
      let resourcesPath = 'Test App.app/Contents/Resources';
      if (process.platform !== 'darwin') {
        resourcesPath = 'resources';
      }

      it('should have deleted the forge config from the packaged app', async () => {
        const cleanPackageJSON = await readPackageJSON(
          path.resolve(dir, 'out', `Test App-${process.platform}-${process.arch}`, resourcesPath, 'app')
        );
        expect(cleanPackageJSON).to.not.have.deep.property('config.forge');
      });

      it('should not affect the actual forge config', async () => {
        const normalPackageJSON = await readPackageJSON(dir);
        expect(normalPackageJSON).to.have.deep.property('config.forge');
      });

      let targets = [];
      if (fs.existsSync(path.resolve(__dirname, `../../src/makers/${process.platform}`))) {
        targets = fs.readdirSync(path.resolve(__dirname, `../../src/makers/${process.platform}`)).map(file => path.parse(file).name);
      }
      const genericTargets = fs.readdirSync(path.resolve(__dirname, '../../src/makers/generic')).map(file => path.parse(file).name);

      [].concat(targets).concat(genericTargets).forEach((target) => {
        describe(`make (with target=${target})`, () => {
          before(async () => {
            const packageJSON = await readPackageJSON(dir);
            packageJSON.config.forge.make_targets[process.platform] = [target];
            await fs.writeFile(path.resolve(dir, 'package.json'), JSON.stringify(packageJSON));
          });

          it('successfully makes with default config', async () => {
            await forge.make({ dir, skipPackage: true });
          });

          it('successfully makes to outDir with default config', async () => {
            await forge.make({ dir, outDir: `${dir}/foo`, skipPackage: true });
          });
        });
      });
    });

    after(() => fs.remove(dir));
  });
});
<|endoftext|>


<commit_before>//Copyright (c) 2019, Livio, Inc.
const app = require('../app');
const sql = require('./sql.js');
const parseXml = require('xml2js').parseString;
const request = require('request');
const async = require('async');
const _ = require('lodash');

function validatePost(req, res) {
    return;
}

function promoteCustomVehicleData(client, obj, parentIdMapping = {}) {
    return function(cb) {
        let originalParentId = obj.parent_id;
        if (obj.parent_id) {
            let parent_id = parentIdMapping[obj.parent_id];
            if (!parent_id) {
                return cb(`Orphaned record`);
            }
            obj.parent_id = parent_id;
            //assign parent_id based on parentIdMapping.
        }

        async.waterfall(
            [
                function(callback) {
                    //skip update if status is on production and not a child that has had its parentId changed.
                    if (obj.status === 'PRODUCTION' && !(obj.parent_id && obj.parent_id != originalParentId)) {
                        parentIdMapping[obj.id] = obj.id;
                        return callback(null);
                    }
                    client.getOne(sql.insertProductionCustomVehicleData(obj), function(err, result) {
                        if (!err && result) {
                            parentIdMapping[obj.id] = result.id;
                        }
                        callback(err, result);
                    });
                }
            ], function(err) {
                if (err) {
                    return cb(err);
                }

                //update children.
                if (obj.params && obj.params.length > 0) {
                    let functions = [];
                    for (let param of obj.params) {
                        functions.push(promoteCustomVehicleData(client, param, parentIdMapping));
                    }
                    return async.waterfall(functions, function(err) {
                        cb(err);
                    });
                } else {
                    cb(err);
                }

            }
        );
    };
}

/**
 * Promotes all custom_vehicle_data records in STAGING if they are the
 * most recent. This means creating new PRODUCTION records and making sure
 * any parent_id relationships remain unchanged.
 *
 * Promoting a parent will cause all new PRODUCTION child records to be created.
 *
 * If the child record is in STAGING a new PRODUCTION record will be created using staging and the parent_id.
 *
 * This will be done as a single transaction with top level records being created first.
 *
 * @param cb
 */
function promote(cb) {
    app.locals.db.runAsTransaction(function(client, callback) {
        async.waterfall(
            [
                function(callback) {
                    app.locals.db.sqlCommand(sql.getVehicleData(false), function(err, res) {
                        callback(null, res);
                    });
                },
                //create nested data.
                function(data, callback) {
                    let vehicleDataById = {};
                    for (let customVehicleDataItem of data) {
                        vehicleDataById[customVehicleDataItem.id] = customVehicleDataItem;
                        customVehicleDataItem.params = [];
                    }

                    let result = [];
                    for (let customVehicleDataItem of data) {
                        if (customVehicleDataItem.parent_id) {
                            //old record not included.
                            if (!vehicleDataById[customVehicleDataItem.parent_id]) {
                                continue;
                            } else {
                                vehicleDataById[customVehicleDataItem.parent_id].params.push(customVehicleDataItem);
                            }
                        } else {
                            result.push(customVehicleDataItem);
                        }
                    }
                    callback(null, result);
                },
                //insert data
                function(data, callback) {
                    let functions = [];
                    for (let customVehicleDataItem of data) {
                        functions.push(promoteCustomVehicleData(client, customVehicleDataItem));
                    }
                    async.waterfall(functions, callback);
                }
            ], callback
        );
    }, cb);

}

function insertCustomVehicleDataItem(client, data, cb) {
    let newParentId;
    let oldParentId = data.id;
    let insertResult;

    async.waterfall(
        [
            function(callback) {
                client.getOne(sql.insertStagingCustomVehicleData(data), function(err, res) {
                    if (err) {
                        return cb(err, res);
                    }
                    if (oldParentId) {
                        newParentId = res.id;
                    }
                    insertResult = res;
                    callback(err, res);
                });
            },
            function(res, callback) { //insert new children
                if (!oldParentId) //new record no children.
                {
                    return callback(null, res);
                }
                newParentId = res.id;

                client.getMany(sql.getDirectChildren(oldParentId), function(err, res) {
                    if (err) {
                        return callback(err);
                    }

                    let functions = [];
                    for (let child of res) {
                        child.parent_id = newParentId;
                        child.status = 'STAGING';
                        functions.push(function(cb) {
                            insertCustomVehicleDataItem(client, child, cb);
                        });
                    }
                    async.parallel(functions, function(err) {
                        if (err) {
                            return callback(err);
                        }
                        return callback(err);
                    });
                });
            },
        ], cb
    );

}

function getCustomVehicleDataItem(customVehicleDataItem, isForPolicyTable) {
    return isForPolicyTable ? {
        name: customVehicleDataItem.name,
        type: customVehicleDataItem.type,
        key: customVehicleDataItem.key,
        mandatory: customVehicleDataItem.mandatory,
        minlength: customVehicleDataItem.min_length,
        maxlength: customVehicleDataItem.max_length,
        minsize: customVehicleDataItem.min_size,
        maxsize: customVehicleDataItem.max_size,
        maxvalue: customVehicleDataItem.max_value,
        array: customVehicleDataItem.array,
    } : customVehicleDataItem;
}

/**
 *
 * @param customVehicleDataItems
 * @param isForPolicyTable
 * @param cb
 */
function getNestedCustomVehicleData(customVehicleDataItems, isForPolicyTable, cb) {
    let vehicleDataById = {};
    for (let customVehicleDataItem of customVehicleDataItems) {
        vehicleDataById[customVehicleDataItem.id] = customVehicleDataItem;
        customVehicleDataItem.params = [];
    }

    let result = [];
    for (let customVehicleDataItem of customVehicleDataItems) {
        if (customVehicleDataItem.parent_id) {
            //if we are filtering by id the parent will not be included.
            if (vehicleDataById[customVehicleDataItem.parent_id]) {
                vehicleDataById[customVehicleDataItem.parent_id].params.push(getCustomVehicleDataItem(customVehicleDataItem, isForPolicyTable));
            } else { //if no parent_id matches, assume this is a top level item.
                result.push(getCustomVehicleDataItem(customVehicleDataItem, isForPolicyTable));
            }
        } else {
            result.push(getCustomVehicleDataItem(customVehicleDataItem, isForPolicyTable));
        }
    }
    cb(null, result);
}

/**
 * Returns a list of custom vehicle data items filtered by status and optionally by id.
 * @param isProduction - If true return status = PRODUCTION otherwise status = STAGING
 * @param id - return only this id and child params.
 * @param cb
 */
function getVehicleData(isProduction, id, cb) {
    async.waterfall(
        [
            app.locals.db.sqlCommand.bind(null, sql.getVehicleData(isProduction, id)),
            function(data, callback) {
                getNestedCustomVehicleData(data, false, callback);
            }
        ], function(err, response) {
            cb(err, response);
        }
    );
}

function getRpcSpec(next) {
    request(
        {
            method: 'GET',
            url: app.locals.config.rpcSpecXmlUrl
        },
        function(err, res, body) {
            next(err, body);
        }
    );
}

function extractRpcSpecVersion(data, next) {
    data.rpcSpec = {
        version: _.get(data.xml, 'interface.$.version', null),
        min_version: _.get(data.xml, 'interface.$.minVersion', null),
        date: _.get(data.xml, 'interface.$.date', null)
    };
    next(null, data);
}

function extractRpcSpecTypes(data, next) {
    let mapping = {
        'name': 'name',
        'since': 'since',
        'until': 'until',
        'deprecated': 'deprecated',
        'removed': 'removed',
        'internal_scope': 'internal_scope',
        'functionID': 'function_id',
        'messagetype': 'message_type'
    };

    let paramMapping = {
        'name': 'name',
        'type': 'type',
        'rootscreen': 'root_screen',
        'mandatory': 'mandatory',
        'since': 'since',
        'until': 'until',
        'deprecated': 'deprecated',
        'removed': 'removed',
        'value': 'value',
        'hexvalue': 'hex_value',
        'minlength': 'min_length',
        'maxlength': 'max_length',
        'minsize': 'min_size',
        'maxsize': 'max_size',
        'minvalue': 'min_value',
        'maxvalue': 'max_value',
        'array': 'array',
        'platform': 'platform',
        'defvalue': 'def_value',
    };

    let rpcSpecTypes = [];

    data.rpcSpecParams = [];

    const enumerations = _.get(data, 'xml.interface.enum');
    const structs = _.get(data, 'xml.interface.struct');
    const functions = _.get(data, 'xml.interface.function');

    if (!enumerations) {
        return next('enum not defined in the imported rpc spec');
    }
    if (!structs) {
        return next('struct not defined in the imported rpc spec');
    }
    if (!functions) {
        return next('function not defined in the imported rpc spec');
    }

    //extract enums
    for (let enumeration of enumerations) {
        let enumData = {
            element_type: 'ENUM',
        };

        const enumerationAttributes = _.get(enumeration, '$', {});

        if (!enumerationAttributes['name']) {
            return next('Enum must have a name defined.');
        }
        if (!enumeration['element']) {
            return next('Enum must have element defined.');
        }

        for (let key in mapping) {
            enumData[mapping[key]] = _.get(enumerationAttributes, key, null);
        }

        rpcSpecTypes.push(enumData);

        for (let element of enumeration.element) {
            let param = {
                rpc_spec_type_name: enumData.name
            };

            const elementAttributes = _.get(element, '$', {});

            if (!elementAttributes['name']) {
                return next('Element of enum must have a name defined.');
            }

            for (let key in paramMapping) {
                param[paramMapping[key]] = _.get(elementAttributes, key, null);
            }

            data.rpcSpecParams.push(param);

        }

    }

    //extract structs
    for (let struct of structs) {
        let structData = {
            element_type: 'STRUCT',
        };

        const attributes = _.get(struct, '$', {});

        if (!attributes['name']) {
            return next('Struct must have a name defined.');
        }

        for (let key in mapping) {
            structData[mapping[key]] = _.get(attributes, key, null);
        }

        rpcSpecTypes.push(structData);

        if (!struct['param']) {
            continue;
        }

        for (let element of struct.param) {
            let param = {
                rpc_spec_type_name: structData.name
            };

            const elementAttributes = _.get(element, '$', {});

            if (!elementAttributes['name']) {
                return next('Param of struct must have a name defined.');
            }

            for (let key in paramMapping) {
                param[paramMapping[key]] = _.get(elementAttributes, key, null);
            }

            data.rpcSpecParams.push(param);

        }
    }

    //extract functions
    for (let func of functions) {
        let funcData = {
            element_type: 'FUNCTION',
        };

        const attributes = _.get(func, '$', {});

        if (!attributes['name']) {
            return next('Struct must have a name defined.');
        }

        if (!func['param']) {
            continue;
        }

        for (let key in mapping) {
            funcData[mapping[key]] = _.get(attributes, key, null);
        }

        rpcSpecTypes.push(funcData);

        for (let element of func.param) {
            let name = funcData.name;
            if (funcData.message_type) {
                name = `${name}.${funcData.message_type}`;
            }
            let param = {
                rpc_spec_type_name: name
            };

            const elementAttributes = _.get(element, '$', {});

            if (!elementAttributes['name']) {
                return next('Param of func must have a name defined.');
            }

            for (let key in paramMapping) {
                param[paramMapping[key]] = _.get(elementAttributes, key, null);
            }

            data.rpcSpecParams.push(param);

        }

    }

    data.rpcSpecTypes = rpcSpecTypes;

    next(null, data);
}

function updateRpcSpec(next = function() {
}) {

    app.locals.db.runAsTransaction(function(client, callback) {
        async.waterfall(
            [
                getRpcSpec,
                function(rpcString, callback) {
                    parseXml(rpcString, function(err, xml) {
                        callback(err, { xml: xml });
                    });
                },
                extractRpcSpecVersion,
                //check rpc version exists exit if already exists.
                function(data, callback) {
                    let rpcSpec = data.rpcSpec;
                    client.getOne(sql.getLatestRpcSpec(), function(err, result) {
                        if (result && result.version) {
                            if (rpcSpec.version === result.version) {
                                return callback({ skipReason: 'Rpc spec no update required' });
                            }
                        }
                        callback(err, data);
                    });
                },
                function(data, callback) {
                    let rpcSpec = data.rpcSpec;
                    client.getOne(sql.insertRpcSpec(rpcSpec), function(err, result) {
                        data.rpcSpecInsert = result;
                        callback(err, data);
                    });
                },
                extractRpcSpecTypes,
                function(data, callback) {
                    client.getMany(sql.insertRpcSpecType(data.rpcSpecInsert.id, data.rpcSpecTypes), function(err, result) {

                        data.rpcSpecTypesByName = {};

                        for (let rpcSpecType of result) {
                            let name = rpcSpecType.name;
                            if (rpcSpecType.message_type) {
                                name = `${name}.${rpcSpecType.message_type}`;
                            }
                            data.rpcSpecTypesByName[name] = rpcSpecType;
                        }
                        callback(err, data);
                    });
                },
                function(data, callback) {
                    client.getOne(sql.insertRpcSpecParam(data.rpcSpecParams, data.rpcSpecTypesByName), function(err, result) {
                        callback(err, data);
                    });
                }
            ], callback);
    }, function(err, response) {

        if (err) {
            if (err.skipReason) {
                //warning only, spec already imported etc.
                app.locals.log.info(err.skipReason);
            } else {
                app.locals.log.error(err);
            }
        } else {

            app.locals.log.info('Rpc spec updated');
        }
        next();
    });

}

function getTemplate(cb) {
    return cb(
        null,
        {
            'id': null,
            'parent_id': null,
            'status': 'STAGING',
            'name': null,
            'type': null,
            'key': null,
            'mandatory': false,
            'min_length': null,
            'max_length': null,
            'min_size': null,
            'max_size': null,
            'min_value': null,
            'max_value': null,
            'array': false,
            'is_deleted': false
        }
    );
}

function getValidTypes(cb) {

    //primitive types and struct
    let types = [
        {
            name: "Float",
            allow_params: false,
        },
        {
            name: "String",
            allow_params: false,
        },
        {
            name: "Boolean",
            allow_params: false,
        },
        {
            name: "Integer",
            allow_params: false,
        },
        {
            name: "Struct",
            allow_params: true,
        }
    ];

    app.locals.db.sqlCommand(sql.getEnums(), function(err, enums) {
        if (err) {
            return cb(err);
        }
        for (let item of enums) {
            types.push(
                {
                    name: item.name,
                    allow_params: false
                }
            );
        }

        return cb(null,types)
    });
}

module.exports = {
    getTemplate: getTemplate,
    insertCustomVehicleDataItem: insertCustomVehicleDataItem,
    getNestedCustomVehicleData: getNestedCustomVehicleData,
    validatePost: validatePost,
    promote: promote,
    getVehicleData: getVehicleData,
    getValidTypes: getValidTypes,
    updateRpcSpec: updateRpcSpec,
};
<commit_msg>added params[] to vehicle data template<commit_after>//Copyright (c) 2019, Livio, Inc.
const app = require('../app');
const sql = require('./sql.js');
const parseXml = require('xml2js').parseString;
const request = require('request');
const async = require('async');
const _ = require('lodash');

function validatePost(req, res) {
    return;
}

function promoteCustomVehicleData(client, obj, parentIdMapping = {}) {
    return function(cb) {
        let originalParentId = obj.parent_id;
        if (obj.parent_id) {
            let parent_id = parentIdMapping[obj.parent_id];
            if (!parent_id) {
                return cb(`Orphaned record`);
            }
            obj.parent_id = parent_id;
            //assign parent_id based on parentIdMapping.
        }

        async.waterfall(
            [
                function(callback) {
                    //skip update if status is on production and not a child that has had its parentId changed.
                    if (obj.status === 'PRODUCTION' && !(obj.parent_id && obj.parent_id != originalParentId)) {
                        parentIdMapping[obj.id] = obj.id;
                        return callback(null);
                    }
                    client.getOne(sql.insertProductionCustomVehicleData(obj), function(err, result) {
                        if (!err && result) {
                            parentIdMapping[obj.id] = result.id;
                        }
                        callback(err, result);
                    });
                }
            ], function(err) {
                if (err) {
                    return cb(err);
                }

                //update children.
                if (obj.params && obj.params.length > 0) {
                    let functions = [];
                    for (let param of obj.params) {
                        functions.push(promoteCustomVehicleData(client, param, parentIdMapping));
                    }
                    return async.waterfall(functions, function(err) {
                        cb(err);
                    });
                } else {
                    cb(err);
                }

            }
        );
    };
}

/**
 * Promotes all custom_vehicle_data records in STAGING if they are the
 * most recent. This means creating new PRODUCTION records and making sure
 * any parent_id relationships remain unchanged.
 *
 * Promoting a parent will cause all new PRODUCTION child records to be created.
 *
 * If the child record is in STAGING a new PRODUCTION record will be created using staging and the parent_id.
 *
 * This will be done as a single transaction with top level records being created first.
 *
 * @param cb
 */
function promote(cb) {
    app.locals.db.runAsTransaction(function(client, callback) {
        async.waterfall(
            [
                function(callback) {
                    app.locals.db.sqlCommand(sql.getVehicleData(false), function(err, res) {
                        callback(null, res);
                    });
                },
                //create nested data.
                function(data, callback) {
                    let vehicleDataById = {};
                    for (let customVehicleDataItem of data) {
                        vehicleDataById[customVehicleDataItem.id] = customVehicleDataItem;
                        customVehicleDataItem.params = [];
                    }

                    let result = [];
                    for (let customVehicleDataItem of data) {
                        if (customVehicleDataItem.parent_id) {
                            //old record not included.
                            if (!vehicleDataById[customVehicleDataItem.parent_id]) {
                                continue;
                            } else {
                                vehicleDataById[customVehicleDataItem.parent_id].params.push(customVehicleDataItem);
                            }
                        } else {
                            result.push(customVehicleDataItem);
                        }
                    }
                    callback(null, result);
                },
                //insert data
                function(data, callback) {
                    let functions = [];
                    for (let customVehicleDataItem of data) {
                        functions.push(promoteCustomVehicleData(client, customVehicleDataItem));
                    }
                    async.waterfall(functions, callback);
                }
            ], callback
        );
    }, cb);

}

function insertCustomVehicleDataItem(client, data, cb) {
    let newParentId;
    let oldParentId = data.id;
    let insertResult;

    async.waterfall(
        [
            function(callback) {
                client.getOne(sql.insertStagingCustomVehicleData(data), function(err, res) {
                    if (err) {
                        return cb(err, res);
                    }
                    if (oldParentId) {
                        newParentId = res.id;
                    }
                    insertResult = res;
                    callback(err, res);
                });
            },
            function(res, callback) { //insert new children
                if (!oldParentId) //new record no children.
                {
                    return callback(null, res);
                }
                newParentId = res.id;

                client.getMany(sql.getDirectChildren(oldParentId), function(err, res) {
                    if (err) {
                        return callback(err);
                    }

                    let functions = [];
                    for (let child of res) {
                        child.parent_id = newParentId;
                        child.status = 'STAGING';
                        functions.push(function(cb) {
                            insertCustomVehicleDataItem(client, child, cb);
                        });
                    }
                    async.parallel(functions, function(err) {
                        if (err) {
                            return callback(err);
                        }
                        return callback(err);
                    });
                });
            },
        ], cb
    );

}

function getCustomVehicleDataItem(customVehicleDataItem, isForPolicyTable) {
    return isForPolicyTable ? {
        name: customVehicleDataItem.name,
        type: customVehicleDataItem.type,
        key: customVehicleDataItem.key,
        mandatory: customVehicleDataItem.mandatory,
        minlength: customVehicleDataItem.min_length,
        maxlength: customVehicleDataItem.max_length,
        minsize: customVehicleDataItem.min_size,
        maxsize: customVehicleDataItem.max_size,
        maxvalue: customVehicleDataItem.max_value,
        array: customVehicleDataItem.array,
    } : customVehicleDataItem;
}

/**
 *
 * @param customVehicleDataItems
 * @param isForPolicyTable
 * @param cb
 */
function getNestedCustomVehicleData(customVehicleDataItems, isForPolicyTable, cb) {
    let vehicleDataById = {};
    for (let customVehicleDataItem of customVehicleDataItems) {
        vehicleDataById[customVehicleDataItem.id] = customVehicleDataItem;
        customVehicleDataItem.params = [];
    }

    let result = [];
    for (let customVehicleDataItem of customVehicleDataItems) {
        if (customVehicleDataItem.parent_id) {
            //if we are filtering by id the parent will not be included.
            if (vehicleDataById[customVehicleDataItem.parent_id]) {
                vehicleDataById[customVehicleDataItem.parent_id].params.push(getCustomVehicleDataItem(customVehicleDataItem, isForPolicyTable));
            } else { //if no parent_id matches, assume this is a top level item.
                result.push(getCustomVehicleDataItem(customVehicleDataItem, isForPolicyTable));
            }
        } else {
            result.push(getCustomVehicleDataItem(customVehicleDataItem, isForPolicyTable));
        }
    }
    cb(null, result);
}

/**
 * Returns a list of custom vehicle data items filtered by status and optionally by id.
 * @param isProduction - If true return status = PRODUCTION otherwise status = STAGING
 * @param id - return only this id and child params.
 * @param cb
 */
function getVehicleData(isProduction, id, cb) {
    async.waterfall(
        [
            app.locals.db.sqlCommand.bind(null, sql.getVehicleData(isProduction, id)),
            function(data, callback) {
                getNestedCustomVehicleData(data, false, callback);
            }
        ], function(err, response) {
            cb(err, response);
        }
    );
}

function getRpcSpec(next) {
    request(
        {
            method: 'GET',
            url: app.locals.config.rpcSpecXmlUrl
        },
        function(err, res, body) {
            next(err, body);
        }
    );
}

function extractRpcSpecVersion(data, next) {
    data.rpcSpec = {
        version: _.get(data.xml, 'interface.$.version', null),
        min_version: _.get(data.xml, 'interface.$.minVersion', null),
        date: _.get(data.xml, 'interface.$.date', null)
    };
    next(null, data);
}

function extractRpcSpecTypes(data, next) {
    let mapping = {
        'name': 'name',
        'since': 'since',
        'until': 'until',
        'deprecated': 'deprecated',
        'removed': 'removed',
        'internal_scope': 'internal_scope',
        'functionID': 'function_id',
        'messagetype': 'message_type'
    };

    let paramMapping = {
        'name': 'name',
        'type': 'type',
        'rootscreen': 'root_screen',
        'mandatory': 'mandatory',
        'since': 'since',
        'until': 'until',
        'deprecated': 'deprecated',
        'removed': 'removed',
        'value': 'value',
        'hexvalue': 'hex_value',
        'minlength': 'min_length',
        'maxlength': 'max_length',
        'minsize': 'min_size',
        'maxsize': 'max_size',
        'minvalue': 'min_value',
        'maxvalue': 'max_value',
        'array': 'array',
        'platform': 'platform',
        'defvalue': 'def_value',
    };

    let rpcSpecTypes = [];

    data.rpcSpecParams = [];

    const enumerations = _.get(data, 'xml.interface.enum');
    const structs = _.get(data, 'xml.interface.struct');
    const functions = _.get(data, 'xml.interface.function');

    if (!enumerations) {
        return next('enum not defined in the imported rpc spec');
    }
    if (!structs) {
        return next('struct not defined in the imported rpc spec');
    }
    if (!functions) {
        return next('function not defined in the imported rpc spec');
    }

    //extract enums
    for (let enumeration of enumerations) {
        let enumData = {
            element_type: 'ENUM',
        };

        const enumerationAttributes = _.get(enumeration, '$', {});

        if (!enumerationAttributes['name']) {
            return next('Enum must have a name defined.');
        }
        if (!enumeration['element']) {
            return next('Enum must have element defined.');
        }

        for (let key in mapping) {
            enumData[mapping[key]] = _.get(enumerationAttributes, key, null);
        }

        rpcSpecTypes.push(enumData);

        for (let element of enumeration.element) {
            let param = {
                rpc_spec_type_name: enumData.name
            };

            const elementAttributes = _.get(element, '$', {});

            if (!elementAttributes['name']) {
                return next('Element of enum must have a name defined.');
            }

            for (let key in paramMapping) {
                param[paramMapping[key]] = _.get(elementAttributes, key, null);
            }

            data.rpcSpecParams.push(param);

        }

    }

    //extract structs
    for (let struct of structs) {
        let structData = {
            element_type: 'STRUCT',
        };

        const attributes = _.get(struct, '$', {});

        if (!attributes['name']) {
            return next('Struct must have a name defined.');
        }

        for (let key in mapping) {
            structData[mapping[key]] = _.get(attributes, key, null);
        }

        rpcSpecTypes.push(structData);

        if (!struct['param']) {
            continue;
        }

        for (let element of struct.param) {
            let param = {
                rpc_spec_type_name: structData.name
            };

            const elementAttributes = _.get(element, '$', {});

            if (!elementAttributes['name']) {
                return next('Param of struct must have a name defined.');
            }

            for (let key in paramMapping) {
                param[paramMapping[key]] = _.get(elementAttributes, key, null);
            }

            data.rpcSpecParams.push(param);

        }
    }

    //extract functions
    for (let func of functions) {
        let funcData = {
            element_type: 'FUNCTION',
        };

        const attributes = _.get(func, '$', {});

        if (!attributes['name']) {
            return next('Struct must have a name defined.');
        }

        if (!func['param']) {
            continue;
        }

        for (let key in mapping) {
            funcData[mapping[key]] = _.get(attributes, key, null);
        }

        rpcSpecTypes.push(funcData);

        for (let element of func.param) {
            let name = funcData.name;
            if (funcData.message_type) {
                name = `${name}.${funcData.message_type}`;
            }
            let param = {
                rpc_spec_type_name: name
            };

            const elementAttributes = _.get(element, '$', {});

            if (!elementAttributes['name']) {
                return next('Param of func must have a name defined.');
            }

            for (let key in paramMapping) {
                param[paramMapping[key]] = _.get(elementAttributes, key, null);
            }

            data.rpcSpecParams.push(param);

        }

    }

    data.rpcSpecTypes = rpcSpecTypes;

    next(null, data);
}

function updateRpcSpec(next = function() {
}) {

    app.locals.db.runAsTransaction(function(client, callback) {
        async.waterfall(
            [
                getRpcSpec,
                function(rpcString, callback) {
                    parseXml(rpcString, function(err, xml) {
                        callback(err, { xml: xml });
                    });
                },
                extractRpcSpecVersion,
                //check rpc version exists exit if already exists.
                function(data, callback) {
                    let rpcSpec = data.rpcSpec;
                    client.getOne(sql.getLatestRpcSpec(), function(err, result) {
                        if (result && result.version) {
                            if (rpcSpec.version === result.version) {
                                return callback({ skipReason: 'Rpc spec no update required' });
                            }
                        }
                        callback(err, data);
                    });
                },
                function(data, callback) {
                    let rpcSpec = data.rpcSpec;
                    client.getOne(sql.insertRpcSpec(rpcSpec), function(err, result) {
                        data.rpcSpecInsert = result;
                        callback(err, data);
                    });
                },
                extractRpcSpecTypes,
                function(data, callback) {
                    client.getMany(sql.insertRpcSpecType(data.rpcSpecInsert.id, data.rpcSpecTypes), function(err, result) {

                        data.rpcSpecTypesByName = {};

                        for (let rpcSpecType of result) {
                            let name = rpcSpecType.name;
                            if (rpcSpecType.message_type) {
                                name = `${name}.${rpcSpecType.message_type}`;
                            }
                            data.rpcSpecTypesByName[name] = rpcSpecType;
                        }
                        callback(err, data);
                    });
                },
                function(data, callback) {
                    client.getOne(sql.insertRpcSpecParam(data.rpcSpecParams, data.rpcSpecTypesByName), function(err, result) {
                        callback(err, data);
                    });
                }
            ], callback);
    }, function(err, response) {

        if (err) {
            if (err.skipReason) {
                //warning only, spec already imported etc.
                app.locals.log.info(err.skipReason);
            } else {
                app.locals.log.error(err);
            }
        } else {

            app.locals.log.info('Rpc spec updated');
        }
        next();
    });

}

function getTemplate(cb) {
    return cb(
        null,
        {
            'id': null,
            'parent_id': null,
            'status': 'STAGING',
            'name': null,
            'type': null,
            'key': null,
            'mandatory': false,
            'min_length': null,
            'max_length': null,
            'min_size': null,
            'max_size': null,
            'min_value': null,
            'max_value': null,
            'array': false,
            'params': [],
            'is_deleted': false
        }
    );
}

function getValidTypes(cb) {

    //primitive types and struct
    let types = [
        {
            name: "Float",
            allow_params: false,
        },
        {
            name: "String",
            allow_params: false,
        },
        {
            name: "Boolean",
            allow_params: false,
        },
        {
            name: "Integer",
            allow_params: false,
        },
        {
            name: "Struct",
            allow_params: true,
        }
    ];

    app.locals.db.sqlCommand(sql.getEnums(), function(err, enums) {
        if (err) {
            return cb(err);
        }
        for (let item of enums) {
            types.push(
                {
                    name: item.name,
                    allow_params: false
                }
            );
        }

        return cb(null,types)
    });
}

module.exports = {
    getTemplate: getTemplate,
    insertCustomVehicleDataItem: insertCustomVehicleDataItem,
    getNestedCustomVehicleData: getNestedCustomVehicleData,
    validatePost: validatePost,
    promote: promote,
    getVehicleData: getVehicleData,
    getValidTypes: getValidTypes,
    updateRpcSpec: updateRpcSpec,
};
<|endoftext|>