<commit_before>var _ = require('lodash');
var csw = require('csw');
var mongoose = require('../mongoose');
var Record = mongoose.model('Record');
var Service = mongoose.model('Service');
var util = require('util');
var moment = require('moment');

function harvestService(service, job, done) {
    var client = csw(service.location, {
        maxSockets: job.data.maxSockets || 5,
        keepAlive: true,
        retry: job.data.maxRetry || 3,
        userAgent: 'Afigeo CSW harvester'
    });

    var harvesterOptions = {
        mapper: 'iso19139',
        constraintLanguage: 'CQL_TEXT'
    };

    if (service.location.indexOf('isogeo') !== -1) harvesterOptions.namespace = 'xmlns(gmd=http://www.isotc211.org/2005/gmd)';
    if (service.location.indexOf('geoportal/csw/discovery') !== -1) delete harvesterOptions.constraintLanguage;

    var startTime = Date.now();

    var harvester = client.harvest(harvesterOptions);

    var total;

    harvester.on('error', function(err) {
        job.log(JSON.stringify(err));
        console.log(util.inspect(err, { showHidden: true, depth: null }));
    });

    harvester.on('start', function(stats) {
        total = stats.matched;
        job.log(JSON.stringify(stats));
    });

    harvester.on('page', function(infos) {
        if (infos.announced < infos.found) {
            total -= (infos.announced - infos.found);
            job.log('Notice: %d records found of %d announced!', infos.found, infos.announced);
        }
    });

    harvester.on('end', function(err, stats) {
        var endTime = Date.now();

        if (err) {
            console.log(err);
            done(err);
            service
                .set('harvesting.state', 'error')
                .save(function(err) {
                    console.log(err);
                });
        } else {
            service
                .set('harvesting.state', 'idle')
                .set('harvesting.jobId', null)
                .set('harvesting.lastDuration', endTime - startTime)
                .set('harvesting.lastSuccessful', endTime)
                .set('items', stats.returned)
                .save(function(err) {
                    if (err) return done(err);
                    done();
                });
        }
    });

    harvester.on('record', function(data) {
        var record = data.record;
        job.progress(data.stats.returned, total);

        if (!record.fileIdentifier) {
            job.log('Dropping 1 record!');
            return;
        }

        var query = {
            identifier: record.fileIdentifier,
            parentCatalog: service.id
        };

        var metadata = _.pick(record, [
            'title',
            'abstract',
            'type',
            'representationType',
            'serviceType',
            'keywords',
            'onlineResources',
            'contacts',
            '_contacts',
            '_updated'
        ]);

        if (metadata._updated) metadata._updated = moment(metadata._updated).toDate();

        var update = { $set: { metadata: metadata }};

        Record.findOneAndUpdate(query, update, { upsert: true }, function(err) {
            if (err) console.log(err);
        });

    });
}

exports.harvest = function(job, done) {
    Service.findById(job.data.serviceId, function(err, service) {
        if (err) return done(err);
        if (!service) return done(new Error('Unable to fetch service ' + job.data.serviceId));
        if (!service.harvesting.enabled) return done(new Error('Harvesting is disabled for service ' + job.data.serviceId));
        if (service.harvesting.state !== 'queued') return done(new Error('Unconsistent state for service ' + job.data.serviceId));
        if (service.harvesting.jobId && service.harvesting.jobId !== parseInt(job.id)) return done(new Error('Unconsistent jobId for service ' + job.data.serviceId));

        setTimeout(function() {
            service
                .set('harvesting.state', 'processing')
                .save(function(err) {
                    if (err) return done(err);
                    harvestService(service, job, done);
                });
        }, 2000);
    });
};
<commit_msg>Separate record processing from harvesting<commit_after>var _ = require('lodash');
var csw = require('csw');
var mongoose = require('../mongoose');
var Record = mongoose.model('Record');
var Service = mongoose.model('Service');
var util = require('util');
var moment = require('moment');

function processRecord(record, service) {
    var query = {
        identifier: record.fileIdentifier,
        parentCatalog: service.id
    };

    var metadata = _.pick(record, [
        'title',
        'abstract',
        'type',
        'representationType',
        'serviceType',
        'keywords',
        'onlineResources',
        'contacts',
        '_contacts',
        '_updated'
    ]);

    if (metadata._updated) metadata._updated = moment(metadata._updated).toDate();

    var update = { $set: { metadata: metadata }};

    Record.findOneAndUpdate(query, update, { upsert: true }, function(err) {
        if (err) console.log(err);
    });
}

function harvestService(service, job, done) {
    var client = csw(service.location, {
        maxSockets: job.data.maxSockets || 5,
        keepAlive: true,
        retry: job.data.maxRetry || 3,
        userAgent: 'Afigeo CSW harvester'
    });

    var harvesterOptions = {
        mapper: 'iso19139',
        constraintLanguage: 'CQL_TEXT'
    };

    if (service.location.indexOf('isogeo') !== -1) harvesterOptions.namespace = 'xmlns(gmd=http://www.isotc211.org/2005/gmd)';
    if (service.location.indexOf('geoportal/csw/discovery') !== -1) delete harvesterOptions.constraintLanguage;

    var startTime = Date.now();

    var harvester = client.harvest(harvesterOptions);

    var total;

    harvester.on('error', function(err) {
        job.log(JSON.stringify(err));
        console.log(util.inspect(err, { showHidden: true, depth: null }));
    });

    harvester.on('start', function(stats) {
        total = stats.matched;
        job.log(JSON.stringify(stats));
    });

    harvester.on('page', function(infos) {
        if (infos.announced < infos.found) {
            total -= (infos.announced - infos.found);
            job.log('Notice: %d records found of %d announced!', infos.found, infos.announced);
        }
    });

    harvester.on('end', function(err, stats) {
        var endTime = Date.now();

        if (err) {
            console.log(err);
            done(err);
            service
                .set('harvesting.state', 'error')
                .save(function(err) {
                    console.log(err);
                });
        } else {
            service
                .set('harvesting.state', 'idle')
                .set('harvesting.jobId', null)
                .set('harvesting.lastDuration', endTime - startTime)
                .set('harvesting.lastSuccessful', endTime)
                .set('items', stats.returned)
                .save(function(err) {
                    if (err) return done(err);
                    done();
                });
        }
    });

    harvester.on('record', function(data) {
        var record = data.record;
        job.progress(data.stats.returned, total);

        if (!record.fileIdentifier) {
            job.log('Dropping 1 record!');
            return;
        }

        processRecord(record, service);

    });
}

exports.harvest = function(job, done) {
    Service.findById(job.data.serviceId, function(err, service) {
        if (err) return done(err);
        if (!service) return done(new Error('Unable to fetch service ' + job.data.serviceId));
        if (!service.harvesting.enabled) return done(new Error('Harvesting is disabled for service ' + job.data.serviceId));
        if (service.harvesting.state !== 'queued') return done(new Error('Unconsistent state for service ' + job.data.serviceId));
        if (service.harvesting.jobId && service.harvesting.jobId !== parseInt(job.id)) return done(new Error('Unconsistent jobId for service ' + job.data.serviceId));

        setTimeout(function() {
            service
                .set('harvesting.state', 'processing')
                .save(function(err) {
                    if (err) return done(err);
                    harvestService(service, job, done);
                });
        }, 2000);
    });
};
<|endoftext|>


<commit_before>/*!
 * Chai - transferFlags utility
 * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>
 * MIT Licensed
 */

/**
 * ### transferFlags(assertion, object, includeAll = true)
 *
 * Transfer all the flags for `assertion` to `object`. If
 * `includeAll` is set to `false`, then the base Chai
 * assertion flags (namely `object`, `ssfi`, and `message`)
 * will not be transferred.
 *
 *
 *     var newAssertion = new Assertion();
 *     utils.transferFlags(assertion, newAssertion);
 *
 *     var anotherAsseriton = new Assertion(myObj);
 *     utils.transferFlags(assertion, anotherAssertion, false);
 *
 * @param {Assertion} assertion the assertion to transfer the flags from
 * @param {Object} object the object to transfer the flags to; usually a new assertion
 * @param {Boolean} includeAll
 * @name transferFlags
 * @api private
 */

module.exports = function (assertion, object, includeAll) {
  var flags = assertion.__flags || (assertion.__flags = Object.create(null));

  if (!object.__flags) {
    object.__flags = Object.create(null);
  }

  includeAll = arguments.length === 3 ? includeAll : true;

  for (var flag in flags) {
    if (includeAll ||
        (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) {
      object.__flags[flag] = flags[flag];
    }
  }
};
<commit_msg>Delete transferFlags.js<commit_after><|endoftext|>


<commit_before>/* Main endpoints for the Polyfill service public API */

'use strict';

const polyfillio = require('../../lib');
const PolyfillSet = require('../PolyfillSet');
const metrics = require('../metrics');
const express = require('express');

const router = express.Router();  // eslint-disable-line new-cap
const contentTypes = {".js": 'application/javascript', ".css": 'text/css'};
const one_day = 60 * 60 * 24;
const one_week = one_day * 7;
const one_year = one_day * 365;

router.get(/^\/v1\/(.*)/, (req, res) => {

	const qs = Object.keys(req.query).reduce((out, key) => {
		if (key !== 'libVersion' && key !== 'gated') {
			out.push(encodeURIComponent(key)+'='+encodeURIComponent(req.query[key]));
		}
		return out;
	}, []).join('&');
	const redirPath = '/v2/' + req.params[0].replace(/[^\w\/\.\+\:]/g, '') + (qs.length ? '?'+qs : '');

	res.status(301);
	res.set('Location', redirPath);
	res.set('Deprecation-Notice', 'API version 1 has been decommissioned - see the body of this response for more information.');
	res.send('API version 1 has been decommissioned. Your request is being redirected to v2.  The `libVersion` and `gated` query string parameters are no longer supported and if present have been removed from your request.\n\nA deprecation period for v1 existed between August and December 2015, during which time v1 requests were honoured but a deprecation warning was added to output.');
});

router.get(/^\/v2\/polyfill(\.\w+)(\.\w+)?/, (req, res) => {
	metrics.counter('hits').inc();
	const respTimeTimer = metrics.timer('respTime').start();
	const firstParameter = req.params[0].toLowerCase();
	const minified = firstParameter === '.min';
	const fileExtension = req.params[1] ? req.params[1].toLowerCase() : firstParameter;
	const uaString = (typeof req.query.ua === 'string' && req.query.ua) || req.header('user-agent');
	const flags = (typeof req.query.flags === 'string') ? req.query.flags.split(',') : [];
	const warnings = [];

	// Currently don't support CSS
	if (fileExtension !== '.js') {
		res.status(404);
		res.set('Content-Type', 'text/plain;charset=utf-8');
		res.send('/* Type not supported.  Only .js is supported at the moment */');
		return;
	}

	const polyfills = PolyfillSet.fromQueryParam(req.query.features, flags);

	// If inbound request did not specify UA on the query string, the cache key must use the HTTP header
	if (!req.query.ua) {
		res.set('Vary', 'User-Agent');
	}

	const params = {
		features: polyfills.get(),
		excludes: (typeof req.query.excludes === 'string' && req.query.excludes.split(',')) || [],
		minify: minified,
		rum: req.query.rum,
		baseurl: req.protocol+'://'+req.get('host')
	};
	if (req.query.unknown) {
		params.unknown = req.query.unknown;
	}
	if (uaString) {
		params.uaString = uaString;
		metrics.counter('useragentcount.'+polyfillio.normalizeUserAgent(uaString).replace(/^(.*?)\/(\d+)(\..*)?$/, '$1.$2')).inc();
	}

	polyfillio.getPolyfillString(params).then(op => {
		if (warnings.length) {
			op = '/* WARNINGS:\n\n- ' + warnings.join('\n- ') + '\n\n*/\n\n' + op;
		}
		if (req.query.callback && req.query.callback.match(/^[\w\.]+$/)) {
			op += "\ntypeof "+req.query.callback+"==='function' && "+req.query.callback+"();";
		}
		res.set('Content-Type', contentTypes[fileExtension]+';charset=utf-8');
		res.set('Access-Control-Allow-Origin', '*');
		res.send(op);
		respTimeTimer.end();
	});

});

router.get("/v2/normalizeUa", (req, res) => {

	if (req.query.ua) {
		res.status(200);
		res.set('Cache-Control', 'public, max-age='+one_year+', stale-if-error='+(one_year+one_week));
		res.set('Normalized-User-Agent', encodeURIComponent(polyfillio.normalizeUserAgent(req.query.ua)));
		res.send();
	} else {
		res.status(400);
		res.send('ua query param required');
	}
});

module.exports = router;
<commit_msg>protocol agnostic rum collection (#759)<commit_after>/* Main endpoints for the Polyfill service public API */

'use strict';

const polyfillio = require('../../lib');
const PolyfillSet = require('../PolyfillSet');
const metrics = require('../metrics');
const express = require('express');

const router = express.Router();  // eslint-disable-line new-cap
const contentTypes = {".js": 'application/javascript', ".css": 'text/css'};
const one_day = 60 * 60 * 24;
const one_week = one_day * 7;
const one_year = one_day * 365;

router.get(/^\/v1\/(.*)/, (req, res) => {

	const qs = Object.keys(req.query).reduce((out, key) => {
		if (key !== 'libVersion' && key !== 'gated') {
			out.push(encodeURIComponent(key)+'='+encodeURIComponent(req.query[key]));
		}
		return out;
	}, []).join('&');
	const redirPath = '/v2/' + req.params[0].replace(/[^\w\/\.\+\:]/g, '') + (qs.length ? '?'+qs : '');

	res.status(301);
	res.set('Location', redirPath);
	res.set('Deprecation-Notice', 'API version 1 has been decommissioned - see the body of this response for more information.');
	res.send('API version 1 has been decommissioned. Your request is being redirected to v2.  The `libVersion` and `gated` query string parameters are no longer supported and if present have been removed from your request.\n\nA deprecation period for v1 existed between August and December 2015, during which time v1 requests were honoured but a deprecation warning was added to output.');
});

router.get(/^\/v2\/polyfill(\.\w+)(\.\w+)?/, (req, res) => {
	metrics.counter('hits').inc();
	const respTimeTimer = metrics.timer('respTime').start();
	const firstParameter = req.params[0].toLowerCase();
	const minified = firstParameter === '.min';
	const fileExtension = req.params[1] ? req.params[1].toLowerCase() : firstParameter;
	const uaString = (typeof req.query.ua === 'string' && req.query.ua) || req.header('user-agent');
	const flags = (typeof req.query.flags === 'string') ? req.query.flags.split(',') : [];
	const warnings = [];

	// Currently don't support CSS
	if (fileExtension !== '.js') {
		res.status(404);
		res.set('Content-Type', 'text/plain;charset=utf-8');
		res.send('/* Type not supported.  Only .js is supported at the moment */');
		return;
	}

	const polyfills = PolyfillSet.fromQueryParam(req.query.features, flags);

	// If inbound request did not specify UA on the query string, the cache key must use the HTTP header
	if (!req.query.ua) {
		res.set('Vary', 'User-Agent');
	}

	const params = {
		features: polyfills.get(),
		excludes: (typeof req.query.excludes === 'string' && req.query.excludes.split(',')) || [],
		minify: minified,
		rum: req.query.rum,
		baseurl: '//'+req.get('host')
	};
	if (req.query.unknown) {
		params.unknown = req.query.unknown;
	}
	if (uaString) {
		params.uaString = uaString;
		metrics.counter('useragentcount.'+polyfillio.normalizeUserAgent(uaString).replace(/^(.*?)\/(\d+)(\..*)?$/, '$1.$2')).inc();
	}

	polyfillio.getPolyfillString(params).then(op => {
		if (warnings.length) {
			op = '/* WARNINGS:\n\n- ' + warnings.join('\n- ') + '\n\n*/\n\n' + op;
		}
		if (req.query.callback && req.query.callback.match(/^[\w\.]+$/)) {
			op += "\ntypeof "+req.query.callback+"==='function' && "+req.query.callback+"();";
		}
		res.set('Content-Type', contentTypes[fileExtension]+';charset=utf-8');
		res.set('Access-Control-Allow-Origin', '*');
		res.send(op);
		respTimeTimer.end();
	});

});

router.get("/v2/normalizeUa", (req, res) => {

	if (req.query.ua) {
		res.status(200);
		res.set('Cache-Control', 'public, max-age='+one_year+', stale-if-error='+(one_year+one_week));
		res.set('Normalized-User-Agent', encodeURIComponent(polyfillio.normalizeUserAgent(req.query.ua)));
		res.send();
	} else {
		res.status(400);
		res.send('ua query param required');
	}
});

module.exports = router;
<|endoftext|>


<commit_before>/*

模块功能： Violet 客户端 SDK

配置文件： violet.json - host

API:
-----------
post(path, data, callback(result)) 向认证服务器发送信息
@param path : 请求服务类型 []
@param data : 数据主体
@param callback(result) : 返回请求结果
@具体服务类型和返回数据结构请查看相关文档
******
example code :
exports.post('/user/post', { data: 'hello, world' }, (data) => {
  console.log(data);
});
----------
*/

const fs = require('fs'); //文件处理
const config = JSON.parse(fs.readFileSync('./config/violet.json'));
const https = require('https'); // https模块
const queryString = require("querystring"); // 转化为格式化对象
const crypto = require('crypto');
const cookieParser = require('cookie-parser'); // cookie模块
const userMod = require('../user.js');

exports.post = (path, data, callback) => {
  let postData = queryString.stringify(data);
  let options = {
    hostname: config.host,
    port: 443,
    path: path,
    method: 'POST',
    headers: {
      "Content-Type": 'application/x-www-form-urlencoded',
      "Content-Length": postData.length
    }
  };
  let req = https.request(options, (res) => {
    if (res.statusCode != '200') {
      return callback({ state: 'failed', reason: res.statusCode });
    }
    res.on('data', (d) => {
      if (d.toString('ascii').indexOf('"state":"ok"') != -1) {
        return callback({ state: 'ok', data: d.toString('ascii') });
      } else {
        return callback({ state: 'failed', reason: d.toString('ascii') });
      }
    });
  });
  req.write(postData);
  req.on('error', (e) => {
    return callback({ state: 'failed', reason: e });
  });
  req.end();
};

exports.encrypt = (json) => {
  var cipher = crypto.createCipher('aes192', config.key);
  var enc = cipher.update(JSON.stringify(json), 'utf8', 'hex');
  enc += cipher.final('hex');
  enc += 'o' + exports.makeAMD5(enc).slice(20);
  return enc;
}; // 加密数据

exports.decrypt = (str) => {
  var data = str.split('o');
  if (exports.makeAMD5(data[0]).slice(20) == data[1]) {
    var decipher = crypto.createDecipher('aes192', config.key);
    var dec = decipher.update(data[0], 'hex', 'utf8');
    dec += decipher.final('utf8');
    var reg = new RegExp('"', "g");
    dec = dec.replace(reg, "");
    return dec;
  } else {
    return 'ERR';
  } //解密数据
};

exports.makeASha = function(str) {
  var hashSHA = crypto.createHash('sha512');
  hashSHA.update(str + config.sign);
  return hashSHA.digest('hex');
}; // 散列

exports.makeAMD5 = function(str) {
  var hashSHA = crypto.createHash('md5');
  hashSHA.update(str + config.sign);
  return hashSHA.digest('hex');
}; // 散列

exports.getUserId = (res) => { //获取用户id
  return res.locals.userData.uid;
};

exports.getUserEmail = (res) => {
  return res.locals.userData.email;
};

exports.getUserName = (res) => {
  return res.locals.userData.name;
};
exports.getUserData = (res) => {
  return res.locals.userData;
};

exports.getNowTime = () => { //当前时间
  return Math.ceil(((new Date()).getTime() - 1499860673563) / 1000);
};

exports.comTime = (time) => { //比较时间
  return exports.getNowTime() - Math.ceil((time.getTime() - 1499860673563) / 1000);
};

exports.checkToken = (req, res, next) => { // 检测token
  let token = req.cookies.token;
  if (token === undefined || token === null) {
    res.send({ state: 'failed', reason: 'ERR_TOKEN' });
    next('route');
    return;
  }
  token = exports.decrypt(token);
  let data = token.split('&');
  if (data[0] === undefined || data[1] === undefined) {
    res.send({ state: 'failed', reason: 'ERR_TOKEN' });
    next('route');
  } else if ((exports.getNowTime() - data[1]) > 864000) {
    res.send({ state: 'failed', reason: 'TIMEOUT' });
    next('route');
  } else {
    let token = Math.round(Math.random() * 1000000);
    userMod.DBToken(res, data[0], data[2], token, (str) => {
      if (str == 'OK') {
        let userData = data[0] + '&' + exports.getNowTime() + '&' + token;
        exports.makeUserToken(req, res, userData, () => {
          next();
        });
      } else {
        res.send({ state: 'failed', reason: 'ERR_TOKEN' });
        next('route');
      }
    });
  }
};

exports.makeUserToken = (req, res, userData, callback) => { //设置cookies信息
  res.cookie('remember', req.cookies.remember, { expires: new Date(Date.now() + 8640000000), httpOnly: false });
  res.cookie('isLogin', true, { expires: new Date(Date.now() + 8640000000), httpOnly: false });
  if (req.cookies.remember == 'true') {
    res.cookie('token', exports.encrypt(userData), { expires: new Date(Date.now() + 8640000000), httpOnly: true });
    // 10天后过期
  } else {
    res.cookie('token', exports.encrypt(userData), { expires: 0, httpOnly: true });
  }
  if (callback !== undefined) callback();
};

exports.logout = (req, res, next) => { // 退出登陆
  res.cookie('isLogin', false, { expires: new Date(Date.now() + 8640000000), httpOnly: false });
  res.clearCookie('token');
  res.send({ state: 'ok' });
  next('route');
};

exports.makeToken = () => { // 生成网站令牌
  var token = config.webId + '&' + exports.getNowTime();
  token = exports.encrypt(token);
  return token;
};

exports.getUserInfo = (token) => {
  exports.post('/api/getInfo', { userToken: token, webToken: exports.makeToken() }, (data) => {
    if (data.state == 'failed') {
      console.log('ERR: ' + data.reason);
    } else {
      // 处理用户信息 data.data
    }
  });
};<commit_msg>紧急修复BUG<commit_after>/*

模块功能： Violet 客户端 SDK

配置文件： violet.json - host

API:
-----------
post(path, data, callback(result)) 向认证服务器发送信息
@param path : 请求服务类型 []
@param data : 数据主体
@param callback(result) : 返回请求结果
@具体服务类型和返回数据结构请查看相关文档
******
example code :
exports.post('/user/post', { data: 'hello, world' }, (data) => {
  console.log(data);
});
----------
*/

const fs = require('fs'); //文件处理
const config = JSON.parse(fs.readFileSync('./config/violet.json'));
const https = require('https'); // https模块
const queryString = require("querystring"); // 转化为格式化对象
const crypto = require('crypto');
const cookieParser = require('cookie-parser'); // cookie模块
const userMod = require('../user.js');

exports.post = (path, data, callback) => {
  let postData = queryString.stringify(data);
  let options = {
    hostname: config.host,
    port: 443,
    path: path,
    method: 'POST',
    headers: {
      "Content-Type": 'application/x-www-form-urlencoded',
      "Content-Length": postData.length
    }
  };
  let req = https.request(options, (res) => {
    if (res.statusCode != '200') {
      return callback({ state: 'failed', reason: res.statusCode });
    }
    res.on('data', (d) => {
      if (d.toString('ascii').indexOf('"state":"ok"') != -1) {
        return callback({ state: 'ok', data: JSON.parse(d.toString('ascii')) });
      } else {
        return callback({ state: 'failed', reason: d.toString('ascii') });
      }
    });
  });
  req.write(postData);
  req.on('error', (e) => {
    return callback({ state: 'failed', reason: e });
  });
  req.end();
};

exports.encrypt = (json) => {
  var cipher = crypto.createCipher('aes192', config.key);
  var enc = cipher.update(JSON.stringify(json), 'utf8', 'hex');
  enc += cipher.final('hex');
  enc += 'o' + exports.makeAMD5(enc).slice(20);
  return enc;
}; // 加密数据

exports.decrypt = (str) => {
  var data = str.split('o');
  if (exports.makeAMD5(data[0]).slice(20) == data[1]) {
    var decipher = crypto.createDecipher('aes192', config.key);
    var dec = decipher.update(data[0], 'hex', 'utf8');
    dec += decipher.final('utf8');
    var reg = new RegExp('"', "g");
    dec = dec.replace(reg, "");
    return dec;
  } else {
    return 'ERR';
  } //解密数据
};

exports.makeASha = function(str) {
  var hashSHA = crypto.createHash('sha512');
  hashSHA.update(str + config.sign);
  return hashSHA.digest('hex');
}; // 散列

exports.makeAMD5 = function(str) {
  var hashSHA = crypto.createHash('md5');
  hashSHA.update(str + config.sign);
  return hashSHA.digest('hex');
}; // 散列

exports.getUserId = (res) => { //获取用户id
  return res.locals.userData.uid;
};

exports.getUserEmail = (res) => {
  return res.locals.userData.email;
};

exports.getUserName = (res) => {
  return res.locals.userData.name;
};
exports.getUserData = (res) => {
  return res.locals.userData;
};

exports.getNowTime = () => { //当前时间
  return Math.ceil(((new Date()).getTime() - 1499860673563) / 1000);
};

exports.comTime = (time) => { //比较时间
  return exports.getNowTime() - Math.ceil((time.getTime() - 1499860673563) / 1000);
};

exports.checkToken = (req, res, next) => { // 检测token
  let token = req.cookies.token;
  if (token === undefined || token === null) {
    res.send({ state: 'failed', reason: 'ERR_TOKEN' });
    next('route');
    return;
  }
  token = exports.decrypt(token);
  let data = token.split('&');
  if (data[0] === undefined || data[1] === undefined) {
    res.send({ state: 'failed', reason: 'ERR_TOKEN' });
    next('route');
  } else if ((exports.getNowTime() - data[1]) > 864000) {
    res.send({ state: 'failed', reason: 'TIMEOUT' });
    next('route');
  } else {
    let token = Math.round(Math.random() * 1000000);
    userMod.DBToken(res, data[0], data[2], token, (str) => {
      if (str == 'OK') {
        let userData = data[0] + '&' + exports.getNowTime() + '&' + token;
        exports.makeUserToken(req, res, userData, () => {
          next();
        });
      } else {
        res.send({ state: 'failed', reason: 'ERR_TOKEN' });
        next('route');
      }
    });
  }
};

exports.makeUserToken = (req, res, userData, callback) => { //设置cookies信息
  res.cookie('remember', req.cookies.remember, { expires: new Date(Date.now() + 8640000000), httpOnly: false });
  res.cookie('isLogin', true, { expires: new Date(Date.now() + 8640000000), httpOnly: false });
  if (req.cookies.remember == 'true') {
    res.cookie('token', exports.encrypt(userData), { expires: new Date(Date.now() + 8640000000), httpOnly: true });
    // 10天后过期
  } else {
    res.cookie('token', exports.encrypt(userData), { expires: 0, httpOnly: true });
  }
  if (callback !== undefined) callback();
};

exports.logout = (req, res, next) => { // 退出登陆
  res.cookie('isLogin', false, { expires: new Date(Date.now() + 8640000000), httpOnly: false });
  res.clearCookie('token');
  res.send({ state: 'ok' });
  next('route');
};

exports.makeToken = () => { // 生成网站令牌
  var token = config.webId + '&' + exports.getNowTime();
  token = exports.encrypt(token);
  return token;
};

exports.getUserInfo = (token, callback) => {
  exports.post('/api/getInfo', { userToken: token, webToken: exports.makeToken() }, (data) => {
    if (data.state == 'failed') console.log('ERR: ' + data.reason);
    callback(data);
  });
};<|endoftext|>


<commit_before>/*
 *  asf-list -- List helpers
 *  Copyright (C) 2012 Stephane Carrez
 *  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
(function($, undefined) {

    $.widget( "ui.list", $.ui.mouse, {
        currentNode: null,

        /**
         * The active or highlighted item in the list.  This is the item which has the action element
         * as last child.
         */
        activeItem: null,

        /**
         * Indicates whether the bloc is active (has the mouse focus).
         */
        isActive: false,

        /**
         * The current item
         */
        currentItem: null,

        /**
         * The current inline edit node.
         */
        currentEdit: null,
        options: {
            min: 0,

            /**
             * The CSS class that is set on active elements.
             */
            activeClass: "asf-active",

            /**
             * The CSS class that is set on the selected element.
             */
            selectClass: "asf-selected",

            /**
             * The CSS class that indicates an element is being deleted.
             */
            deletingClass: "asf-deleting",

            /**
             * URL to edit an item of the list.
             */
            editUrl: null,

            /**
             * URL to delete an item of the list.
             */
            deleteUrl: null,

            /**
             * Relative URL to refresh the item (after edit or view mode for example).
             */
            refreshUrl: null,

            /**
             * Disable the mouseover effect.  When set to 'true', the mouseover effect implemented by
             * setting the 'active' CSS class on the item is disabled.
             */
            disableMouseover: false,

            /**
             * Prefix for item ids in the DOM tree
             */
            itemPrefix: '',

            /**
             * A function which is called when an element of the list is selected.
             */
            selectAction: null
        },

        _create: function() {
            var self = this;

            $.ui.mouse.prototype._create.apply(this, arguments);
            this.element.addClass("ui-list");
            this.element.bind('click', function(event) {
                return self.click(event);
            }).bind('blur', function(event) {
                return self.blur(event);
            });
            if (this.options.disableMouseover == false) {
                this.element.bind('mouseover', function(event) {
                    return self._mouseOver(event);
                }).bind('mouseout', function(event) {
                    return self._mouseOut(event);
                });
            }

            /**
             * Get the action element (a div in most cases) which contains the actions
             * to be displayed for the active/highlighted element.
             */
            this.action = $(this.options["actionId"]);
        },

        selectAction: function(node) {
            if (this.currentItem != null) {
                $(this.currentItem).removeClass(this.options.selectClass);
            }
            this.currentItem = node;
            $(this.currentItem).addClass(this.options.selectClass);
            if (this.options.selectAction != null) {
                this.options.selectAction(this, node);
            }
            return false;
        },

        /**
         * Set the active item.  The active item is marked with the 'active' class and kept as reference
         * in the 'activeItem' member.
         *
         * @param item the active item or null to disable any active item
         */
        setActiveItem: function(item) {
            if (this.activeItem != null && this.activeItem[0] != item) {
                // Ensure that previously active line is deactivated.
                this.activeItem.removeClass(this.options.activeClass);
            }
            if (item != null) {
                this.activeItem = $(item);
                this.activeItem.addClass(this.options.activeClass);
            } else {
                this.activeItem = null;
            }
        },

        /**
         * Get the object ID of the selected node.  This operation assumes that the HTML element has
         * an id of the form 'itemPrefix' + object Id.  This operation removes the item prefix.
         *
         * @param node the node element that was selected
         * @return the ID of the object
         */
        getSelectedId: function(node) {
            if (node == null) {
                return null;
            }
            var id = $(node).attr('id');
            if (id == null) {
                return null;
            }
            return id.substring(this.options.itemPrefix.length);
        },

        /**
         * Find the parent node that should receive the event.
         *
         */
        _getTargetNode: function(node) {
            while (node) {
                var name = node.tagName;
                if (name) {
                    name = name.toUpperCase();
                    if (name != "EM" && name != "I" && name != "B" && name != "IMG" && name != "SPAN") {
                        if (node.id && node.id != "" && this.action[0] != node) {
                            return node;
                        }
                        if (name == 'A') {
                            return node;
                        }
                    }
                }
                if (node == this.element[0]) {
                    return null;
                }

                node = node.parentNode;
            }
            return null;
        },

        /**
         * Get the item list node that contains the inner element represented by <tt>node</tt>.
         * Returns null if the node element is not part of a list item component.
         */
        getTarget: function(node) {
            if (node == this.element[0]) {
                return null;
            }
            while (node) {
                var name = node.tagName;
                if (name) {
                    name = name.toUpperCase();
                    if (name == "DIV" || name == "DL") {
                        var id = node.id;
                        if (id && id.indexOf(this.options.itemPrefix) === 0) {
                            return node;
                        }
                    }
                }
                node = node.parentNode;
                if (node == this.element[0]) {
                    return null;
                }
            }
            /* $("#current").html(node.id); */
            return node;
        },

        _mouseOver: function(event) {
            var node = this.getTarget(event.target);
            if (node && this.currentNode != node) {
                /* $("#current").html("Mover " + node.id); */
                this.setActiveItem(node);
                if (this.action[0]) {
                    this.action.detach();
                    this.action.prependTo(this.activeItem);
                }
            }
            if (this.isActive == false) {
                this.isActive = true;
                this.element.addClass(this.options.activeClass);
            }
        } ,

        _mouseOut: function(event) {
            if (!this.disableMouseover) {
                var node = event.target;
                while (node && node != document) {
                    if (node == this.activeItem) {
                        this.setActiveItem(null);
                        /* $("#current").html("Mouse out"); */
                        break;
                    } else {
                        if (node == this.element[0]) {
                            break;
                        }
                        node = node.parentNode;
                    }
                }
                if (node && node != document) {
                    this.isActive = false;
                    this.element.removeClass(this.options.activeClass);
                }
            }
        },
        /**
         * Get the shopping category.
         */
        getCategoryId: function() {
            return $(this.element).attr("data-id");
        },

        /**
         * Get the URL to execute an AJAX operation on the given item.  Override this operation to customize
         * the URL.
         *
         * @param item the item
         * @param oid the item identifier
         * @param url the relative URL
         * @return the URL to invoke an AJAX operation on the given item
         */
        getOperationUrl: function(item, oid, url) {
            return url + oid;
        },
        enterEdit: function(event) {
            var node = this.element.find(".am-list");
            var catId = this.getCategoryId();
            $("#current").html("Enter edit");
            ASF.Update(this.element, "/am/shoplist/edit-category.html?id=" + catId, node);
        },

        /**
         * Enter delete mode for the current active element.
         * The 'deletingCss' is applied on the element being deleted.  The delete dialog box is opened
         * to confirm the deletion of our item.  The 'deletingCSS' is removed once the dialog box is closed.
         */
        enterDelete: function(event) {
            var item = this.activeItem;
            var id   = this.getSelectedId(item);
            if (id) {
                var url = this.getOperationUrl(item, id, this.options.deleteUrl);
                if (url) {
                    var css = this.options.deletingClass;

                    item.addClass(css);
                    ASF.OpenDialog(item, 'deleteDialog_' + id, url, {
                        close: function() {
                            item.removeClass(css);
                        }
                    });
                }
            }
            return false;
        },
        enterCreate: function(event) {

        },

        /**
         * Click action executed when one inner HTML element is clicked.
         *
         * @param event the event that was clicked
         */
        click: function(event) {
            var node = this._getTargetNode(event.target);
            if (node && this.currentNode != node) {

                if ($(node).hasClass("asf-edit")) {
                    this.enterEdit(event);
                } else if ($(node).hasClass("asf-delete")) {
                    this.enterDelete(event);

                } else if ($(node).hasClass("asf-editable")) {
                    if (! $(node).hasClass("asf-editing")) {
                        this.currentEdit = node;
                        $(node).addClass("asf-editing");
                        this.enterCreate(event);
                    }
                } else {
                    this.selectAction(node);
                }
            } else {
                var name = event.target.tagName;
                node = event.target;

                if ($(node).hasClass("asf-edit")) {
                    this.enterEdit(event);
                } else if ($(node).hasClass("asf-delete")) {
                    this.enterDelete(event);
                }

            }
            event.stopPropagation();
        },
        blur: function(event) {
            if (this.currentEdit) {
                this.currentEdit.remove();
                this.currentEdit = null;
            }
        },
        destroy: function() {
            this.element.removeClass( "ui-list" );
            $.Widget.prototype.destroy.apply( this, arguments );
        }

    });
})( jQuery );
<commit_msg>Use the CSS 'asf-active-list' to mark a list as active (ie with the mouse focus)<commit_after>/*
 *  asf-list -- List helpers
 *  Copyright (C) 2012 Stephane Carrez
 *  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
(function($, undefined) {

    $.widget( "ui.list", $.ui.mouse, {
        currentNode: null,

        /**
         * The active or highlighted item in the list.  This is the item which has the action element
         * as last child.
         */
        activeItem: null,

        /**
         * Indicates whether the bloc is active (has the mouse focus).
         */
        isActive: false,

        /**
         * The current item
         */
        currentItem: null,

        /**
         * The current inline edit node.
         */
        currentEdit: null,
        options: {
            min: 0,

            /**
             * The CSS class that is set on active elements.
             */
            activeClass: "asf-active",

            /**
             * The CSS class that is set on the list element when it has the focus.
             */
            activeListClass: "asf-active-list",

            /**
             * The CSS class that is set on the selected element.
             */
            selectClass: "asf-selected",

            /**
             * The CSS class that indicates an element is being deleted.
             */
            deletingClass: "asf-deleting",

            /**
             * URL to edit an item of the list.
             */
            editUrl: null,

            /**
             * URL to delete an item of the list.
             */
            deleteUrl: null,

            /**
             * Relative URL to refresh the item (after edit or view mode for example).
             */
            refreshUrl: null,

            /**
             * Disable the mouseover effect.  When set to 'true', the mouseover effect implemented by
             * setting the 'active' CSS class on the item is disabled.
             */
            disableMouseover: false,

            /**
             * Prefix for item ids in the DOM tree.
             */
            itemPrefix: '',

            /**
             * A function which is called when an element of the list is selected.
             */
            selectAction: null
        },

        _create: function() {
            var self = this;

            $.ui.mouse.prototype._create.apply(this, arguments);
            this.element.addClass("ui-list");
            this.element.bind('click', function(event) {
                return self.click(event);
            }).bind('blur', function(event) {
                return self.blur(event);
            });
            if (this.options.disableMouseover == false) {
                this.element.bind('mouseover', function(event) {
                    return self._mouseOver(event);
                }).bind('mouseout', function(event) {
                    return self._mouseOut(event);
                });
            }

            /**
             * Get the action element (a div in most cases) which contains the actions
             * to be displayed for the active/highlighted element.
             */
            this.action = $(this.options["actionId"]);
        },

        selectAction: function(node) {
            if (this.currentItem != null) {
                $(this.currentItem).removeClass(this.options.selectClass);
            }
            this.currentItem = node;
            $(this.currentItem).addClass(this.options.selectClass);
            if (this.options.selectAction != null) {
                this.options.selectAction(this, node);
            }
            return false;
        },

        /**
         * Set the active item.  The active item is marked with the 'active' class and kept as reference
         * in the 'activeItem' member.
         *
         * @param item the active item or null to disable any active item
         */
        setActiveItem: function(item) {
            if (this.activeItem != null && this.activeItem[0] != item) {
                // Ensure that previously active line is deactivated.
                this.activeItem.removeClass(this.options.activeClass);
            }
            if (item != null) {
                this.activeItem = $(item);
                this.activeItem.addClass(this.options.activeClass);
            } else {
                this.activeItem = null;
            }
        },

        /**
         * Get the object ID of the selected node.  This operation assumes that the HTML element has
         * an id of the form 'itemPrefix' + object Id.  This operation removes the item prefix.
         *
         * @param node the node element that was selected
         * @return the ID of the object
         */
        getSelectedId: function(node) {
            if (node == null) {
                return null;
            }
            var id = $(node).attr('id');
            if (id == null) {
                return null;
            }
            return id.substring(this.options.itemPrefix.length);
        },

        /**
         * Find the parent node that should receive the event.
         *
         */
        _getTargetNode: function(node) {
            while (node) {
                var name = node.tagName;
                if (name) {
                    name = name.toUpperCase();
                    if (name != "EM" && name != "I" && name != "B" && name != "IMG" && name != "SPAN") {
                        if (node.id && node.id != "" && this.action[0] != node) {
                            return node;
                        }
                        if (name == 'A') {
                            return node;
                        }
                    }
                }
                if (node == this.element[0]) {
                    return null;
                }

                node = node.parentNode;
            }
            return null;
        },

        /**
         * Get the item list node that contains the inner element represented by <tt>node</tt>.
         * Returns null if the node element is not part of a list item component.
         */
        getTarget: function(node) {
            if (node == this.element[0]) {
                return null;
            }
            while (node) {
                var name = node.tagName;
                if (name) {
                    name = name.toUpperCase();
                    if (name == "DIV" || name == "DL") {
                        var id = node.id;
                        if (id && id.indexOf(this.options.itemPrefix) === 0) {
                            return node;
                        }
                    }
                }
                node = node.parentNode;
                if (node == this.element[0]) {
                    return null;
                }
            }
            /* $("#current").html(node.id); */
            return node;
        },

        _mouseOver: function(event) {
            var node = this.getTarget(event.target);
            if (node && this.currentNode != node) {
                /* $("#current").html("Mover " + node.id); */
                this.setActiveItem(node);
                if (this.action[0]) {
                    this.action.detach();
                    this.action.prependTo(this.activeItem);
                }
            }
            if (this.isActive == false) {
                this.isActive = true;
                this.element.addClass(this.options.activeListClass);
            }
        } ,

        _mouseOut: function(event) {
            if (!this.disableMouseover) {
                var node = event.target;
                while (node && node != document) {
                    if (node == this.activeItem) {
                        this.setActiveItem(null);
                        /* $("#current").html("Mouse out"); */
                        break;
                    } else {
                        if (node == this.element[0]) {
                            break;
                        }
                        node = node.parentNode;
                    }
                }
                if (node && node != document) {
                    this.isActive = false;
                    this.element.removeClass(this.options.activeListClass);
                }
            }
        },
        /**
         * Get the shopping category.
         */
        getCategoryId: function() {
            return $(this.element).attr("data-id");
        },

        /**
         * Get the URL to execute an AJAX operation on the given item.  Override this operation to customize
         * the URL.
         *
         * @param item the item
         * @param oid the item identifier
         * @param url the relative URL
         * @return the URL to invoke an AJAX operation on the given item
         */
        getOperationUrl: function(item, oid, url) {
            return url + oid;
        },
        enterEdit: function(event) {
            var node = this.element.find(".am-list");
            var catId = this.getCategoryId();
            $("#current").html("Enter edit");
            ASF.Update(this.element, "/am/shoplist/edit-category.html?id=" + catId, node);
        },

        /**
         * Enter delete mode for the current active element.
         * The 'deletingCss' is applied on the element being deleted.  The delete dialog box is opened
         * to confirm the deletion of our item.  The 'deletingCSS' is removed once the dialog box is closed.
         */
        enterDelete: function(event) {
            var item = this.activeItem;
            var id   = this.getSelectedId(item);
            if (id) {
                var url = this.getOperationUrl(item, id, this.options.deleteUrl);
                if (url) {
                    var css = this.options.deletingClass;

                    item.addClass(css);
                    ASF.OpenDialog(item, 'deleteDialog_' + id, url, {
                        close: function() {
                            item.removeClass(css);
                        }
                    });
                }
            }
            return false;
        },
        enterCreate: function(event) {

        },

        /**
         * Click action executed when one inner HTML element is clicked.
         *
         * @param event the event that was clicked
         */
        click: function(event) {
            var node = this._getTargetNode(event.target);
            if (node && this.currentNode != node) {

                if ($(node).hasClass("asf-edit")) {
                    this.enterEdit(event);
                } else if ($(node).hasClass("asf-delete")) {
                    this.enterDelete(event);

                } else if ($(node).hasClass("asf-editable")) {
                    if (! $(node).hasClass("asf-editing")) {
                        this.currentEdit = node;
                        $(node).addClass("asf-editing");
                        this.enterCreate(event);
                    }
                } else {
                    this.selectAction(node);
                }
            } else {
                var name = event.target.tagName;
                node = event.target;

                if ($(node).hasClass("asf-edit")) {
                    this.enterEdit(event);
                } else if ($(node).hasClass("asf-delete")) {
                    this.enterDelete(event);
                }

            }
            event.stopPropagation();
        },
        blur: function(event) {
            if (this.currentEdit) {
                this.currentEdit.remove();
                this.currentEdit = null;
            }
        },
        destroy: function() {
            this.element.removeClass( "ui-list" );
            $.Widget.prototype.destroy.apply( this, arguments );
        }

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


<commit_before>/*
Copyright (c) 2010, Geomatics and Cartographic Research Centre, Carleton
University
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 - Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
 - Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 - Neither the name of the Geomatics and Cartographic Research Centre,
   Carleton University nor the names of its contributors may be used to
   endorse or promote products derived from this software without specific
   prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

$Id: n2.couchMap.js 8437 2012-08-14 17:59:23Z jpfiset $
*/
;(function($n2){

// Localization
var _loc = function(str,args){ return $n2.loc(str,'nunaliit2-couch',args); };

/*
 * This function retained for backward compatibility
 */
function adjustDocument(doc) {

	$n2.couchDocument.adjustDocument(doc);
};

function isAdmin() {

	var admin = false;
	var sessionContext = $n2.couch.getSession().getContext();
	if( sessionContext
	 && sessionContext.roles ) {
		if( $n2.inArray('_admin',sessionContext.roles) !== -1 ) {
			admin = true;
		};
		if( $n2.inArray('administrator',sessionContext.roles) !== -1 ) {
			admin = true;
		};
		if( typeof(n2atlas) === 'object'
		 && typeof(n2atlas.name) === 'string' ) {
			var dbAdmin = n2atlas.name + '_administrator';
			if( $n2.inArray(dbAdmin,sessionContext.roles) !== -1 ) {
				admin = true;
			};
		};
	};

	return admin;
};

function canEditDoc(data) {

	if( isAdmin() ) {
		return true;
	};

	var userName = null;
	var sessionContext = $n2.couch.getSession().getContext();
	if( sessionContext ) {
		userName = sessionContext.name;
	};
	var roleMap = {};
	for(var i=0,e=sessionContext.roles.length; i<e; ++i){
		roleMap[sessionContext.roles[i]] = true;
	};

	// On an atlas with a submission database, any user can submit
	// a change to any document
	if( typeof(n2atlas) === 'object'
	 && n2atlas.submissionDbEnabled) {
		return true;
	};

	// If a document is on a layer, then one must have the roles
	// associated with all layers. If a document is not on a layer,
	// then the roles are not relevant.
	var documentIsControlledLayer = false;
	if( data.nunaliit_layers && data.nunaliit_layers.length ){
		for(var i=0,e=data.nunaliit_layers.length; i<e; ++i){
			var layerId = data.nunaliit_layers[i];
			if( 'public' === layerId ){
				// Public layer. Ignore
			} else {
				documentIsControlledLayer = true;

				var requiredRole = null;
				if( typeof(n2atlas) === 'object'
				 && typeof(n2atlas.name) === 'string' ) {
					requiredRole = n2atlas.name + '_layer_' + layerId;
				} else {
					requiredRole = 'layer_' + layerId;
				};

				if( !roleMap[requiredRole] ){
					return false;
				};
			};
		};

		if( documentIsControlledLayer ){
			// At this point, there is at least one controlled layer
			// and we have the roles for all of them.
			return true;
		};
	};

	// If a document is not on a controlled layer, then the creator of the
	// document can edit it
	if( data.nunaliit_created
	 && data.nunaliit_created.nunaliit_type
	 && data.nunaliit_created.nunaliit_type === 'actionstamp'
	 && data.nunaliit_created.name === userName
	 ) {
		return true;
	};

	// By default, can not edit a document
	return false;
};

function canDeleteDoc(data) {

	// At this time, if one can edit a document, one can delete it
	return canEditDoc(data);
};

function documentContainsMedia(doc){
	var containsMedia = false;

	if( doc.nunaliit_attachments
	 && doc.nunaliit_attachments.files
	 ) {
		for(var attName in doc.nunaliit_attachments.files){
			containsMedia = true;
		};
	};

	return containsMedia;
};

function documentContainsApprovedMedia(doc){
	var containsApprovedMedia = false;

	if( doc.nunaliit_attachments
	 && doc.nunaliit_attachments.files
	 ) {
		for(var attName in doc.nunaliit_attachments.files){
			var att = doc.nunaliit_attachments.files[attName];

			if( att.status === 'approved'
			 || att.status === 'attached' ) {
				containsApprovedMedia = true;
			};
		};
	};

	return containsApprovedMedia;
};

function documentContainsDeniedMedia(doc){
	var containsDeniedMedia = false;

	if( doc.nunaliit_attachments
	 && doc.nunaliit_attachments.files
	 ) {
		for(var attName in doc.nunaliit_attachments.files){
			var att = doc.nunaliit_attachments.files[attName];

			if( att.status === 'denied' ) {
				containsDeniedMedia = true;
			};
		};
	};

	return containsDeniedMedia;
};

// Exports
$n2.couchMap = {
	adjustDocument: adjustDocument
	,isAdmin: isAdmin
	,canEditDoc: canEditDoc
	,canDeleteDoc: canDeleteDoc
	,documentContainsMedia: documentContainsMedia
	,documentContainsApprovedMedia: documentContainsApprovedMedia
	,documentContainsDeniedMedia: documentContainsDeniedMedia
};

})(nunaliit2);
<commit_msg>nunaliit2-js: An atlas with a submission database should allow any user to edit any document.   Issue #344<commit_after>/*
Copyright (c) 2010, Geomatics and Cartographic Research Centre, Carleton
University
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 - Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
 - Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 - Neither the name of the Geomatics and Cartographic Research Centre,
   Carleton University nor the names of its contributors may be used to
   endorse or promote products derived from this software without specific
   prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

$Id: n2.couchMap.js 8437 2012-08-14 17:59:23Z jpfiset $
*/
;(function($n2){

// Localization
var _loc = function(str,args){ return $n2.loc(str,'nunaliit2-couch',args); };

/*
 * This function retained for backward compatibility
 */
function adjustDocument(doc) {

	$n2.couchDocument.adjustDocument(doc);
};

function isAdmin() {

	var admin = false;
	var sessionContext = $n2.couch.getSession().getContext();
	if( sessionContext
	 && sessionContext.roles ) {
		if( $n2.inArray('_admin',sessionContext.roles) !== -1 ) {
			admin = true;
		};
		if( $n2.inArray('administrator',sessionContext.roles) !== -1 ) {
			admin = true;
		};
		if( typeof(n2atlas) === 'object'
		 && typeof(n2atlas.name) === 'string' ) {
			var dbAdmin = n2atlas.name + '_administrator';
			if( $n2.inArray(dbAdmin,sessionContext.roles) !== -1 ) {
				admin = true;
			};
		};
	};

	return admin;
};

function canEditDoc(data) {

	if( isAdmin() ) {
		return true;
	};

	var userName = null;
	var sessionContext = $n2.couch.getSession().getContext();
	if( sessionContext ) {
		userName = sessionContext.name;
	};
	var roleMap = {};
	for(var i=0,e=sessionContext.roles.length; i<e; ++i){
		roleMap[sessionContext.roles[i]] = true;
	};

	// On an atlas with a submission database, any user can submit
	// a change to any document
	if( typeof(n2atlas) === 'object'
	 && n2atlas.submissionDbEnabled
	 && userName ) {
		return true;
	};

	// If a document is on a layer, then one must have the roles
	// associated with all layers. If a document is not on a layer,
	// then the roles are not relevant.
	var documentIsControlledLayer = false;
	if( data.nunaliit_layers && data.nunaliit_layers.length ){
		for(var i=0,e=data.nunaliit_layers.length; i<e; ++i){
			var layerId = data.nunaliit_layers[i];
			if( 'public' === layerId ){
				// Public layer. Ignore
			} else {
				documentIsControlledLayer = true;

				var requiredRole = null;
				if( typeof(n2atlas) === 'object'
				 && typeof(n2atlas.name) === 'string' ) {
					requiredRole = n2atlas.name + '_layer_' + layerId;
				} else {
					requiredRole = 'layer_' + layerId;
				};

				if( !roleMap[requiredRole] ){
					return false;
				};
			};
		};

		if( documentIsControlledLayer ){
			// At this point, there is at least one controlled layer
			// and we have the roles for all of them.
			return true;
		};
	};

	// If a document is not on a controlled layer, then the creator of the
	// document can edit it
	if( data.nunaliit_created
	 && data.nunaliit_created.nunaliit_type
	 && data.nunaliit_created.nunaliit_type === 'actionstamp'
	 && data.nunaliit_created.name === userName
	 ) {
		return true;
	};

	// By default, can not edit a document
	return false;
};

function canDeleteDoc(data) {

	// At this time, if one can edit a document, one can delete it
	return canEditDoc(data);
};

function documentContainsMedia(doc){
	var containsMedia = false;

	if( doc.nunaliit_attachments
	 && doc.nunaliit_attachments.files
	 ) {
		for(var attName in doc.nunaliit_attachments.files){
			containsMedia = true;
		};
	};

	return containsMedia;
};

function documentContainsApprovedMedia(doc){
	var containsApprovedMedia = false;

	if( doc.nunaliit_attachments
	 && doc.nunaliit_attachments.files
	 ) {
		for(var attName in doc.nunaliit_attachments.files){
			var att = doc.nunaliit_attachments.files[attName];

			if( att.status === 'approved'
			 || att.status === 'attached' ) {
				containsApprovedMedia = true;
			};
		};
	};

	return containsApprovedMedia;
};

function documentContainsDeniedMedia(doc){
	var containsDeniedMedia = false;

	if( doc.nunaliit_attachments
	 && doc.nunaliit_attachments.files
	 ) {
		for(var attName in doc.nunaliit_attachments.files){
			var att = doc.nunaliit_attachments.files[attName];

			if( att.status === 'denied' ) {
				containsDeniedMedia = true;
			};
		};
	};

	return containsDeniedMedia;
};

// Exports
$n2.couchMap = {
	adjustDocument: adjustDocument
	,isAdmin: isAdmin
	,canEditDoc: canEditDoc
	,canDeleteDoc: canDeleteDoc
	,documentContainsMedia: documentContainsMedia
	,documentContainsApprovedMedia: documentContainsApprovedMedia
	,documentContainsDeniedMedia: documentContainsDeniedMedia
};

})(nunaliit2);
<|endoftext|>


<commit_before>/*global define, CKEDITOR */
/*jslint browser: true */

define(["ckeditor"], function () {
    "use strict";

    //open a simpler link dialog
    CKEDITOR.on("dialogDefinition", function (ev) {
        var dialogName = ev.data.name,
            dialogDefinition = ev.data.definition,
            infoTab;

        if (dialogName === "link") {
            dialogDefinition.removeContents("target");
            dialogDefinition.removeContents("advanced");

            infoTab = dialogDefinition.getContents("info");

            infoTab.remove("linkType");
            infoTab.remove("protocol");
        }
    });

    var config = {};

    config.customConfig = "";
    config.language = "pt_BR";
    config.height = "400px";
    config.allowedContent = "p b i br u s; a[!href]";
    config.entities = false;
    config.basicEntities = true;
    config.entities_greek = false;
    config.entities_latin = false;
    config.entities_additional = "";
    config.htmlEncodeOutput = false;
    config.removeButtons = "Anchor,Subscript,Superscript";

    config.toolbar = [
        {
            name: 'basicstyles',
            groups: ['basicstyles', 'cleanup' ],
            items: ['Bold', 'Italic', 'Underline', 'Strike', '-']
        },
        {
            name: 'links',
            items: [ 'Link', 'Unlink']
        },
        {
            name: 'clipboard',
            items : [ 'Undo', 'Redo' ]
        }
    ];

    config.toolbarGroups = [
        {
            name: 'basicstyles',
            groups: [ 'basicstyles', 'cleanup' ]
        },
        {
            name: 'links'
        }
    ];

    return config;
});
<commit_msg>improve ckeditor-config.js code style<commit_after>/*global define, CKEDITOR */
/*jslint browser: true */

define(['ckeditor'], function () {
    'use strict';

    //open a simpler link dialog
    CKEDITOR.on('dialogDefinition', function (ev) {
        var dialogName = ev.data.name,
            dialogDefinition = ev.data.definition,
            infoTab;

        if (dialogName === 'link') {
            dialogDefinition.removeContents('target');
            dialogDefinition.removeContents('advanced');

            infoTab = dialogDefinition.getContents('info');

            infoTab.remove('linkType');
            infoTab.remove('protocol');
        }
    });

    var config = {};

    config.customConfig = '';
    config.language = 'pt_BR';
    config.height = '400px';
    config.allowedContent = 'p b i br u s; a[!href]';
    config.entities = false;
    config.basicEntities = true;
    config.entities_greek = false;
    config.entities_latin = false;
    config.entities_additional = '';
    config.htmlEncodeOutput = false;
    config.removeButtons = 'Anchor,Subscript,Superscript';

    config.toolbar = [
        {
            name: 'basicstyles',
            groups: ['basicstyles', 'cleanup'],
            items: ['Bold', 'Italic', 'Underline', 'Strike', '-']
        },
        {
            name: 'links',
            items: ['Link', 'Unlink']
        },
        {
            name: 'clipboard',
            items: ['Undo', 'Redo']
        }
    ];

    config.toolbarGroups = [
        {
            name: 'basicstyles',
            groups: ['basicstyles', 'cleanup']
        },
        {
            name: 'links'
        }
    ];

    return config;
});
<|endoftext|>


<commit_before>// MIT License:
//
// Copyright (c) 2010-2012, Joe Walnes
//
// 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.

/**
 * This behaves like a WebSocket in every way, except if it fails to connect,
 * or it gets disconnected, it will repeatedly poll until it successfully connects
 * again.
 *
 * It is API compatible, so when you have:
 *   ws = new WebSocket('ws://....');
 * you can replace with:
 *   ws = new ReconnectingWebSocket('ws://....');
 *
 * The event stream will typically look like:
 *  onconnecting
 *  onopen
 *  onmessage
 *  onmessage
 *  onclose // lost connection
 *  onconnecting
 *  onopen  // sometime later...
 *  onmessage
 *  onmessage
 *  etc...
 *
 * It is API compatible with the standard WebSocket API, apart from the following members:
 *
 * - `addEventListener`, `addEventListener`, `dispatchEvent`
 *   (ReconnectingWebSocket is not an EventTarget)
 * - `bufferedAmount`
 * - `extensions`
 * - `binaryType`
 * - `protocol`
 *
 * Latest version: https://github.com/joewalnes/reconnecting-websocket/
 * - Joe Walnes
 */
(function (global, factory) {
    if (typeof define === 'function' && define.amd) {
        define([], factory);
    } else if (typeof module !== 'undefined' && module.exports){
        module.exports = factory();
    } else {
        global.ReconnectingWebSocket = factory();
    }
})(this, function () {

    function ReconnectingWebSocket(url, protocols) {
        // These can be altered by calling code.
        this.debug = false;
        this.reconnectInterval = 1000;
        this.reconnectDecay = 1.5;
        this.reconnectAttempts = 0;
        this.timeoutInterval = 2000;

        var self = this;
        var ws;
        var forcedClose = false;
        var timedOut = false;

        this.url = url;
        this.readyState = WebSocket.CONNECTING;

        this.onopen = function(event) {
        };

        this.onclose = function(event) {
        };

        this.onconnecting = function(event) {
        };

        this.onmessage = function(event) {
        };

        this.onerror = function(event) {
        };

        function connect(reconnectAttempt) {
            ws = new WebSocket(url, protocols || []);

            if(!reconnectAttempt)
                self.onconnecting();

            if (self.debug || ReconnectingWebSocket.debugAll) {
                console.debug('ReconnectingWebSocket', 'attempt-connect', url);
            }

            var localWs = ws;
            var timeout = setTimeout(function() {
                if (self.debug || ReconnectingWebSocket.debugAll) {
                    console.debug('ReconnectingWebSocket', 'connection-timeout', url);
                }
                timedOut = true;
                localWs.close();
                timedOut = false;
            }, self.timeoutInterval);

            ws.onopen = function(event) {
                clearTimeout(timeout);
                if (self.debug || ReconnectingWebSocket.debugAll) {
                    console.debug('ReconnectingWebSocket', 'onopen', url);
                }
                self.readyState = WebSocket.OPEN;
                reconnectAttempt = false;
                self.reconnectAttempts = 0;
                self.onopen(event);
            };

            ws.onclose = function(event) {
                clearTimeout(timeout);
                ws = null;
                if (forcedClose) {
                    self.readyState = WebSocket.CLOSED;
                    self.onclose(event);
                } else {
                    self.readyState = WebSocket.CONNECTING;
                    self.onconnecting();
                    if (!reconnectAttempt && !timedOut) {
                        if (self.debug || ReconnectingWebSocket.debugAll) {
                            console.debug('ReconnectingWebSocket', 'onclose', url);
                        }
                        self.onclose(event);
                    }
                    setTimeout(function() {
                        self.reconnectAttempts++;
                        connect(true);
                    }, self.reconnectInterval * Math.pow(self.reconnectDecay, self.reconnectAttempts));
                }
            };
            ws.onmessage = function(event) {
                if (self.debug || ReconnectingWebSocket.debugAll) {
                    console.debug('ReconnectingWebSocket', 'onmessage', url, event.data);
                }
                self.onmessage(event);
            };
            ws.onerror = function(event) {
                if (self.debug || ReconnectingWebSocket.debugAll) {
                    console.debug('ReconnectingWebSocket', 'onerror', url, event);
                }
                self.onerror(event);
            };
        }
        connect(false);

        this.send = function(data) {
            if (ws) {
                if (self.debug || ReconnectingWebSocket.debugAll) {
                    console.debug('ReconnectingWebSocket', 'send', url, data);
                }
                return ws.send(data);
            } else {
                throw 'INVALID_STATE_ERR : Pausing to reconnect websocket';
            }
        };

        this.close = function(code, reason) {
            forcedClose = true;
            if (ws) {
                ws.close(code, reason);
            }
        };

        /**
         * Additional public API method to refresh the connection if still open (close, re-open).
         * For example, if the app suspects bad data / missed heart beats, it can try to refresh.
         */
        this.refresh = function() {
            if (ws) {
                ws.close();
            }
        };
    }

    /**
     * Setting this to true is the equivalent of setting all instances of ReconnectingWebSocket.debug to true.
     */
    ReconnectingWebSocket.debugAll = false;

    ReconnectingWebSocket.CONNECTING = WebSocket.CONNECTING;
    ReconnectingWebSocket.OPEN = WebSocket.OPEN;
    ReconnectingWebSocket.CLOSING = WebSocket.CLOSING;
    ReconnectingWebSocket.CLOSED = WebSocket.CLOSED;

    return ReconnectingWebSocket;
});
<commit_msg>Support the `protocol` property.<commit_after>// MIT License:
//
// Copyright (c) 2010-2012, Joe Walnes
//
// 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.

/**
 * This behaves like a WebSocket in every way, except if it fails to connect,
 * or it gets disconnected, it will repeatedly poll until it successfully connects
 * again.
 *
 * It is API compatible, so when you have:
 *   ws = new WebSocket('ws://....');
 * you can replace with:
 *   ws = new ReconnectingWebSocket('ws://....');
 *
 * The event stream will typically look like:
 *  onconnecting
 *  onopen
 *  onmessage
 *  onmessage
 *  onclose // lost connection
 *  onconnecting
 *  onopen  // sometime later...
 *  onmessage
 *  onmessage
 *  etc...
 *
 * It is API compatible with the standard WebSocket API, apart from the following members:
 *
 * - `addEventListener`, `addEventListener`, `dispatchEvent`
 *   (ReconnectingWebSocket is not an EventTarget)
 * - `bufferedAmount`
 * - `extensions`
 * - `binaryType`
 *
 * Latest version: https://github.com/joewalnes/reconnecting-websocket/
 * - Joe Walnes
 */
(function (global, factory) {
    if (typeof define === 'function' && define.amd) {
        define([], factory);
    } else if (typeof module !== 'undefined' && module.exports){
        module.exports = factory();
    } else {
        global.ReconnectingWebSocket = factory();
    }
})(this, function () {

    function ReconnectingWebSocket(url, protocols) {
        // These can be altered by calling code.
        this.debug = false;
        this.reconnectInterval = 1000;
        this.reconnectDecay = 1.5;
        this.reconnectAttempts = 0;
        this.timeoutInterval = 2000;

        var self = this;
        var ws;
        var forcedClose = false;
        var timedOut = false;

        this.url = url;
        this.readyState = WebSocket.CONNECTING;
        this.protocol = null;

        this.onopen = function(event) {
        };

        this.onclose = function(event) {
        };

        this.onconnecting = function(event) {
        };

        this.onmessage = function(event) {
        };

        this.onerror = function(event) {
        };

        function connect(reconnectAttempt) {
            ws = new WebSocket(url, protocols || []);

            if(!reconnectAttempt)
                self.onconnecting();

            if (self.debug || ReconnectingWebSocket.debugAll) {
                console.debug('ReconnectingWebSocket', 'attempt-connect', url);
            }

            var localWs = ws;
            var timeout = setTimeout(function() {
                if (self.debug || ReconnectingWebSocket.debugAll) {
                    console.debug('ReconnectingWebSocket', 'connection-timeout', url);
                }
                timedOut = true;
                localWs.close();
                timedOut = false;
            }, self.timeoutInterval);

            ws.onopen = function(event) {
                clearTimeout(timeout);
                if (self.debug || ReconnectingWebSocket.debugAll) {
                    console.debug('ReconnectingWebSocket', 'onopen', url);
                }
                self.protocol = ws.protocol;
                self.readyState = WebSocket.OPEN;
                reconnectAttempt = false;
                self.reconnectAttempts = 0;
                self.onopen(event);
            };

            ws.onclose = function(event) {
                clearTimeout(timeout);
                ws = null;
                if (forcedClose) {
                    self.readyState = WebSocket.CLOSED;
                    self.onclose(event);
                } else {
                    self.readyState = WebSocket.CONNECTING;
                    self.onconnecting();
                    if (!reconnectAttempt && !timedOut) {
                        if (self.debug || ReconnectingWebSocket.debugAll) {
                            console.debug('ReconnectingWebSocket', 'onclose', url);
                        }
                        self.onclose(event);
                    }
                    setTimeout(function() {
                        self.reconnectAttempts++;
                        connect(true);
                    }, self.reconnectInterval * Math.pow(self.reconnectDecay, self.reconnectAttempts));
                }
            };
            ws.onmessage = function(event) {
                if (self.debug || ReconnectingWebSocket.debugAll) {
                    console.debug('ReconnectingWebSocket', 'onmessage', url, event.data);
                }
                self.onmessage(event);
            };
            ws.onerror = function(event) {
                if (self.debug || ReconnectingWebSocket.debugAll) {
                    console.debug('ReconnectingWebSocket', 'onerror', url, event);
                }
                self.onerror(event);
            };
        }
        connect(false);

        this.send = function(data) {
            if (ws) {
                if (self.debug || ReconnectingWebSocket.debugAll) {
                    console.debug('ReconnectingWebSocket', 'send', url, data);
                }
                return ws.send(data);
            } else {
                throw 'INVALID_STATE_ERR : Pausing to reconnect websocket';
            }
        };

        this.close = function(code, reason) {
            forcedClose = true;
            if (ws) {
                ws.close(code, reason);
            }
        };

        /**
         * Additional public API method to refresh the connection if still open (close, re-open).
         * For example, if the app suspects bad data / missed heart beats, it can try to refresh.
         */
        this.refresh = function() {
            if (ws) {
                ws.close();
            }
        };
    }

    /**
     * Setting this to true is the equivalent of setting all instances of ReconnectingWebSocket.debug to true.
     */
    ReconnectingWebSocket.debugAll = false;

    ReconnectingWebSocket.CONNECTING = WebSocket.CONNECTING;
    ReconnectingWebSocket.OPEN = WebSocket.OPEN;
    ReconnectingWebSocket.CLOSING = WebSocket.CLOSING;
    ReconnectingWebSocket.CLOSED = WebSocket.CLOSED;

    return ReconnectingWebSocket;
});
<|endoftext|>


<commit_before>var _ = require('underscore');
var Promise = require("bluebird");
var events = require('events');
var EventEmitter = events.EventEmitter;

module.exports = OperationPromise;

function OperationPromise(queueClient, onCompleteFn) {
    var self,
        emitter = new EventEmitter(),
        emitterMethods = ['on', 'emit'];

    function init () {
        self = new Promise(function (resolve, reject) {
            emitter.on('complete', function (result) {
                resolve(result);
            });

            emitter.on('error', function (error) {
                reject(error);
            });
        });
    }

    init ();

    _.each(emitterMethods, function(method) {
        self[method] = _.bind(emitter[method], emitter);
    });

    self.resolveWhenJobCompleted = function(response) {
        self.emit('job-queue', response);

        pingStatus(self, self.mixinStatusSupport(response));

        return self;
    };

    self.processErrors = function(response) {
        return self;
    };

    function pingStatus(emitter, response) {
        queueClient
            .getStatus(response.findStatusId())
            .then(function (response) {
                return response.status;
            })
            .then(function (status) {
                if (status === 'succeeded') {
                    if (onCompleteFn) {
                        onCompleteFn(response.findSelfId()).then(function (result) {
                            emitter.emit('complete', result);
                        });
                    } else {
                        emitter.emit('complete', response);
                    }
                } else if (!status || status === 'failed' || status === 'unknown') {
                    emitter.emit('error', {status: status, job: response});
                } else {
                    setTimeout(_.partial(pingStatus, emitter, response), 5000);
                }
            });

        return response;
    }

    self.mixinStatusSupport = function (data) {
        return _.extend(Object.create(new StatusResult()), data);
    };

    return self;
}

function StatusResult () {

    this.findStatusId = function () {
        return _.findWhere(this.links, {rel: "status"}).id;
    };

    this.findSelfId = function () {
        return _.findWhere(this.links, {rel: "self"}).id;
    };

}<commit_msg>#12 DataCenters search<commit_after>var _ = require('underscore');
var Promise = require("bluebird");
var events = require('events');
var EventEmitter = events.EventEmitter;

module.exports = OperationPromise;

function OperationPromise(queueClient, onCompleteFn) {
    var self,
        emitter = new EventEmitter(),
        emitterMethods = ['on', 'emit'];

    function init () {
        self = new Promise(function (resolve, reject) {
            emitter.on('complete', function (result) {
                resolve(result);
            });

            emitter.on('error', function (error) {
                reject(error);
            });
        });
    }

    init ();

    _.each(emitterMethods, function(method) {
        self[method] = _.bind(emitter[method], emitter);
    });

    self.resolveWhenJobCompleted = function(response) {
        self.emit('job-queue', response);

        pingStatus(self, self.mixinStatusSupport(response));

        return self;
    };

    self.processErrors = function(response) {
        return self;
    };

    function pingStatus(emitter, response) {
        queueClient
            .getStatus(response.findStatusId())
            .then(function (response) {
                return response.status;
            })
            .then(function (status) {
                console.log(response);

                if (status === 'succeeded') {
                    if (onCompleteFn) {
                        onCompleteFn(response.findSelfId()).then(function (result) {
                            emitter.emit('complete', result);
                        });
                    } else {
                        emitter.emit('complete', response);
                    }
                } else if (!status || status === 'failed' || status === 'unknown') {
                    emitter.emit('error', {status: status, job: response});
                } else {
                    setTimeout(_.partial(pingStatus, emitter, response), 5000);
                }
            });

        return response;
    }

    self.mixinStatusSupport = function (data) {
        return _.extend(Object.create(new StatusResult()), data);
    };

    return self;
}

function StatusResult () {

    this.findStatusId = function () {
        return _.findWhere(this.links, {rel: "status"}).id;
    };

    this.findSelfId = function () {
        return _.findWhere(this.links, {rel: "self"}).id;
    };

}<|endoftext|>