<commit_before>'use strict';

var expect = require('chai').expect;
var Promise = require('bluebird');
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var entity = require('@back4app/back4app-entity');
var classes = entity.utils.classes;
var Entity = entity.models.Entity;
var Attribute = entity.models.attributes.Attribute;
var Adapter = entity.adapters.Adapter;

module.exports = MongoAdapter;

/**
 * MongoDB adapter for back{4}app's entities.
 * @constructor
 * @memberof module:back4app-entity-mongodb
 * @extends {module:back4app-entity/adapters.Adapter}
 * @param {!string} connectionUrl The connection url for MongoDB as specified in
 * {@link
 * https://mongodb.github.io/node-mongodb-native/api-generated/mongoclient.html
 * }.
 * @param {?Object} [connectionOptions] The optional connection parameter for
 * MongoDB as specified in
 * {@link
 * https://mongodb.github.io/node-mongodb-native/api-generated/mongoclient.html
 * }.
 * @example
 * require('back4app-entity').settings.ADAPTERS = {
 *   default: new MongoAdapter('127.0.0.1', '51764')
 * };
 */
function MongoAdapter(connectionUrl, connectionOptions) {
  Adapter.call(this);

  var _database = null;
  var _databaseIsLocked = false;
  var _databaseRequestQueue = [];

  this.getDatabase = getDatabase;
  this.openConnection = openConnection;
  this.closeConnection = closeConnection;

  expect(arguments).to.have.length.within(
    1,
    2,
    'Invalid arguments length when creating a new MongoAdapter ' +
    '(it has to be passed from 1 to 2 arguments)'
  );

  expect(connectionUrl).to.be.a(
    'string',
    'Invalid argument "connectionUrl" when creating a new MongoAdapter  (it ' +
    'has to be a string)'
  );

  if (connectionOptions) {
    expect(connectionOptions).to.be.a(
      'object',
      'Invalid argument "connectionOptions" when creating a new MongoAdapter ' +
      '(it has to be an object)'
    );
  } else {
    connectionOptions = null;
  }

  function getDatabase() {
    var mongoAdapter = this;

    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when getting a database in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked || !_database) {
        mongoAdapter
          .openConnection()
          .then(function () {
            resolve(_database);
          })
          .catch(reject);
      } else {
        resolve(_database);
      }
    });
  }

  /**
   * Connects the adapter with the targeted Mongo database.
   * @name module:back4app-entity-mongodb.MongoAdapter#openConnection
   * @function
   * @returns {Promise.<undefined|Error>} Promise that returns nothing if
   * succeed and the Error if failed.
   * @example
   * mongoAdapter.openConnection()
   *   .then(function () {
 *     console.log('success');
 *   })
   *   .catch(function (error) {
 *     console.log(error);
 *   });
   */
  function openConnection() {
    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when opening a connection in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked) {
        _databaseRequestQueue.push(function () {
          openConnection().then(resolve).catch(reject);
        });
      } else if (_database) {
        resolve();
      } else {
        _databaseIsLocked = true;

        MongoClient
          .connect(connectionUrl, connectionOptions)
          .then(function (database) {
            _database = database;
            _databaseIsLocked = false;
            resolve();
            _processDatabaseRequestQueue();
          })
          .catch(function (error) {
            _databaseIsLocked = false;
            reject(error);
            _processDatabaseRequestQueue();
          });
      }
    });
  }

  /**
   * Closes the current adapter' connection with MongoDB.
   * @name module:back4app-entity-mongodb.MongoAdapter#closeConnection
   * @function
   * @returns {Promise.<undefined|Error>} Promise that returns nothing if
   * succeed and the Error if failed.
   * @example
   * mongoAdapter.closeConnection()
   *   .then(function (result) {
   *     console.log(result);
   *   })
   *   .catch(function (error) {
   *     console.log(error);
   *   });
   */
  function closeConnection() {
    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when closing a connection in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked) {
        _databaseRequestQueue.push(function () {
          closeConnection()
            .then(resolve)
            .catch(reject);
        });
      } else if (!_database) {
        resolve();
      } else {
        _databaseIsLocked = true;
        _database
          .close()
          .then(function () {
            _database = null;
            _databaseIsLocked = false;
            resolve();
            _processDatabaseRequestQueue();
          })
          .catch(function (error) {
            _databaseIsLocked = false;
            reject(error);
            _processDatabaseRequestQueue();
          });
      }
    });
  }

  function _processDatabaseRequestQueue() {
    while (_databaseRequestQueue.length > 0) {
      _databaseRequestQueue.splice(0,1)[0]();
    }
  }
}

classes.generalize(Adapter, MongoAdapter);

MongoAdapter.prototype.loadEntity = loadEntity;
MongoAdapter.prototype.loadEntityAttribute = loadEntityAttribute;
MongoAdapter.prototype.insertObject = insertObject;
MongoAdapter.prototype.objectToDocument = objectToDocument;

function loadEntity(Entity) {
  expect(arguments).to.have.length(
    1,
    'Invalid arguments length when loading an entity in a ' +
    'MongoAdapter (it has to be passed 1 argument)'
  );

  expect(classes.isGeneral(entity.models.Entity, Entity)).to.be.equal(
    true,
    'Invalid argument "Entity" when loading an entity in a ' +
    'MongoAdapter (it has to be an Entity class)'
  );

  expect(Entity.dataName).to.not.equal(
    '',
    'The dataName of an Entity cannot be an empty string in a MongoAdapter'
  );

  expect(Entity.dataName).to.not.match(
    /^system\./,
    'The dataName of an Entity cannot start with "system." in a MongoAdapter'
  );

  expect(Entity.dataName).to.not.contain(
    '$',
    'The dataName of an Entity cannot contain "$" in a MongoAdapter'
  );

  expect(Entity.dataName).to.not.contain(
    '\0',
    'The dataName of an Entity cannot contain "\0" in a MongoAdapter'
  );
}

function loadEntityAttribute(Entity, attribute) {
  expect(arguments).to.have.length(
    2,
    'Invalid arguments length when loading an entity attribute in a ' +
    'MongoAdapter (it has to be passed 2 arguments)'
  );

  expect(classes.isGeneral(entity.models.Entity, Entity)).to.be.equal(
    true,
    'Invalid argument "Entity" when loading an entity attribute in a ' +
    'MongoAdapter (it has to be an Entity class)'
  );

  expect(attribute).to.be.an.instanceOf(
    Attribute,
    'Invalid argument "attribute" when loading an entity attribute in a ' +
    'MongoAdapter (it has to be an Attribute instance)'
  );

  var dataName = attribute.getDataName(Entity.adapterName);

  expect(dataName).to.not.match(
    /^\$/,
    'The dataName of an Attribute cannot start with "$" in a MongoAdapter'
  );

  expect(dataName).to.not.contain(
    '.',
    'The dataName of an Attribute cannot contain "." in a MongoAdapter'
  );

  expect(dataName).to.not.contain(
    '\0',
    'The dataName of an Attribute cannot contain "\0" in a MongoAdapter'
  );

  expect(dataName).to.not.equal(
    'Entity',
    'The dataName of an Attribute cannot be equal to "Entity" in a MongoAdapter'
  );

  expect(dataName).to.not.equal(
    '_id',
    'The dataName of an Attribute cannot be equal to "_id" in a MongoAdapter'
  );
}

function insertObject(entityObject) {
  var mongoAdapter = this;

  expect(arguments).to.have.length(
    1,
    'Invalid arguments length when inserting an object in a MongoAdapter ' +
    '(it has to be passed 1 argument)'
  );

  return new Promise(function (resolve, reject) {
    expect(entityObject).to.be.an.instanceOf(
      Entity,
      'Invalid argument "entityObject" when inserting an object in a ' +
      'MongoAdapter (it has to be an Entity instance)'
    );

    var EntityClass = entityObject.Entity;

    var promises = [];

    while (EntityClass) {
      promises.push(_insertObject(EntityClass));
      EntityClass = EntityClass.General;
    }

    Promise.all(promises)
      .then(resolve)
      .catch(reject);

    function _insertObject(EntityClass) {
      return mongoAdapter
        .getDatabase()
        .then(function (database) {
          return database
            .collection(EntityClass.dataName)
            .insertOne(
              objectToDocument(
                entityObject,
                EntityClass
              )
            );
        })
        .then(function (result) {
          expect(result.insertedCount).to.equal(
            1,
            'Invalid result.insertedCount return of collection.insertOne ' +
            'in MongoDB driver when inserting an Object (it should be 1)'
          );
        });
    }
  });
}

function objectToDocument(entityObject, EntityClass) {
  var document = {};

  if (!EntityClass) {
    EntityClass = entityObject.Entity;
  }

  var entitySpecificationAttributes = EntityClass.specification.attributes;

  for (var attributeName in entitySpecificationAttributes) {
    var attribute = entitySpecificationAttributes[attributeName];
    var attributeDataName = attribute.getDataName(entityObject.adapterName);
    var attributeValue = attribute.getDataValue(entityObject[attributeName]);
    document[attributeDataName] = attributeValue;
  }

  document.Entity = entityObject.Entity.specification.name;

  document._id = entityObject.id;
  if (document.hasOwnProperty('id')) {
    delete document.id;
  }

  return document;
}
<commit_msg>Inserting foreign key<commit_after>'use strict';

var expect = require('chai').expect;
var Promise = require('bluebird');
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var entity = require('@back4app/back4app-entity');
var classes = entity.utils.classes;
var Adapter = entity.adapters.Adapter;
var Entity = entity.models.Entity;
var attributes = entity.models.attributes;
var Attribute = attributes.Attribute;
var AssociationAttribute = attributes.types.AssociationAttribute;

module.exports = MongoAdapter;

/**
 * MongoDB adapter for back{4}app's entities.
 * @constructor
 * @memberof module:back4app-entity-mongodb
 * @extends {module:back4app-entity/adapters.Adapter}
 * @param {!string} connectionUrl The connection url for MongoDB as specified in
 * {@link
 * https://mongodb.github.io/node-mongodb-native/api-generated/mongoclient.html
 * }.
 * @param {?Object} [connectionOptions] The optional connection parameter for
 * MongoDB as specified in
 * {@link
 * https://mongodb.github.io/node-mongodb-native/api-generated/mongoclient.html
 * }.
 * @example
 * require('back4app-entity').settings.ADAPTERS = {
 *   default: new MongoAdapter('127.0.0.1', '51764')
 * };
 */
function MongoAdapter(connectionUrl, connectionOptions) {
  Adapter.call(this);

  var _database = null;
  var _databaseIsLocked = false;
  var _databaseRequestQueue = [];

  this.getDatabase = getDatabase;
  this.openConnection = openConnection;
  this.closeConnection = closeConnection;

  expect(arguments).to.have.length.within(
    1,
    2,
    'Invalid arguments length when creating a new MongoAdapter ' +
    '(it has to be passed from 1 to 2 arguments)'
  );

  expect(connectionUrl).to.be.a(
    'string',
    'Invalid argument "connectionUrl" when creating a new MongoAdapter  (it ' +
    'has to be a string)'
  );

  if (connectionOptions) {
    expect(connectionOptions).to.be.a(
      'object',
      'Invalid argument "connectionOptions" when creating a new MongoAdapter ' +
      '(it has to be an object)'
    );
  } else {
    connectionOptions = null;
  }

  function getDatabase() {
    var mongoAdapter = this;

    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when getting a database in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked || !_database) {
        mongoAdapter
          .openConnection()
          .then(function () {
            resolve(_database);
          })
          .catch(reject);
      } else {
        resolve(_database);
      }
    });
  }

  /**
   * Connects the adapter with the targeted Mongo database.
   * @name module:back4app-entity-mongodb.MongoAdapter#openConnection
   * @function
   * @returns {Promise.<undefined|Error>} Promise that returns nothing if
   * succeed and the Error if failed.
   * @example
   * mongoAdapter.openConnection()
   *   .then(function () {
 *     console.log('success');
 *   })
   *   .catch(function (error) {
 *     console.log(error);
 *   });
   */
  function openConnection() {
    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when opening a connection in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked) {
        _databaseRequestQueue.push(function () {
          openConnection().then(resolve).catch(reject);
        });
      } else if (_database) {
        resolve();
      } else {
        _databaseIsLocked = true;

        MongoClient
          .connect(connectionUrl, connectionOptions)
          .then(function (database) {
            _database = database;
            _databaseIsLocked = false;
            resolve();
            _processDatabaseRequestQueue();
          })
          .catch(function (error) {
            _databaseIsLocked = false;
            reject(error);
            _processDatabaseRequestQueue();
          });
      }
    });
  }

  /**
   * Closes the current adapter' connection with MongoDB.
   * @name module:back4app-entity-mongodb.MongoAdapter#closeConnection
   * @function
   * @returns {Promise.<undefined|Error>} Promise that returns nothing if
   * succeed and the Error if failed.
   * @example
   * mongoAdapter.closeConnection()
   *   .then(function (result) {
   *     console.log(result);
   *   })
   *   .catch(function (error) {
   *     console.log(error);
   *   });
   */
  function closeConnection() {
    expect(arguments).to.have.length(
      0,
      'Invalid arguments length when closing a connection in a MongoAdapter ' +
      '(it has to be passed no arguments)'
    );

    return new Promise(function (resolve, reject) {
      if (_databaseIsLocked) {
        _databaseRequestQueue.push(function () {
          closeConnection()
            .then(resolve)
            .catch(reject);
        });
      } else if (!_database) {
        resolve();
      } else {
        _databaseIsLocked = true;
        _database
          .close()
          .then(function () {
            _database = null;
            _databaseIsLocked = false;
            resolve();
            _processDatabaseRequestQueue();
          })
          .catch(function (error) {
            _databaseIsLocked = false;
            reject(error);
            _processDatabaseRequestQueue();
          });
      }
    });
  }

  function _processDatabaseRequestQueue() {
    while (_databaseRequestQueue.length > 0) {
      _databaseRequestQueue.splice(0,1)[0]();
    }
  }
}

classes.generalize(Adapter, MongoAdapter);

MongoAdapter.prototype.loadEntity = loadEntity;
MongoAdapter.prototype.loadEntityAttribute = loadEntityAttribute;
MongoAdapter.prototype.insertObject = insertObject;
MongoAdapter.prototype.objectToDocument = objectToDocument;

function loadEntity(Entity) {
  expect(arguments).to.have.length(
    1,
    'Invalid arguments length when loading an entity in a ' +
    'MongoAdapter (it has to be passed 1 argument)'
  );

  expect(classes.isGeneral(entity.models.Entity, Entity)).to.be.equal(
    true,
    'Invalid argument "Entity" when loading an entity in a ' +
    'MongoAdapter (it has to be an Entity class)'
  );

  expect(Entity.dataName).to.not.equal(
    '',
    'The dataName of an Entity cannot be an empty string in a MongoAdapter'
  );

  expect(Entity.dataName).to.not.match(
    /^system\./,
    'The dataName of an Entity cannot start with "system." in a MongoAdapter'
  );

  expect(Entity.dataName).to.not.contain(
    '$',
    'The dataName of an Entity cannot contain "$" in a MongoAdapter'
  );

  expect(Entity.dataName).to.not.contain(
    '\0',
    'The dataName of an Entity cannot contain "\0" in a MongoAdapter'
  );
}

function loadEntityAttribute(Entity, attribute) {
  expect(arguments).to.have.length(
    2,
    'Invalid arguments length when loading an entity attribute in a ' +
    'MongoAdapter (it has to be passed 2 arguments)'
  );

  expect(classes.isGeneral(entity.models.Entity, Entity)).to.be.equal(
    true,
    'Invalid argument "Entity" when loading an entity attribute in a ' +
    'MongoAdapter (it has to be an Entity class)'
  );

  expect(attribute).to.be.an.instanceOf(
    Attribute,
    'Invalid argument "attribute" when loading an entity attribute in a ' +
    'MongoAdapter (it has to be an Attribute instance)'
  );

  var dataName = attribute.getDataName(Entity.adapterName);

  expect(dataName).to.not.match(
    /^\$/,
    'The dataName of an Attribute cannot start with "$" in a MongoAdapter'
  );

  expect(dataName).to.not.contain(
    '.',
    'The dataName of an Attribute cannot contain "." in a MongoAdapter'
  );

  expect(dataName).to.not.contain(
    '\0',
    'The dataName of an Attribute cannot contain "\0" in a MongoAdapter'
  );

  expect(dataName).to.not.equal(
    'Entity',
    'The dataName of an Attribute cannot be equal to "Entity" in a MongoAdapter'
  );

  expect(dataName).to.not.equal(
    '_id',
    'The dataName of an Attribute cannot be equal to "_id" in a MongoAdapter'
  );
}

function insertObject(entityObject) {
  var mongoAdapter = this;

  expect(arguments).to.have.length(
    1,
    'Invalid arguments length when inserting an object in a MongoAdapter ' +
    '(it has to be passed 1 argument)'
  );

  return new Promise(function (resolve, reject) {
    expect(entityObject).to.be.an.instanceOf(
      Entity,
      'Invalid argument "entityObject" when inserting an object in a ' +
      'MongoAdapter (it has to be an Entity instance)'
    );

    var EntityClass = entityObject.Entity;

    var promises = [];

    while (EntityClass) {
      promises.push(_insertObject(EntityClass));
      EntityClass = EntityClass.General;
    }

    Promise.all(promises)
      .then(resolve)
      .catch(reject);

    function _insertObject(EntityClass) {
      return mongoAdapter
        .getDatabase()
        .then(function (database) {
          return database
            .collection(EntityClass.dataName)
            .insertOne(
              objectToDocument(
                entityObject,
                EntityClass
              )
            );
        })
        .then(function (result) {
          expect(result.insertedCount).to.equal(
            1,
            'Invalid result.insertedCount return of collection.insertOne ' +
            'in MongoDB driver when inserting an Object (it should be 1)'
          );
        });
    }
  });
}

function objectToDocument(entityObject, EntityClass) {
  var document = {};

  if (!EntityClass) {
    EntityClass = entityObject.Entity;
  }

  var entitySpecificationAttributes = EntityClass.specification.attributes;

  for (var attributeName in entitySpecificationAttributes) {
    var attribute = entitySpecificationAttributes[attributeName];
    var attributeDataName = attribute.getDataName(entityObject.adapterName);
    var attributeValue = attribute.getDataValue(entityObject[attributeName]);

    if (attribute instanceof AssociationAttribute) {
      document[attributeDataName] = {
        $ref: attribute.Entity.dataName,
        $id: attributeValue.id
      };
    } else {
      document[attributeDataName] = attributeValue;
    }
  }

  document.Entity = entityObject.Entity.specification.name;

  document._id = entityObject.id;
  if (document.hasOwnProperty('id')) {
    delete document.id;
  }

  return document;
}
<|endoftext|>


<commit_before>import got from 'got';
import getSecret from '../services/secrets.js';
import { deleteUser, getUser, setUser } from '../services/user_cache.js';
import { getUser as getAppUser } from '../services/user_management.js';

export async function getToken(request, response) {
  const accessTokenName = 'authorization_code';
  const grantTypes = [accessTokenName, 'refresh_token'];
  if (request.body.client_id !== getSecret('client-id')) {
    return response.status(400).send('invalid client_id');
  } else if (!grantTypes.includes(request.body.grant_type)) {
    return response.status(400).json({
      error_description: `invalid grant_type: ${request.body.grant_type}, must be one of ${grantTypes.join(', ')}`,
      error: 'invalid_request',
    });
  }

  const passed_through_params =
    request.body.grant_type === accessTokenName
      ? ['client_id', 'code_verifier', 'code_challenge', 'redirect_uri', 'code']
      : ['client_id', 'refresh_token'];
  const body = { grant_type: request.body.grant_type };
  try {
    passed_through_params.forEach((name) => {
      const param = request.body[name];
      if (param) {
        body[name] = param;
      } else {
        const error = new Error(`${name} is required`);
        error.status = 400;

        throw error;
      }
    });
  } catch (error) {
    return response.status(400).json({ error_description: error.message, error: 'invalid_request' });
  }

  try {
    const tokenRequest = await got.post('https://login.dts.utah.gov:443/sso/oauth2/access_token', {
      form: body,
      responseType: 'json',
      headers: {
        authorization: request.headers.authorization,
        accept: request.headers.accept,
      },
    });

    return response.send(tokenRequest.body);
  } catch (error) {
    const errorMessage = error.body || error.message || error;

    return response.status(500).json({ error_description: errorMessage, error: 'server_error' });
  }
}

export async function logout(request, response) {
  const { token, isJWTToken } = getTokenFromHeader(request.headers.authorization);

  if (!token) {
    return response.status(401).send('empty token');
  }

  if (isJWTToken) {
    await deleteUser(token);
  }

  return response.status(200).send('user logged out successfully');
}

function getTokenFromHeader(authorization) {
  const [authProvider, authToken] = authorization.split(':');

  let token;
  let isJWTToken;
  if (authToken) {
    token = authToken.split(' ').pop();
    isJWTToken = authProvider === 'utahid';
  }

  return { token, isJWTToken, authProvider, authToken };
}

export async function authenticate(request, response, next) {
  if (request.headers.authorization) {
    const { token, isJWTToken, authProvider, authToken } = getTokenFromHeader(request.headers.authorization);

    if (!token) {
      return response.status(401).send('empty token');
    }

    response.locals.authProvider = authProvider;

    if (isJWTToken) {
      const cachedUser = await getUser(token);
      if (cachedUser) {
        response.locals.user = cachedUser;

        return next();
      }
    }

    let userResponse;
    const userInfos = {
      utahid: 'https://login.dts.utah.gov/sso/oauth2/userinfo',
      google: 'https://openidconnect.googleapis.com/v1/userinfo',
      facebook: `https://graph.facebook.com/me?access_token=${token}`,
    };

    try {
      userResponse = await got(userInfos[authProvider], {
        responseType: 'json',
        headers: {
          Authorization: authToken,
        },
        retry: 5,
        throwHttpErrors: false,
      });
    } catch (error) {
      const errorMessage = error.body || error.message || error;

      return response.status(500).json({ error_description: errorMessage, error: 'server_error' });
    }

    if (userResponse.statusCode === 200 && userResponse.body) {
      response.locals.user = userResponse.body;

      // facebook returns `id`, utahid and google return `sub`
      const authId = userResponse.body.sub || userResponse.body.id;
      response.locals.user.authId = authId;

      const appUser = await getAppUser(authId, authProvider);
      if (appUser) {
        response.locals.user.appUser = appUser;
      }

      // don't cache until we have the app user in the database
      if (isJWTToken && appUser) {
        setUser(token, {
          ...userResponse.body,
          appUser,
        });
      }

      return next();
    }

    return response.status(userResponse.statusCode).json(userResponse.body);
  }

  return response.status(400).send('authorization header is required');
}
<commit_msg>fix(back): fix got syntax for retries<commit_after>import got from 'got';
import getSecret from '../services/secrets.js';
import { deleteUser, getUser, setUser } from '../services/user_cache.js';
import { getUser as getAppUser } from '../services/user_management.js';

export async function getToken(request, response) {
  const accessTokenName = 'authorization_code';
  const grantTypes = [accessTokenName, 'refresh_token'];
  if (request.body.client_id !== getSecret('client-id')) {
    return response.status(400).send('invalid client_id');
  } else if (!grantTypes.includes(request.body.grant_type)) {
    return response.status(400).json({
      error_description: `invalid grant_type: ${request.body.grant_type}, must be one of ${grantTypes.join(', ')}`,
      error: 'invalid_request',
    });
  }

  const passed_through_params =
    request.body.grant_type === accessTokenName
      ? ['client_id', 'code_verifier', 'code_challenge', 'redirect_uri', 'code']
      : ['client_id', 'refresh_token'];
  const body = { grant_type: request.body.grant_type };
  try {
    passed_through_params.forEach((name) => {
      const param = request.body[name];
      if (param) {
        body[name] = param;
      } else {
        const error = new Error(`${name} is required`);
        error.status = 400;

        throw error;
      }
    });
  } catch (error) {
    return response.status(400).json({ error_description: error.message, error: 'invalid_request' });
  }

  try {
    const tokenRequest = await got.post('https://login.dts.utah.gov:443/sso/oauth2/access_token', {
      form: body,
      responseType: 'json',
      headers: {
        authorization: request.headers.authorization,
        accept: request.headers.accept,
      },
    });

    return response.send(tokenRequest.body);
  } catch (error) {
    const errorMessage = error.body || error.message || error;

    return response.status(500).json({ error_description: errorMessage, error: 'server_error' });
  }
}

export async function logout(request, response) {
  const { token, isJWTToken } = getTokenFromHeader(request.headers.authorization);

  if (!token) {
    return response.status(401).send('empty token');
  }

  if (isJWTToken) {
    await deleteUser(token);
  }

  return response.status(200).send('user logged out successfully');
}

function getTokenFromHeader(authorization) {
  const [authProvider, authToken] = authorization.split(':');

  let token;
  let isJWTToken;
  if (authToken) {
    token = authToken.split(' ').pop();
    isJWTToken = authProvider === 'utahid';
  }

  return { token, isJWTToken, authProvider, authToken };
}

export async function authenticate(request, response, next) {
  if (request.headers.authorization) {
    const { token, isJWTToken, authProvider, authToken } = getTokenFromHeader(request.headers.authorization);

    if (!token) {
      return response.status(401).send('empty token');
    }

    response.locals.authProvider = authProvider;

    if (isJWTToken) {
      const cachedUser = await getUser(token);
      if (cachedUser) {
        response.locals.user = cachedUser;

        return next();
      }
    }

    let userResponse;
    const userInfos = {
      utahid: 'https://login.dts.utah.gov/sso/oauth2/userinfo',
      google: 'https://openidconnect.googleapis.com/v1/userinfo',
      facebook: `https://graph.facebook.com/me?access_token=${token}`,
    };

    try {
      userResponse = await got(userInfos[authProvider], {
        responseType: 'json',
        headers: {
          Authorization: authToken,
        },
        retry: {
          limit: 5,
        },
        throwHttpErrors: false,
      });
    } catch (error) {
      const errorMessage = error.body || error.message || error;

      return response.status(500).json({ error_description: errorMessage, error: 'server_error' });
    }

    if (userResponse.statusCode === 200 && userResponse.body) {
      response.locals.user = userResponse.body;

      // facebook returns `id`, utahid and google return `sub`
      const authId = userResponse.body.sub || userResponse.body.id;
      response.locals.user.authId = authId;

      const appUser = await getAppUser(authId, authProvider);
      if (appUser) {
        response.locals.user.appUser = appUser;
      }

      // don't cache until we have the app user in the database
      if (isJWTToken && appUser) {
        setUser(token, {
          ...userResponse.body,
          appUser,
        });
      }

      return next();
    }

    return response.status(userResponse.statusCode).json(userResponse.body);
  }

  return response.status(400).send('authorization header is required');
}
<|endoftext|>


<commit_before>this.recline = this.recline || {};
this.recline.Backend = this.recline.Backend || {};
this.recline.Backend.DataProxy = this.recline.Backend.DataProxy || {};

(function($, my) {
  my.__type__ = 'dataproxy';
  // URL for the dataproxy
  my.dataproxy_url = 'http://jsonpdataproxy.appspot.com';
  // Timeout for dataproxy (after this time if no response we error)
  // Needed because use JSONP so do not receive e.g. 500 errors
  my.timeout = 5000;

  // ## load
  //
  // Load data from a URL via the [DataProxy](http://github.com/okfn/dataproxy).
  //
  // Returns array of field names and array of arrays for records
  my.fetch = function(dataset) {
    var data = {
      url: dataset.url,
      'max-results':  dataset.size || dataset.rows || 1000,
      type: dataset.format || ''
    };
    var jqxhr = $.ajax({
      url: my.dataproxy_url,
      data: data,
      dataType: 'jsonp'
    });
    var dfd = $.Deferred();
    _wrapInTimeout(jqxhr).done(function(results) {
      if (results.error) {
        dfd.reject(results.error);
      }

      dfd.resolve({
        records: results.data,
        fields: results.fields,
        useMemoryStore: true
      });
    })
    .fail(function(arguments) {
      dfd.reject(arguments);
    });
    return dfd.promise();
  };

  // ## _wrapInTimeout
  //
  // Convenience method providing a crude way to catch backend errors on JSONP calls.
  // Many of backends use JSONP and so will not get error messages and this is
  // a crude way to catch those errors.
  var _wrapInTimeout = function(ourFunction) {
    var dfd = $.Deferred();
    var timer = setTimeout(function() {
      dfd.reject({
        message: 'Request Error: Backend did not respond after ' + (my.timeout / 1000) + ' seconds'
      });
    }, my.timeout);
    ourFunction.done(function(arguments) {
        clearTimeout(timer);
        dfd.resolve(arguments);
      })
      .fail(function(arguments) {
        clearTimeout(timer);
        dfd.reject(arguments);
      })
      ;
    return dfd.promise();
  }

}(jQuery, this.recline.Backend.DataProxy));
<commit_msg>[#345] Use dataproxy url without http scheme to allow usage on ssl enabled pages.<commit_after>this.recline = this.recline || {};
this.recline.Backend = this.recline.Backend || {};
this.recline.Backend.DataProxy = this.recline.Backend.DataProxy || {};

(function($, my) {
  my.__type__ = 'dataproxy';
  // URL for the dataproxy
  my.dataproxy_url = '//jsonpdataproxy.appspot.com';
  // Timeout for dataproxy (after this time if no response we error)
  // Needed because use JSONP so do not receive e.g. 500 errors
  my.timeout = 5000;

  // ## load
  //
  // Load data from a URL via the [DataProxy](http://github.com/okfn/dataproxy).
  //
  // Returns array of field names and array of arrays for records
  my.fetch = function(dataset) {
    var data = {
      url: dataset.url,
      'max-results':  dataset.size || dataset.rows || 1000,
      type: dataset.format || ''
    };
    var jqxhr = $.ajax({
      url: my.dataproxy_url,
      data: data,
      dataType: 'jsonp'
    });
    var dfd = $.Deferred();
    _wrapInTimeout(jqxhr).done(function(results) {
      if (results.error) {
        dfd.reject(results.error);
      }

      dfd.resolve({
        records: results.data,
        fields: results.fields,
        useMemoryStore: true
      });
    })
    .fail(function(arguments) {
      dfd.reject(arguments);
    });
    return dfd.promise();
  };

  // ## _wrapInTimeout
  //
  // Convenience method providing a crude way to catch backend errors on JSONP calls.
  // Many of backends use JSONP and so will not get error messages and this is
  // a crude way to catch those errors.
  var _wrapInTimeout = function(ourFunction) {
    var dfd = $.Deferred();
    var timer = setTimeout(function() {
      dfd.reject({
        message: 'Request Error: Backend did not respond after ' + (my.timeout / 1000) + ' seconds'
      });
    }, my.timeout);
    ourFunction.done(function(arguments) {
        clearTimeout(timer);
        dfd.resolve(arguments);
      })
      .fail(function(arguments) {
        clearTimeout(timer);
        dfd.reject(arguments);
      })
      ;
    return dfd.promise();
  }

}(jQuery, this.recline.Backend.DataProxy));
<|endoftext|>


<commit_before>$(function () {
    $('[data-toggle="tooltip"]').tooltip();

    $('body')
        .on('click', '.upvote', function(e) {
            e.preventDefault();
            vote($(this), 1);
        }).on('click', '.downvote', function(e) {
        e.preventDefault();
        vote($(this), -1);
    });
});

function vote($voteLink, value) {
    if (typeof userId === 'undefined') {
        alert('You must log in to vote. To log in, click the "log in" link in the top-right corner.');
        return;
    }

    var emailId = $voteLink.data('email-id');
    if ($voteLink.hasClass('active')) {
        value = 0;
    }

    $.post('/votes/' + emailId, {
        userId: userId,
        value: value,
    })
    .done(function(data) {
        $voteLink.parent().find('.vote-action').removeClass('active');
        if (data.newValue === 1) {
            $voteLink.parent().find('.upvote').addClass('active');
        } else if (data.newValue === -1) {
            $voteLink.parent().find('.downvote').addClass('active');
        }
        $voteLink.parent().find('.vote-value').text(data.newTotal);
    })
    .fail(function() {
        alert('An error occurred');
    });
}
<commit_msg>Fix indentation<commit_after>$(function () {
    $('[data-toggle="tooltip"]').tooltip();

    $('body')
        .on('click', '.upvote', function(e) {
            e.preventDefault();
            vote($(this), 1);
        })
        .on('click', '.downvote', function(e) {
            e.preventDefault();
            vote($(this), -1);
        });
});

function vote($voteLink, value) {
    if (typeof userId === 'undefined') {
        alert('You must log in to vote. To log in, click the "log in" link in the top-right corner.');
        return;
    }

    var emailId = $voteLink.data('email-id');
    if ($voteLink.hasClass('active')) {
        value = 0;
    }

    $.post('/votes/' + emailId, {
        userId: userId,
        value: value,
    })
    .done(function(data) {
        $voteLink.parent().find('.vote-action').removeClass('active');
        if (data.newValue === 1) {
            $voteLink.parent().find('.upvote').addClass('active');
        } else if (data.newValue === -1) {
            $voteLink.parent().find('.downvote').addClass('active');
        }
        $voteLink.parent().find('.vote-value').text(data.newTotal);
    })
    .fail(function() {
        alert('An error occurred');
    });
}
<|endoftext|>


<commit_before>/*
 * Tangram
 * Copyright 2009 Baidu Inc. All rights reserved.
 */
///import baidu.i18n;
///import baidu.string.format;
/**
 * number
 * @name baidu.i18n.number
 * @Object
 * @grammar baidu.i18n.number
 */
baidu.i18n.number = baidu.i18n.number || /**@lends baidu.i18n.number.prototype*/{

    /**
     * 将传入的数字或者文字某种语言的格式进行格式化
     * @grammar baidu.i18n.number.format(number, sLocale, tLocale)
     * @param {String|Number} number 需要进行格式化的数字或者文字
     * @param {String} [sLocale] 可选参数，若传入的number格式为字符串，则该参数必须传入
     * @param {String} [tLocale] 目标语言
     * @return {String}
     */
    format: function(number, sLocale, tLocale){
        var me = this,
            sOpt = sLocale && baidu.i18n.cultures[sLocale].number,
            tOpt = baidu.i18n.cultures[tLocale || baidu.i18n.currentLocale].number,
            isNegative = false;

        if(typeof number === 'string'){

            if(number.indexOf(sOpt.negative) > -1){
                isNegative = true;
                number = number.replace(sOpt.negative, "");
            }else if(number.indexOf(sOpt.positive) > -1){
                number = number.replace(sOpt.positive, "");
            }
            number = number.replace(new RegExp(sOpt.group,'g'), "");
        }else{
            if(number < 0){
                isNegative = true;
                number *= -1;
            }
        }
        number = parseFloat(number);
        if(isNaN(number)){
            return 'NAN';
        }

        return tOpt._format ? tOpt._format(number, isNegative) : me._format(number, {
            group: tOpt.group || ',',
            decimal: tOpt.decimal || '.',
            groupLength: tOpt.groupLength,
            symbol: isNegative ? tOpt.negative : tOpt.positive
        });
    },

    /**
     * 格式化数字
     * @private
     * @param {Number} number 需要格式化的数字
     * @param {Object} options 格式化数字使用的参数
     * @return {String}
     */
    _format: function(number, options){
        var numberArray = String(number).split(options.decimal),
            preNum = numberArray[0].split('').reverse(),
            aftNum = numberArray[1] || '',
            len = 0,remainder = 0,
            result = '';

        len = parseInt(preNum.length / options.groupLength);
        remainder = preNum.length % options.groupLength;
        len = remainder == 0 ? len - 1 : len;

        for(var i = 1; i <= len; i++){
            preNum.splice(options.groupLength * i + (i - 1), 0, options.group);
        }
        preNum = preNum.reverse();
        result = options.symbol + preNum.join('') + (aftNum.length > 0 ? options.decimal + aftNum : '');

        return result;
    },

    /*
     * 根据给定的参数数值，返回对应的参数项
     * @grammar baidu.i18n.number.plural('#{num} 1_book', '#{num} 2_books', '#{num} 3_books', 100)
     * @param   参数项不定，但大于2
     * @return  {String }返回对应的参数项内容
     */
    plural: function() {
        if (arguments.length == 0) return;
        if (arguments.length == 1) return arguments[0];
        var num = arguments.pop();  // 最后一个参数是对应的数值
        if (parseInt(num) > arguments.length - 1) {
            return baidu.string.format(arguments.pop(), num);
        } else {
            return baidu.string.format(arguments[num-1], num);
        }
    }
};
<commit_msg>bugfix<commit_after>/*
 * Tangram
 * Copyright 2009 Baidu Inc. All rights reserved.
 */
///import baidu.i18n;
///import baidu.string.format;
/**
 * number
 * @name baidu.i18n.number
 * @Object
 * @grammar baidu.i18n.number
 */
baidu.i18n.number = baidu.i18n.number || /**@lends baidu.i18n.number.prototype*/{

    /**
     * 将传入的数字或者文字某种语言的格式进行格式化
     * @grammar baidu.i18n.number.format(number, sLocale, tLocale)
     * @param {String|Number} number 需要进行格式化的数字或者文字
     * @param {String} [sLocale] 可选参数，若传入的number格式为字符串，则该参数必须传入
     * @param {String} [tLocale] 目标语言
     * @return {String}
     */
    format: function(number, sLocale, tLocale){
        var me = this,
            sOpt = sLocale && baidu.i18n.cultures[sLocale].number,
            tOpt = baidu.i18n.cultures[tLocale || baidu.i18n.currentLocale].number,
            isNegative = false;

        if(typeof number === 'string'){

            if(number.indexOf(sOpt.negative) > -1){
                isNegative = true;
                number = number.replace(sOpt.negative, "");
            }else if(number.indexOf(sOpt.positive) > -1){
                number = number.replace(sOpt.positive, "");
            }
            number = number.replace(new RegExp(sOpt.group,'g'), "");
        }else{
            if(number < 0){
                isNegative = true;
                number *= -1;
            }
        }
        number = parseFloat(number);
        if(isNaN(number)){
            return 'NAN';
        }

        return tOpt._format ? tOpt._format(number, isNegative) : me._format(number, {
            group: tOpt.group || ',',
            decimal: tOpt.decimal || '.',
            groupLength: tOpt.groupLength,
            symbol: isNegative ? tOpt.negative : tOpt.positive
        });
    },

    /**
     * 格式化数字
     * @private
     * @param {Number} number 需要格式化的数字
     * @param {Object} options 格式化数字使用的参数
     * @return {String}
     */
    _format: function(number, options){
        var numberArray = String(number).split(options.decimal),
            preNum = numberArray[0].split('').reverse(),
            aftNum = numberArray[1] || '',
            len = 0,remainder = 0,
            result = '';

        len = parseInt(preNum.length / options.groupLength);
        remainder = preNum.length % options.groupLength;
        len = remainder == 0 ? len - 1 : len;

        for(var i = 1; i <= len; i++){
            preNum.splice(options.groupLength * i + (i - 1), 0, options.group);
        }
        preNum = preNum.reverse();
        result = options.symbol + preNum.join('') + (aftNum.length > 0 ? options.decimal + aftNum : '');

        return result;
    },

    /*
     * 根据给定的参数数值，返回对应的参数项
     * @grammar baidu.i18n.number.plural('#{num} 1_book', '#{num} 2_books', '#{num} 3_books', 100)
     * @param   参数项不定，但大于2
     * @return  {String }返回对应的参数项内容
     */
    plural: function() {
        var _arg = Array.prototype.slice.call(arguments);
        if (_arg.length == 0) return;
        if (_arg.length == 1) return _arg[0];
        var num = _arg.pop();  // 最后一个参数是对应的数值
        if (parseInt(num) > _arg.length - 1) {
            return baidu.string.format(_arg.pop(), num);
        } else {
            return baidu.string.format(_arg[num-1], num);
        }
    }
};
<|endoftext|>


<commit_before>/****************************************************************************
 Copyright (c) 2013-2014 Chukong Technologies Inc.

 http://www.cocos2d-x.org

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 ****************************************************************************/

(function(load, baseParser){

    var loadedPlist = {};

    var Parser = baseParser.extend({

        getNodeJson: function(json){
            return json["nodeTree"];
        },

        addSpriteFrame: function(plists, pngs, resourcePath){
            if(!plists || !pngs || plists.length != pngs.length)
                return;
            for (var i = 0; i < plists.length; i++) {
                var plist = resourcePath + plists[i];
                if(!cc.loader.getRes(plist) && !loadedPlist[plist])
                    cc.log("%s need to be preloaded", plist);
                else
                    loadedPlist[plist] = true;
                cc.spriteFrameCache.addSpriteFrames(
                    plist,
                    resourcePath + pngs[i]
                );
            }
        },

        pretreatment: function(json, resourcePath, file){
            this.addSpriteFrame(json["textures"], json["texturesPng"], resourcePath);
        }

    });
    var parser = new Parser();

    parser.generalAttributes = function(node, options){
        var width         = options["width"]        !=null ? options["width"] : 0;
        var height        = options["height"]       !=null ? options["height"] : 0;
        var x             = options["x"]            !=null ? options["x"] : 0;
        var y             = options["y"]            !=null ? options["y"] : 0;
        var scalex        = options["scaleX"]       !=null ? options["scaleX"] : 1;
        var scaley        = options["scaleY"]       !=null ? options["scaleY"] : 1;
        var rotation      = options["rotation"]     !=null ? options["rotation"] : 0;
        var rotationSkewX = options["rotationSkewX"]!=null ? options["rotationSkewX"] : 0;
        var rotationSkewY = options["rotationSkewY"]!=null ? options["rotationSkewY"] : 0;
        var skewx         = options["skewX"]        !=null ? options["skewX"] : 0;
        var skewy         = options["skewY"]        !=null ? options["skewY"] : 0;
        var anchorx       = options["anchorPointX"] !=null ? options["anchorPointX"] : 0.5;
        var anchory       = options["anchorPointY"] !=null ? options["anchorPointY"] : 0.5;
        var alpha         = options["opacity"]      !=null ? options["opacity"] : 255;
        var red           = options["colorR"]       !=null ? options["colorR"] : 255;
        var green         = options["colorG"]       !=null ? options["colorG"] : 255;
        var blue          = options["colorB"]       !=null ? options["colorB"] : 255;
        var zorder        = options["colorR"]       !=null ? options["colorR"] : 0;
        var tag           = options["tag"]          !=null ? options["tag"] : 0;
        var actionTag     = options["actionTag"]    !=null ? options["actionTag"] : 0;
        var visible       = options["visible"]      !=null ? options["visible"] : true;

        if(x != 0 || y != 0)
            node.setPosition(cc.p(x, y));
        if(scalex != 1)
            node.setScaleX(scalex);
        if(scaley != 1)
            node.setScaleY(scaley);
        if (rotation != 0)
            node.setRotation(rotation);
        if(rotationSkewX != 0)
            node.setRotationX(rotationSkewX);
        if(rotationSkewY != 0)
            node.setRotationY(rotationSkewY);
        if(skewx != 0)
            node.setSkewX(skewx);
        if(skewy != 0)
            node.setSkewY(skewy);
        if(anchorx != 0.5 || anchory != 0.5)
            node.setAnchorPoint(cc.p(anchorx, anchory));
        if(width != 0 || height != 0)
            node.setContentSize(cc.size(width, height));
        if(zorder != 0)
            node.setLocalZOrder(zorder);
        if(visible != true)
            node.setVisible(visible);

        if(alpha != 255)
        {
            node.setOpacity(alpha);
        }
        if(red != 255 || green != 255 || blue != 255)
        {
            node.setColor(cc.color(red, green, blue));
        }

        node.setTag(tag);
        node.setUserObject(new ccs.ActionTimelineData(actionTag));
    };

    parser.parseComponent = function(node, options){
        if(!options) return;
        for (var i = 0; i < options.length; ++i){
            var dic = options[i];
            var component = this.loadComponent(dic);
            if (component){
                node.addComponent(component);
            }
        }
    };

    parser.parseChild = function(parse, widget, options, resourcePath){
        var children = options["children"];
        for (var i = 0; i < children.length; i++) {
            var child = this.parseNode(children[i], resourcePath);
            if(child){
                if(widget instanceof ccui.PageView){
                    if(child instanceof ccui.Layout)
                        widget.addPage(child);
                } else {
                    if(widget instanceof ccui.ListView){
                        if(child instanceof ccui.Widget)
                            widget.pushBackCustomItem(child);
                    } else {
                        if(!(widget instanceof ccui.Layout) && child instanceof ccui.Widget) {
                            if(child.getPositionType() == ccui.Widget.POSITION_PERCENT) {
                                var position = child.getPositionPercent();
                                var anchor = widget.getAnchorPoint();
                                child.setPositionPercent(cc.p(position.x + anchor.x, position.y + anchor.y));
                            }
                            var AnchorPointIn = widget.getAnchorPointInPoints();
                            child.setPosition(cc.p(child.getPositionX() + AnchorPointIn.x, child.getPositionY() + AnchorPointIn.y));
                        }
                        widget.addChild(child);
                    }
                }
            }
        }
    };

    parser.initNode = function(options){
        var node = new cc.Node();
        this.generalAttributes(node, options);
        return node;
    };
    parser.initSubGraph = function(options){
        var filePath = options["fileName"];

        var node;
        if (filePath && "" != filePath){
            node = this.createNode(filePath);
        }else{
            node = new ccs.Node();
        }
        this.generalAttributes(node, options);
        return node;
    };
    parser.initSprite = function(options, resourcePath){
        var path = options["fileName"];
        var sprite;
        if(path != null){
            var spriteFrame = cc.spriteFrameCache.getSpriteFrame(path);
            if(!spriteFrame){
                path = resourcePath + path;
                sprite = new ccs.Sprite(path);
            }else{
                sprite = ccs.Sprite.createWithSpriteFrame(spriteFrame);
            }

            if(!sprite){
                sprite = new cc.Sprite();
                cc.log("filePath is empty. Create a sprite with no texture");
            }
        }else{
            sprite = new ccs.Sprite();
        }
        this.generalAttributes(sprite, options);
        var flipX = options["flipX"];
        var flipY = options["flipY"];

        if(flipX != false)
            sprite.setFlippedX(flipX);
        if(flipY != false)
            sprite.setFlippedY(flipY);
        return sprite;
    };
    parser.initParticle = function(options, resourcePath){
        var filePath = options["plistFile"];
        var num = options["tmxFile"];
        var particle = new cc.ParticleSystemQuad(filePath);
        particle.setTotalParticles(num);
        this.generalAttributes(particle, options);
        return particle;
    };
    parser.initTMXTiledMap = function(options, resourcePath){
        var tmxFile = options["tmxFile"];
        var tmxString = options["tmxString"];
        //todo check path and resourcePath
        var path = options["resourcePath"];

        var tmx = null;
        if (tmxFile && "" != tmxFile){
            tmx = new cc.TMXTiledMap(tmxFile);
        }else if (tmxString && "" != tmxString && path && "" != path){
            tmx = new cc.TMXTiledMap(tmxString, path);
        }
        return tmx;
    };
    var uiParser = load.getParser("ccui")["*"];
    parser.initWidget = function(options, resourcePath){
        var type = options["classname"];

        var parser = uiParser.parsers[type];
        if(!parser)
            return cc.log("%s parser is not found", type);

        var node = parser.call(uiParser, options, resourcePath);
        if(node){
            var rotationSkewX = options["rotationSkewX"];
            var rotationSkewY = options["rotationSkewY"];
            var skewx         = options["skewX"];
            var skewy         = options["skewY"];
            if(rotationSkewX != 0)
                node.setRotationX(rotationSkewX);
            if(rotationSkewY != 0)
                node.setRotationY(rotationSkewY);
            if(skewx != 0)
                node.setSkewX(skewx);
            if(skewy != 0)
                node.setSkewY(skewy);

            var actionTag = options["actionTag"];
            node.setUserObject(new ccs.ActionTimelineData(actionTag));
        }
        return node;
    };

    var register = [
        {name: "Node", handle: parser.initNode},
        {name: "SubGraph", handle: parser.initSubGraph},
        {name: "Sprite", handle: parser.initSprite},
        {name: "Particle", handle: parser.initParticle},
        {name: "TMXTiledMap", handle: parser.initTMXTiledMap},

        {name: "Widget", handle: parser.initWidget},
        {name: "Panel", handle: parser.initWidget},
        {name: "Button", handle: parser.initWidget},
        {name: "CheckBox", handle: parser.initWidget},
        {name: "ImageView", handle: parser.initWidget},
        {name: "LabelAtlas", handle: parser.initWidget},
        {name: "LabelBMFont", handle: parser.initWidget},
        {name: "Label", handle: parser.initWidget},
        {name: "ListView", handle: parser.initWidget},
        {name: "LoadingBar", handle: parser.initWidget},
        {name: "PageView", handle: parser.initWidget},
        {name: "ScrollView", handle: parser.initWidget},
        {name: "Slider", handle: parser.initWidget},
        {name: "TextField", handle: parser.initWidget}
    ];

    register.forEach(function(item){
        parser.registerParser(item.name, function(options, parse, resourcePath){
            var node = item.handle.call(this, options["options"]);
            this.parseComponent(node, options["components"]);
            this.parseChild(parse, node, options, resourcePath);
            return node;
        });
    });

    load.registerParser("timeline", "*", parser);

})(ccs._load, ccs._parser);
<commit_msg>Fixed ccui position error<commit_after>/****************************************************************************
 Copyright (c) 2013-2014 Chukong Technologies Inc.

 http://www.cocos2d-x.org

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 ****************************************************************************/

(function(load, baseParser){

    var loadedPlist = {};

    var Parser = baseParser.extend({

        getNodeJson: function(json){
            return json["nodeTree"];
        },

        addSpriteFrame: function(plists, pngs, resourcePath){
            if(!plists || !pngs || plists.length != pngs.length)
                return;
            for (var i = 0; i < plists.length; i++) {
                var plist = resourcePath + plists[i];
                if(!cc.loader.getRes(plist) && !loadedPlist[plist])
                    cc.log("%s need to be preloaded", plist);
                else
                    loadedPlist[plist] = true;
                cc.spriteFrameCache.addSpriteFrames(
                    plist,
                    resourcePath + pngs[i]
                );
            }
        },

        pretreatment: function(json, resourcePath, file){
            this.addSpriteFrame(json["textures"], json["texturesPng"], resourcePath);
        }

    });
    var parser = new Parser();

    parser.generalAttributes = function(node, options){
        var width         = options["width"]        !=null ? options["width"] : 0;
        var height        = options["height"]       !=null ? options["height"] : 0;
        var x             = options["x"]            !=null ? options["x"] : 0;
        var y             = options["y"]            !=null ? options["y"] : 0;
        var scalex        = options["scaleX"]       !=null ? options["scaleX"] : 1;
        var scaley        = options["scaleY"]       !=null ? options["scaleY"] : 1;
        var rotation      = options["rotation"]     !=null ? options["rotation"] : 0;
        var rotationSkewX = options["rotationSkewX"]!=null ? options["rotationSkewX"] : 0;
        var rotationSkewY = options["rotationSkewY"]!=null ? options["rotationSkewY"] : 0;
        var skewx         = options["skewX"]        !=null ? options["skewX"] : 0;
        var skewy         = options["skewY"]        !=null ? options["skewY"] : 0;
        var anchorx       = options["anchorPointX"] !=null ? options["anchorPointX"] : 0.5;
        var anchory       = options["anchorPointY"] !=null ? options["anchorPointY"] : 0.5;
        var alpha         = options["opacity"]      !=null ? options["opacity"] : 255;
        var red           = options["colorR"]       !=null ? options["colorR"] : 255;
        var green         = options["colorG"]       !=null ? options["colorG"] : 255;
        var blue          = options["colorB"]       !=null ? options["colorB"] : 255;
        var zorder        = options["colorR"]       !=null ? options["colorR"] : 0;
        var tag           = options["tag"]          !=null ? options["tag"] : 0;
        var actionTag     = options["actionTag"]    !=null ? options["actionTag"] : 0;
        var visible       = options["visible"]      !=null ? options["visible"] : true;

        if(x != 0 || y != 0)
            node.setPosition(cc.p(x, y));
        if(scalex != 1)
            node.setScaleX(scalex);
        if(scaley != 1)
            node.setScaleY(scaley);
        if (rotation != 0)
            node.setRotation(rotation);
        if(rotationSkewX != 0)
            node.setRotationX(rotationSkewX);
        if(rotationSkewY != 0)
            node.setRotationY(rotationSkewY);
        if(skewx != 0)
            node.setSkewX(skewx);
        if(skewy != 0)
            node.setSkewY(skewy);
        if(anchorx != 0.5 || anchory != 0.5)
            node.setAnchorPoint(cc.p(anchorx, anchory));
        if(width != 0 || height != 0)
            node.setContentSize(cc.size(width, height));
        if(zorder != 0)
            node.setLocalZOrder(zorder);
        if(visible != true)
            node.setVisible(visible);

        if(alpha != 255)
        {
            node.setOpacity(alpha);
        }
        if(red != 255 || green != 255 || blue != 255)
        {
            node.setColor(cc.color(red, green, blue));
        }

        node.setTag(tag);
        node.setUserObject(new ccs.ActionTimelineData(actionTag));
    };

    parser.parseComponent = function(node, options){
        if(!options) return;
        for (var i = 0; i < options.length; ++i){
            var dic = options[i];
            var component = this.loadComponent(dic);
            if (component){
                node.addComponent(component);
            }
        }
    };

    parser.parseChild = function(parse, widget, options, resourcePath){
        var children = options["children"];
        for (var i = 0; i < children.length; i++) {
            var child = this.parseNode(children[i], resourcePath);
            if(child){
                if(widget instanceof ccui.PageView){
                    if(child instanceof ccui.Layout)
                        widget.addPage(child);
                } else {
                    if(widget instanceof ccui.ListView){
                        if(child instanceof ccui.Widget)
                            widget.pushBackCustomItem(child);
                    } else {
                        if(!(widget instanceof ccui.Layout) && child instanceof ccui.Widget) {
                            if(child.getPositionType() == ccui.Widget.POSITION_PERCENT) {
                                var position = child.getPositionPercent();
                                var anchor = widget.getAnchorPoint();
                                child.setPositionPercent(cc.p(position.x + anchor.x, position.y + anchor.y));
                            }
                            //To make up for the studio positioning error problem
                            var AnchorPointIn = widget.getAnchorPointInPoints();
                            child.setPosition(cc.p(child.getPositionX() + AnchorPointIn.x, child.getPositionY() + AnchorPointIn.y));
                        }
                        widget.addChild(child);
                    }
                }
            }
        }
    };

    parser.initNode = function(options){
        var node = new cc.Node();
        this.generalAttributes(node, options);
        return node;
    };
    parser.initSubGraph = function(options){
        var filePath = options["fileName"];

        var node;
        if (filePath && "" != filePath){
            node = this.createNode(filePath);
        }else{
            node = new ccs.Node();
        }
        this.generalAttributes(node, options);
        return node;
    };
    parser.initSprite = function(options, resourcePath){
        var path = options["fileName"];
        var sprite;
        if(path != null){
            var spriteFrame = cc.spriteFrameCache.getSpriteFrame(path);
            if(!spriteFrame){
                path = resourcePath + path;
                sprite = new ccs.Sprite(path);
            }else{
                sprite = ccs.Sprite.createWithSpriteFrame(spriteFrame);
            }

            if(!sprite){
                sprite = new cc.Sprite();
                cc.log("filePath is empty. Create a sprite with no texture");
            }
        }else{
            sprite = new ccs.Sprite();
        }
        this.generalAttributes(sprite, options);
        var flipX = options["flipX"];
        var flipY = options["flipY"];

        if(flipX != false)
            sprite.setFlippedX(flipX);
        if(flipY != false)
            sprite.setFlippedY(flipY);
        return sprite;
    };
    parser.initParticle = function(options, resourcePath){
        var filePath = options["plistFile"];
        var num = options["tmxFile"];
        var particle = new cc.ParticleSystemQuad(filePath);
        particle.setTotalParticles(num);
        this.generalAttributes(particle, options);
        return particle;
    };
    parser.initTMXTiledMap = function(options, resourcePath){
        var tmxFile = options["tmxFile"];
        var tmxString = options["tmxString"];
        //todo check path and resourcePath
        var path = options["resourcePath"];

        var tmx = null;
        if (tmxFile && "" != tmxFile){
            tmx = new cc.TMXTiledMap(tmxFile);
        }else if (tmxString && "" != tmxString && path && "" != path){
            tmx = new cc.TMXTiledMap(tmxString, path);
        }
        return tmx;
    };
    var uiParser = load.getParser("ccui")["*"];
    parser.initWidget = function(options, resourcePath){
        var type = options["classname"];

        var parser = uiParser.parsers[type];
        if(!parser)
            return cc.log("%s parser is not found", type);

        var node = parser.call(uiParser, options, resourcePath);
        if(node){
            var rotationSkewX = options["rotationSkewX"];
            var rotationSkewY = options["rotationSkewY"];
            var skewx         = options["skewX"];
            var skewy         = options["skewY"];
            if(rotationSkewX != 0)
                node.setRotationX(rotationSkewX);
            if(rotationSkewY != 0)
                node.setRotationY(rotationSkewY);
            if(skewx != 0)
                node.setSkewX(skewx);
            if(skewy != 0)
                node.setSkewY(skewy);

            var actionTag = options["actionTag"];
            node.setUserObject(new ccs.ActionTimelineData(actionTag));
        }
        return node;
    };

    var register = [
        {name: "Node", handle: parser.initNode},
        {name: "SubGraph", handle: parser.initSubGraph},
        {name: "Sprite", handle: parser.initSprite},
        {name: "Particle", handle: parser.initParticle},
        {name: "TMXTiledMap", handle: parser.initTMXTiledMap},

        {name: "Widget", handle: parser.initWidget},
        {name: "Panel", handle: parser.initWidget},
        {name: "Button", handle: parser.initWidget},
        {name: "CheckBox", handle: parser.initWidget},
        {name: "ImageView", handle: parser.initWidget},
        {name: "LabelAtlas", handle: parser.initWidget},
        {name: "LabelBMFont", handle: parser.initWidget},
        {name: "Label", handle: parser.initWidget},
        {name: "ListView", handle: parser.initWidget},
        {name: "LoadingBar", handle: parser.initWidget},
        {name: "PageView", handle: parser.initWidget},
        {name: "ScrollView", handle: parser.initWidget},
        {name: "Slider", handle: parser.initWidget},
        {name: "TextField", handle: parser.initWidget}
    ];

    register.forEach(function(item){
        parser.registerParser(item.name, function(options, parse, resourcePath){
            var node = item.handle.call(this, options["options"]);
            this.parseComponent(node, options["components"]);
            this.parseChild(parse, node, options, resourcePath);
            return node;
        });
    });

    load.registerParser("timeline", "*", parser);

})(ccs._load, ccs._parser);
<|endoftext|>


<commit_before>'use strict';

var diffMatchPatch;
/**
 * @param {Function} onload
 */
function loadDiffMatchPatch(onload) {
    var script = document.createElement('script');
    script.src = 'diff_match_patch.js';
    script.onload = function() {
        diffMatchPatch = new diff_match_patch();
        onload();
    };
    document.head.appendChild(script);
}

function ResourceMap() {
    this._map = {};
}
ResourceMap.prototype = {
    get: function(key) {
        this.assertKey(key);
        if (!this._map.hasOwnProperty(key)) {
            throw new Error('resourceMap does not have ' + JSON.stringify(key) + ' key.');
        }
        return this._map[key];
    },
    set: function(key, value) {
        this.assertKey(key);
        this._map[key] = value;
    },
    assertKey: function(key) {
        if (!key) {
            throw new Error('key is ' + JSON.stringify(key));
        }
    }
};

var resourceMap;
var lastStylesheetURL = '';
var addedCSS = '';

/**
 * @param {Object} event
 * @nosideeffects
 * @return {boolean}
 */
function isNewlyAdded(event) {
    return event.url.indexOf('inspector://') == 0 || event.type === 'document';
}

chrome.devtools.inspectedWindow.onResourceContentCommitted.addListener(function(event) {

    if (isNewlyAdded(event)) {
        if (lastStylesheetURL) {
            getBackend(lastStylesheetURL);
        } else {
            getLastStylesheetURL(getBackend);
        }
    } else {
        getBackend(event.url);
    }

    function getBackend(url) {
        chrome.extension.sendRequest({method: 'getBackend', url: url}, function(response) {

            if (!response) {
                console.error(url + ' doesn\'t match any rules in the DevTools Autosave options.');
                return;
            }

            event.getContent(function(content) {
                if (diffMatchPatch) {
                    sendToBackgroundPage();
                } else {
                    loadDiffMatchPatch(sendToBackgroundPage);
                }

                function sendToBackgroundPage() {
                    var patch;
                    if (isNewlyAdded(event)) {
                        var oldAddedCSS = addedCSS;
                        if (content) {
                            addedCSS = '\n' + content + '\n';
                        } else {
                            addedCSS = '';
                        }
                        patch = diffMatchPatch.patch_make(resourceMap.get(lastStylesheetURL) + oldAddedCSS, resourceMap.get(lastStylesheetURL) + addedCSS);
                    } else {
                        patch = diffMatchPatch.patch_make(resourceMap.get(url), content);
                        resourceMap.set(url, content);
                    }

                    if (arePatchesEmpty(patch)) {
                        console.error('Patch for ' + JSON.stringify(url) + ' is empty.');
                        return;
                    }

                    chrome.extension.sendRequest({
                        method: 'send',
                        content: JSON.stringify(patch),
                        url: response.serverURL,
                        headers: {
                            'Content-Type': 'application/json',
                            'X-URL': url,
                            'X-Path': response.savePath,
                            'X-Type': event.type
                        }
                    });
                }
            });
        });
    }
});

/**
 * @param {Array} patches
 * @nosideeffects
 * @return {Boolean}
 */
function arePatchesEmpty(patches) {
    for (var i = 0, ii = patches.length; i < ii; i++) {
        if (patches[i].diffs.length > 0) {
            return false;
        }
    }
    return true;
}

/**
 * @param {Function} onSuccess
 */
function getLastStylesheetURL(onSuccess) {
    lastStylesheetURL = '';
    chrome.devtools.inspectedWindow.eval('(function() {\n\
    var links = document.head.querySelectorAll("link[rel=stylesheet][href]");\n\
    var last = links[links.length - 1];\n\
    return last && last.href})()', function(href, fail) {
        if (fail || !href) {
            throw new Error('Cannot find link[rel=stylesheet][href] in the head.');
        }
        lastStylesheetURL = href;
        onSuccess(href);
    });
}

/**
 * @param {Resource} resource
 */
function addResource(resource) {
    var url = resource.url;
    if (!url || url === 'about:blank') {
        return;
    }
    switch (resource.type) {
        case 'stylesheet':
        case 'script':
            resource.getContent(function(content) {
                resourceMap.set(url, content);
            });
            break;
    }
}

function getAllResources() {
    resourceMap = new ResourceMap();
    chrome.devtools.inspectedWindow.getResources(function(resources) {
        resources.forEach(addResource);
    });
}

getAllResources();

chrome.devtools.inspectedWindow.onResourceAdded.addListener(addResource);

chrome.devtools.network.onNavigated.addListener(function() {
    console.log('Reloaded');
    addedCSS = '';
    getAllResources();
});
<commit_msg>Make a proper logging to detect bugs<commit_after>'use strict';

var diffMatchPatch;
/**
 * @param {Function} onload
 */
function loadDiffMatchPatch(onload) {
    console.info('Loading diff_match_patch.js');
    var script = document.createElement('script');
    script.src = 'diff_match_patch.js';
    script.onload = function() {
        diffMatchPatch = new diff_match_patch();
        console.info('diff_match_patch.js loaded');
        onload();
    };
    document.head.appendChild(script);
}

function ResourceMap() {
    this._map = {};
}
ResourceMap.prototype = {
    get: function(key) {
        this.assertKey(key);
        if (!this._map.hasOwnProperty(key)) {
            throw new Error('resourceMap does not have ' + JSON.stringify(key) + ' key.');
        }
        return this._map[key];
    },
    set: function(key, value) {
        this.assertKey(key);
        this._map[key] = value;
    },
    assertKey: function(key) {
        if (!key) {
            throw new Error('key is ' + JSON.stringify(key));
        }
    }
};

var resourceMap;
var lastStylesheetURL = '';
var addedCSS = '';

/**
 * @param {Object} event
 * @nosideeffects
 * @return {boolean}
 */
function isNewlyAdded(event) {
    return event.url.indexOf('inspector://') == 0 || event.type === 'document';
}

chrome.devtools.inspectedWindow.onResourceContentCommitted.addListener(function(event) {

    if (isNewlyAdded(event)) {
        if (lastStylesheetURL) {
            getBackend(lastStylesheetURL);
        } else {
            getLastStylesheetURL(getBackend);
        }
    } else {
        getBackend(event.url);
    }

    function getBackend(url) {
        chrome.extension.sendRequest({method: 'getBackend', url: url}, function(response) {

            if (!response) {
                console.error(url + ' doesn\'t match any rules in the DevTools Autosave options.');
                return;
            }

            event.getContent(function(content) {
                if (diffMatchPatch) {
                    sendToBackgroundPage();
                } else {
                    loadDiffMatchPatch(sendToBackgroundPage);
                }

                function sendToBackgroundPage() {
                    var patch;
                    if (isNewlyAdded(event)) {
                        console.info('New CSS rules added. Appending them to', lastStylesheetURL);
                        var oldAddedCSS = addedCSS;
                        if (content) {
                            addedCSS = '\n' + content + '\n';
                        } else {
                            addedCSS = '';
                        }
                        patch = diffMatchPatch.patch_make(resourceMap.get(lastStylesheetURL) + oldAddedCSS, resourceMap.get(lastStylesheetURL) + addedCSS);
                    } else {
                        patch = diffMatchPatch.patch_make(resourceMap.get(url), content);
                        resourceMap.set(url, content);
                    }

                    if (arePatchesEmpty(patch)) {
                        console.error('Patch for ' + JSON.stringify(url) + ' is empty.');
                        return;
                    }

                    chrome.extension.sendRequest({
                        method: 'send',
                        content: JSON.stringify(patch),
                        url: response.serverURL,
                        headers: {
                            'Content-Type': 'application/json',
                            'X-URL': url,
                            'X-Path': response.savePath,
                            'X-Type': event.type
                        }
                    });
                }
            });
        });
    }
});

/**
 * @param {Array} patches
 * @nosideeffects
 * @return {Boolean}
 */
function arePatchesEmpty(patches) {
    for (var i = 0, ii = patches.length; i < ii; i++) {
        if (patches[i].diffs.length > 0) {
            return false;
        }
    }
    return true;
}

/**
 * @param {Function} onSuccess
 */
function getLastStylesheetURL(onSuccess) {
    lastStylesheetURL = '';
    chrome.devtools.inspectedWindow.eval('(function() {\n\
    var links = document.head.querySelectorAll("link[rel=stylesheet][href]");\n\
    var last = links[links.length - 1];\n\
    return last && last.href})()', function(href, fail) {
        if (fail || !href) {
            throw new Error('Cannot find link[rel=stylesheet][href] in the head.');
        }
        lastStylesheetURL = href;
        onSuccess(href);
    });
}

/**
 * @param {Resource} resource
 */
function addResource(resource) {
    var url = resource.url;
    if (!url || url === 'about:blank') {
        return;
    }
    switch (resource.type) {
        case 'stylesheet':
        case 'script':
            resource.getContent(function(content) {
                resourceMap.set(url, content);
            });
            console.info(url, 'loaded');
            break;
    }
}

function getAllResources() {
    console.info('Loading all scripts and stylesheets');
    resourceMap = new ResourceMap();
    chrome.devtools.inspectedWindow.getResources(function(resources) {
        resources.forEach(addResource);
    });
}

getAllResources();

chrome.devtools.inspectedWindow.onResourceAdded.addListener(addResource);

chrome.devtools.network.onNavigated.addListener(function() {
    console.info('A page reloaded');
    addedCSS = '';
    getAllResources();
});
<|endoftext|>