<commit_before>var dashes = '\n------------------------------------------------\n';
var utils = require('keystone-utils');

module.exports = function bindErrorHandlers (keystone, app) {

	// Handle 404 (no route matched) errors
	var default404Handler = function (req, res) {
		if (req.headers.accept === 'application/json') {
			return res.status(404).json({ error: 'not found' });
		}
		res.status(404).send(keystone.wrapHTMLError('Sorry, no page could be found at this address (404)'));
	};

	app.use(function (req, res, next) {
		var err404 = keystone.get('404');
		if (err404) {
			try {
				if (typeof err404 === 'function') {
					return err404(req, res, next);
				} else if (typeof err404 === 'string') {
					if (req.headers.accept === 'application/json') {
						return res.status(404).json({ error: 'not found' });
					}
					return res.status(404).render(err404);
				} else {
					if (keystone.get('logger')) {
						console.log(dashes + 'Error handling 404 (not found): Invalid type (' + (typeof err404) + ') for 404 setting.' + dashes);
					}
					return default404Handler(req, res, next);
				}
			} catch (e) {
				if (keystone.get('logger')) {
					console.log(dashes + 'Error handling 404 (not found):');
					console.log(e);
					console.log(dashes);
				}
				return default404Handler(req, res, next);
			}
		} else {
			return default404Handler(req, res, next);
		}
	});

	// Handle other errors

	var default500Handler = function (err, req, res, next) { // eslint-disable-line no-unused-vars

		if (keystone.get('logger')) {
			if (err instanceof Error) {
				console.log((err.type ? err.type + ' ' : '') + 'Error thrown for request: ' + req.url);
			} else {
				console.log('Error thrown for request: ' + req.url);
			}
			console.log(err.stack || err);
		}

		var msg = '';

		if (keystone.get('env') === 'development') {

			if (err instanceof Error) {
				if (err.type) {
					msg += '
' + err.type + '
';
				}
				msg += utils.textToHTML(err.message);
			} else if (typeof err === 'object') {
				msg += '' + JSON.stringify(err) + '';
			} else if (err) {
				msg += err;
			}
		}

		res.status(500).send(keystone.wrapHTMLError('Sorry, an error occurred loading the page (500)', msg));
	};

	app.use(function (err, req, res, next) {

		var err500 = keystone.get('500');

		if (err500) {
			try {
				if (typeof err500 === 'function') {
					err500(err, req, res, next);
				} else if (typeof err500 === 'string') {
					res.locals.err = err;
					res.status(500).render(err500);
				} else {
					if (keystone.get('logger')) {
						console.log(dashes + 'Error handling 500 (error): Invalid type (' + (typeof err500) + ') for 500 setting.' + dashes);
					}
					default500Handler(err, req, res, next);
				}
			} catch (e) {
				if (keystone.get('logger')) {
					console.log(dashes + 'Error handling 500 (error):');
					console.log(e);
					console.log(dashes);
				}
				default500Handler(err, req, res, next);
			}
		} else {
			default500Handler(err, req, res, next);
		}
	});
};
<commit_msg>Returning valid json from default 500 handlers, ref #2247<commit_after>var dashes = '\n------------------------------------------------\n';
var utils = require('keystone-utils');

module.exports = function bindErrorHandlers (keystone, app) {

	// Handle 404 (no route matched) errors
	var default404Handler = function (req, res) {
		if (req.headers.accept === 'application/json') {
			return res.status(404).json({ error: 'not found' });
		}
		res.status(404).send(keystone.wrapHTMLError('Sorry, no page could be found at this address (404)'));
	};

	app.use(function (req, res, next) {
		var err404 = keystone.get('404');
		if (err404) {
			try {
				if (typeof err404 === 'function') {
					return err404(req, res, next);
				} else if (typeof err404 === 'string') {
					if (req.headers.accept === 'application/json') {
						return res.status(404).json({ error: 'not found' });
					}
					return res.status(404).render(err404);
				} else {
					if (keystone.get('logger')) {
						console.log(dashes + 'Error handling 404 (not found): Invalid type (' + (typeof err404) + ') for 404 setting.' + dashes);
					}
					return default404Handler(req, res, next);
				}
			} catch (e) {
				if (keystone.get('logger')) {
					console.log(dashes + 'Error handling 404 (not found):');
					console.log(e);
					console.log(dashes);
				}
				return default404Handler(req, res, next);
			}
		} else {
			return default404Handler(req, res, next);
		}
	});

	// Handle other errors

	var default500Handler = function (err, req, res, next) { // eslint-disable-line no-unused-vars
		if (keystone.get('logger')) {
			if (err instanceof Error) {
				console.log((err.type ? err.type + ' ' : '') + 'Error thrown for request: ' + req.url);
			} else {
				console.log('Error thrown for request: ' + req.url);
			}
			console.log(err.stack || err);
		}
		// TODO: Take into account dev settings to send a more useful JSON error
		if (req.headers.accept === 'application/json') {
			return res.status(500).json({ error: 'unknown error' });
		}
		var msg = '';
		if (keystone.get('env') === 'development') {
			if (err instanceof Error) {
				if (err.type) {
					msg += '
' + err.type + '
';
				}
				msg += utils.textToHTML(err.message);
			} else if (typeof err === 'object') {
				msg += '' + JSON.stringify(err) + '';
			} else if (err) {
				msg += err;
			}
		}
		return res.status(500).send(keystone.wrapHTMLError('Sorry, an error occurred loading the page (500)', msg));
	};

	app.use(function (err, req, res, next) {
		var err500 = keystone.get('500');
		if (err500) {
			try {
				if (typeof err500 === 'function') {
					return err500(err, req, res, next);
				} else if (typeof err500 === 'string') {
					if (req.headers.accept === 'application/json') {
						return res.status(500).json({ error: 'unknown error' });
					}
					res.locals.err = err;
					return res.status(500).render(err500);
				} else {
					if (keystone.get('logger')) {
						console.log(dashes + 'Error handling 500 (error): Invalid type (' + (typeof err500) + ') for 500 setting.' + dashes);
					}
					return default500Handler(err, req, res, next);
				}
			} catch (e) {
				if (keystone.get('logger')) {
					console.log(dashes + 'Error handling 500 (error):');
					console.log(e);
					console.log(dashes);
				}
				return default500Handler(err, req, res, next);
			}
		} else {
			return default500Handler(err, req, res, next);
		}
	});
};
<|endoftext|>


<commit_before>import { Observable } from 'rx';
import debugFactory from 'debug';

const debug = debugFactory('freecc:user:remote');

function destroyAllRelated(id, Model) {
  return Observable.fromNodeCallback(
    Model.destroyAll,
    Model
  )({ userId: id });
}

module.exports = function(app) {
  var User = app.models.User;
  var UserIdentity = app.models.UserIdentity;
  var UserCredential = app.models.UserCredential;
  var Email = app.models.Email;
  User.observe('before delete', function(ctx, next) {
    debug('removing user', ctx.where);
    var id = ctx.where && ctx.where.id ? ctx.where.id : null;
    if (!id) {
      return next();
    }
    Observable.combineLatest(
      destroyAllRelated(id, UserIdentity),
      destroyAllRelated(id, UserCredential),
      function(identData, credData) {
        return {
          identData: identData,
          credData: credData
        };
      }
    ).subscribe(
      function(data) {
        debug('deleted', data);
      },
      function(err) {
        debug('error deleting user %s stuff', id, err);
        next(err);
      },
      function() {
        debug('user stuff deleted for user %s', id);
        next();
      }
    );
  });

  // set email varified false on user email signup
  // should not be set with oauth signin methods
  User.beforeRemote('create', function(ctx, user, next) {
    var body = ctx.req.body;
    if (body) {
      body.emailVerified = false;
    }
    next();
  });

  // send welcome email to new camper
  User.afterRemote('create', function(ctx, user, next) {
    debug('user created, sending email');
    if (!user.email) { return next(); }

    var mailOptions = {
      type: 'email',
      to: user.email,
      from: 'Team@freecodecamp.com',
      subject: 'Welcome to Free Code Camp!',
      redirect: '/',
      text: [
        'Greetings from San Francisco!\n\n',
        'Thank you for joining our community.\n',
        'Feel free to email us at this address if you have ',
        'any questions about Free Code Camp.\n',
        'And if you have a moment, check out our blog: ',
        'medium.freecodecamp.com.\n\n',
        'Good luck with the challenges!\n\n',
        '- the Free Code Camp Team'
      ].join('')
    };

    debug('sending welcome email');
    Email.send(mailOptions, function(err) {
      if (err) { return next(err); }
      ctx.req.logIn(user, function(err) {
        if (err) { return next(err); }

        ctx.req.flash('success', {
          msg: [ "Welcome to Free Code Camp! We've created your account." ]
        });
        ctx.res.redirect('/');
      });
    });
  });
};
<commit_msg>Fix user redirect on email account creation<commit_after>import { Observable } from 'rx';
import debugFactory from 'debug';

const debug = debugFactory('freecc:user:remote');

function destroyAllRelated(id, Model) {
  return Observable.fromNodeCallback(
    Model.destroyAll,
    Model
  )({ userId: id });
}

module.exports = function(app) {
  var User = app.models.User;
  var UserIdentity = app.models.UserIdentity;
  var UserCredential = app.models.UserCredential;
  var Email = app.models.Email;
  User.observe('before delete', function(ctx, next) {
    debug('removing user', ctx.where);
    var id = ctx.where && ctx.where.id ? ctx.where.id : null;
    if (!id) {
      return next();
    }
    Observable.combineLatest(
      destroyAllRelated(id, UserIdentity),
      destroyAllRelated(id, UserCredential),
      function(identData, credData) {
        return {
          identData: identData,
          credData: credData
        };
      }
    ).subscribe(
      function(data) {
        debug('deleted', data);
      },
      function(err) {
        debug('error deleting user %s stuff', id, err);
        next(err);
      },
      function() {
        debug('user stuff deleted for user %s', id);
        next();
      }
    );
  });

  // set email varified false on user email signup
  // should not be set with oauth signin methods
  User.beforeRemote('create', function(ctx, user, next) {
    var body = ctx.req.body;
    if (body) {
      body.emailVerified = false;
    }
    next();
  });

  // send welcome email to new camper
  User.afterRemote('create', function({ req, res }, user, next) {
    debug('user created, sending email');
    if (!user.email) { return next(); }
    const redirect = req.session && req.session.returnTo ?
      req.session.returnTo :
      '/';

    var mailOptions = {
      type: 'email',
      to: user.email,
      from: 'Team@freecodecamp.com',
      subject: 'Welcome to Free Code Camp!',
      redirect: '/',
      text: [
        'Greetings from San Francisco!\n\n',
        'Thank you for joining our community.\n',
        'Feel free to email us at this address if you have ',
        'any questions about Free Code Camp.\n',
        'And if you have a moment, check out our blog: ',
        'medium.freecodecamp.com.\n\n',
        'Good luck with the challenges!\n\n',
        '- the Free Code Camp Team'
      ].join('')
    };

    debug('sending welcome email');
    Email.send(mailOptions, function(err) {
      if (err) { return next(err); }
      req.logIn(user, function(err) {
        if (err) { return next(err); }

        req.flash('success', {
          msg: [ "Welcome to Free Code Camp! We've created your account." ]
        });
        res.redirect(redirect);
      });
    });
  });
};
<|endoftext|>


<commit_before>import {assert} from '@webex/test-helper-chai';
import {ServiceCatalogs, serviceConstants} from '@webex/webex-core';

const {SERVICE_CATALOGS, SERVICE_CATALOGS_ENUM_TYPES: SCET} = serviceConstants;

describe('webex-core', () => {
  describe('ServiceCatalogs', () => {
    let fixture;
    let fixtureHosts;
    let serviceCatalogs;

    before('generate fixture', () => {
      fixture = {
        serviceLinks: {
          'example-service-a-name': 'http://example-service-a.com/',
          'example-service-b-name': 'http://example-service-b.com/'
        },
        hostCatalog: {
          'example-service-a': [
            {
              host: 'example-service-a-h1.com',
              id: 'head:group:cluster-a-h1:example-service-a-name',
              priority: 5
            },
            {
              host: 'example-service-a-h2.com',
              id: 'head:group:cluster-a-h2:example-service-a-name',
              priority: 3
            }
          ],
          'example-service-b': [
            {
              host: 'example-service-b-h1.com',
              id: 'head:group:cluster-b-h1:example-service-b-name',
              priority: 5
            },
            {
              host: 'example-service-b-h2.com',
              id: 'head:group:cluster-b-h2:example-service-b-name',
              priority: 3
            }
          ],
          'example-service-c': [
            {
              host: 'example-service-c-h1.com',
              id: 'head:group:cluster-c-h1:example-service-a-name',
              priority: 5
            },
            {
              host: 'example-service-c-h2.com',
              id: 'head:group:cluster-c-h2:example-service-a-name',
              priority: 3
            }
          ]
        }
      };

      fixtureHosts = Object.keys(fixture.hostCatalog)
        .reduce((output, key) => {
          output.push(...fixture.hostCatalog[key]);

          return output;
        }, []);
    });

    beforeEach('initialize a service catalog', () => {
      serviceCatalogs = new ServiceCatalogs();
    });

    describe('class members', () => {
      describe('#hosts', () => {
        it('should be an array', () => {
          assert.isArray(serviceCatalogs.hosts);
        });
      });
    });

    describe('#filterActive()', () => {
      let hostList;
      let failedHost;
      let filteredHosts;

      beforeEach('generate the service host class objects', () => {
        hostList = ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[0],
          ...fixture
        });

        serviceCatalogs.load(hostList);
        failedHost = serviceCatalogs.hosts[0];
        failedHost.setStatus({failed: true, replaced: true});
      });

      it('should return all hosts when called without params', () => {
        filteredHosts = serviceCatalogs.filterActive();

        assert.equal(filteredHosts.length, hostList.length);
      });

      it('should return only active hosts when called with true', () => {
        filteredHosts = serviceCatalogs.filterActive(true);

        assert.isBelow(filteredHosts.length, hostList.length);
        assert.notInclude(filteredHosts, failedHost);
      });

      it('should return only inactive hosts when active is false', () => {
        filteredHosts = serviceCatalogs.filterActive(false);

        assert.equal(filteredHosts.length, 1);
        assert.include(filteredHosts[0], failedHost);
      });
    });

    describe('#filterCatalog()', () => {
      let filteredHosts;
      let hostsCustomA;
      let hostsCustomB;

      beforeEach('generate the service host class objects', () => {
        hostsCustomA = ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[0],
          ...fixture
        });

        hostsCustomB = ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[1],
          ...fixture
        });

        serviceCatalogs.load(hostsCustomA);
        serviceCatalogs.load(hostsCustomB);
      });

      it('should return all hosts when called without params', () => {
        filteredHosts = serviceCatalogs.filterCatalog();

        assert.deepEqual(filteredHosts, serviceCatalogs.hosts);
      });

      it('should return only service hosts in the specific catalog', () => {
        filteredHosts = serviceCatalogs.filterCatalog(SERVICE_CATALOGS[0]);

        assert.equal(filteredHosts.length, hostsCustomA.length);
        assert.isTrue(filteredHosts.every(
          (host) => host.catalog === SERVICE_CATALOGS[0]
        ));
      });

      it('should return service hosts for an array of catalogs', () => {
        filteredHosts = serviceCatalogs.filterCatalog(
          [SERVICE_CATALOGS[0], SERVICE_CATALOGS[1]]
        );

        assert.equal(
          filteredHosts.length,
          (hostsCustomA.length + hostsCustomB.length)
        );

        assert.isTrue(filteredHosts.every(
          (host) => [SERVICE_CATALOGS[0], SERVICE_CATALOGS[1]].includes(
            host.catalog
          )
        ));
      });

      it('should return only service hosts from valid catalogs', () => {
        filteredHosts = serviceCatalogs.filterCatalog(
          [SERVICE_CATALOGS[0], 'invalid', -1]
        );

        assert.equal(filteredHosts.length, hostsCustomA.length);
        assert.isTrue(filteredHosts.every(
          (host) => host.catalog === SERVICE_CATALOGS[0]
        ));
      });
    });

    describe('#filterLocal()', () => {
      let filteredHosts;
      let remoteHosts;
      let localHosts;

      beforeEach('generate the service host class objects', () => {
        serviceCatalogs.load(
          ServiceCatalogs.mapRemoteCatalog({
            catalog: SERVICE_CATALOGS[0],
            ...fixture
          })
        );

        remoteHosts = fixture.hostCatalog['example-service-c'];
        localHosts = [
          ...fixture.hostCatalog['example-service-a'],
          ...fixture.hostCatalog['example-service-b']
        ];
      });

      it('should return all hosts when called without params', () => {
        filteredHosts = serviceCatalogs.filterLocal();

        assert.deepEqual(filteredHosts, serviceCatalogs.hosts);
      });

      it('should return only local hosts when called with true', () => {
        filteredHosts = serviceCatalogs.filterLocal(true);

        assert.equal(filteredHosts.length, localHosts.length);
        assert.isTrue(filteredHosts.every(
          (host) => host.local === true
        ));
      });

      it('should return only hosts remote hosts when called with false', () => {
        filteredHosts = serviceCatalogs.filterLocal(false);

        assert.equal(filteredHosts.length, remoteHosts.length);
        assert.isTrue(filteredHosts.every(
          (host) => host.local === false
        ));
      });
    });

    describe('#filterPriority()', () => {
      let filteredHosts;
      let priorityHosts;

      beforeEach('generate the service host class objects', () => {
        serviceCatalogs.load(
          ServiceCatalogs.mapRemoteCatalog({
            catalog: SERVICE_CATALOGS[0],
            ...fixture
          })
        );

        priorityHosts = [
          fixture.hostCatalog['example-service-a'][0],
          fixture.hostCatalog['example-service-b'][0],
          fixture.hostCatalog['example-service-c'][0]
        ];
      });

      it('should return all hosts when called without params', () => {
        filteredHosts = serviceCatalogs.filterPriority();

        assert.deepEqual(filteredHosts, serviceCatalogs.hosts);
      });

      it('should return only priority hosts when called with true', () => {
        filteredHosts = serviceCatalogs.filterPriority(true);

        assert.equal(filteredHosts.length, priorityHosts.length);
      });

      it('should not return inactive hosts when called with true', () => {
        filteredHosts = serviceCatalogs.filterPriority(true);
        filteredHosts[0].setStatus({failed: true});

        const failedHost = filteredHosts[0];

        filteredHosts = serviceCatalogs.filterPriority(true);

        assert.notInclude(filteredHosts, failedHost);
      });

      it('should return all hosts when called with false', () => {
        filteredHosts = serviceCatalogs.filterPriority(false);

        assert.deepEqual(filteredHosts, serviceCatalogs.hosts);
      });
    });

    describe('#filterService()', () => {
      let filteredHosts;
      let otherHosts;
      let otherServiceName;
      let serviceHosts;
      let serviceName;

      beforeEach('generate the service host class objects', () => {
        serviceCatalogs.load(
          ServiceCatalogs.mapRemoteCatalog({
            catalog: SERVICE_CATALOGS[0],
            ...fixture
          })
        );

        otherHosts = [
          ...fixture.hostCatalog['example-service-b']
        ];

        serviceHosts = [
          ...fixture.hostCatalog['example-service-a'],
          ...fixture.hostCatalog['example-service-c']
        ];

        otherServiceName = 'example-service-b-name';
        serviceName = 'example-service-a-name';
      });

      it('should return all hosts when called without params', () => {
        filteredHosts = serviceCatalogs.filterService();

        assert.equal(filteredHosts.length, serviceCatalogs.hosts.length);
      });

      it('should return hosts that belong to a service', () => {
        filteredHosts = serviceCatalogs.filterService(serviceName);

        assert.equal(filteredHosts.length, serviceHosts.length);
        assert.isTrue(filteredHosts.every(
          (host) => host.service === serviceName
        ));
      });

      it('should return all hosts that belong to an array of services', () => {
        filteredHosts = serviceCatalogs.filterService([
          otherServiceName,
          serviceName
        ]);

        assert.equal(
          filteredHosts.length,
          [...otherHosts, ...serviceHosts].length
        );

        assert.isTrue(filteredHosts.every(
          (host) => [otherServiceName, serviceName].includes(host.service)
        ));
      });

      it('should return no hosts with an invalid service', () => {
        filteredHosts = serviceCatalogs.filterService('invalid');

        assert.equal(filteredHosts.length, 0);
      });
    });

    describe('#load()', () => {
      it('should amend all provided hosts to the hosts array', () => {
        serviceCatalogs.load(ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[0],
          ...fixture
        }));

        assert.equal(serviceCatalogs.hosts.length, fixtureHosts.length);
      });

      it('should ignore unloadable hosts', () => {
        const unloadables = ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[0],
          ...fixture
        }).map((unloadable) => ({...unloadable, catalog: 'invalid'}));

        serviceCatalogs.load(unloadables);

        assert.equal(serviceCatalogs.hosts.length, 0);
      });

      it('should return itself', () => {
        assert.equal(serviceCatalogs.load([]), serviceCatalogs);
      });
    });

    describe('static methods', () => {
      describe('#mapCatalogName()', () => {
        let index;
        let name;

        beforeEach(() => {
          index = 0;
          name = SERVICE_CATALOGS[index];
        });

        it('should map an index to the matching name', () => {
          assert.equal(
            ServiceCatalogs.mapCatalogName({id: index, type: SCET.STRING}),
            name
          );
        });

        it('should map an index to the matching index', () => {
          assert.equal(
            ServiceCatalogs.mapCatalogName({id: index, type: SCET.NUMBER}),
            index
          );
        });

        it('should map a name to the matching index', () => {
          assert.equal(
            ServiceCatalogs.mapCatalogName({id: name, type: SCET.NUMBER}),
            index
          );
        });

        it('should map a name to the matching name', () => {
          assert.equal(
            ServiceCatalogs.mapCatalogName({id: name, type: SCET.STRING}),
            name
          );
        });

        it('should return undefined if an index doesn\'t exist', () => {
          assert.isUndefined(
            ServiceCatalogs.mapCatalogName({id: -1, type: SCET.NUMBER})
          );
        });

        it('should return undefined if a name doesn\'t exist', () => {
          assert.isUndefined(
            ServiceCatalogs.mapCatalogName({id: 'invalid', type: SCET.NUMBER})
          );
        });
      });

      describe('#mapRemoteCatalog()', () => {
        it('should return an array', () => {
          const mappedHosts = ServiceCatalogs.mapRemoteCatalog({
            catalog: SERVICE_CATALOGS[0],
            ...fixture
          });

          assert.isArray(mappedHosts);
        });

        it('should include all provided hosts', () => {
          const mappedHosts = ServiceCatalogs.mapRemoteCatalog({
            catalog: SERVICE_CATALOGS[0],
            ...fixture
          });

          assert.equal(mappedHosts.length, fixtureHosts.length);
        });

        it('should not map using an invalid catalog name', () => {
          assert.throws(() => ServiceCatalogs.mapRemoteCatalog({
            catalog: 'invalid',
            ...fixture
          }));
        });

        it('should map catalog indexes to catalog names', () => {
          const catalogIndex = 4;

          const mappedHosts = ServiceCatalogs.mapRemoteCatalog({
            catalog: catalogIndex,
            ...fixture
          });

          assert.equal(
            mappedHosts[0].catalog,
            SERVICE_CATALOGS[catalogIndex]
          );
        });
      });
    });
  });
});
<commit_msg>test(webex-core): add service catalog handling methods<commit_after>import {assert} from '@webex/test-helper-chai';
import sinon from 'sinon';
import {ServiceCatalogs, serviceConstants} from '@webex/webex-core';

const {SERVICE_CATALOGS, SERVICE_CATALOGS_ENUM_TYPES: SCET} = serviceConstants;

describe('webex-core', () => {
  describe('ServiceCatalogs', () => {
    let fixture;
    let fixtureHosts;
    let serviceCatalogs;

    before('generate fixture', () => {
      fixture = {
        serviceLinks: {
          'example-service-a-name': 'http://example-service-a.com/',
          'example-service-b-name': 'http://example-service-b.com/'
        },
        hostCatalog: {
          'example-service-a': [
            {
              host: 'example-service-a-h1.com',
              id: 'head:group:cluster-a-h1:example-service-a-name',
              priority: 5
            },
            {
              host: 'example-service-a-h2.com',
              id: 'head:group:cluster-a-h2:example-service-a-name',
              priority: 3
            }
          ],
          'example-service-b': [
            {
              host: 'example-service-b-h1.com',
              id: 'head:group:cluster-b-h1:example-service-b-name',
              priority: 5
            },
            {
              host: 'example-service-b-h2.com',
              id: 'head:group:cluster-b-h2:example-service-b-name',
              priority: 3
            }
          ],
          'example-service-c': [
            {
              host: 'example-service-c-h1.com',
              id: 'head:group:cluster-c-h1:example-service-a-name',
              priority: 5
            },
            {
              host: 'example-service-c-h2.com',
              id: 'head:group:cluster-c-h2:example-service-a-name',
              priority: 3
            }
          ]
        }
      };

      fixtureHosts = Object.keys(fixture.hostCatalog)
        .reduce((output, key) => {
          output.push(...fixture.hostCatalog[key]);

          return output;
        }, []);
    });

    beforeEach('initialize a service catalog', () => {
      serviceCatalogs = new ServiceCatalogs();
    });

    describe('class members', () => {
      describe('#hosts', () => {
        it('should be an array', () => {
          assert.isArray(serviceCatalogs.hosts);
        });
      });

      describe('#map', () => {
        let priorityLocalHosts;

        beforeEach('setup hosts', () => {
          serviceCatalogs.load(
            ServiceCatalogs.mapRemoteCatalog({
              catalog: SERVICE_CATALOGS[0],
              ...fixture
            })
          );

          const {hostCatalog} = fixture;

          priorityLocalHosts = {
            'example-service-a-name': hostCatalog['example-service-a'][0].host,
            'example-service-b-name': hostCatalog['example-service-b'][0].host
          };
        });

        it('should only return hosts that are active/local/priority', () => {
          const {map} = serviceCatalogs;
          const priorityLocalHostsKeys = Object.keys(priorityLocalHosts);

          assert.isTrue(priorityLocalHostsKeys.every(
            (key) => map[key].includes(priorityLocalHosts[key])
          ));
        });
      });
    });

    describe('#clear()', () => {
      let filter;
      let host;

      beforeEach('generate the service host class objects', () => {
        serviceCatalogs.load(ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[0],
          ...fixture
        }));

        host = serviceCatalogs.hosts[0];

        filter = {
          active: true,
          catalog: host.catalog,
          cluster: host.id,
          local: true,
          priority: true,
          service: host.service
        };
      });

      it('should remove all hosts when called without a filter', () => {
        serviceCatalogs.clear();

        assert.equal(serviceCatalogs.hosts.length, 0);
      });

      it('should remove only filtered hosts when called with a filter', () => {
        serviceCatalogs.clear(filter);

        assert.notInclude(serviceCatalogs.hosts, host);
      });

      it('should remove multiple hosts based on the provided filter', () => {
        host.setStatus({failed: true});
        serviceCatalogs.clear({active: true});
        assert.deepEqual(serviceCatalogs.hosts, [host]);
      });

      it('should return the removed hosts', () => {
        const [removedHost] = serviceCatalogs.clear(filter);

        assert.equal(removedHost, host);
      });
    });

    describe('#filterActive()', () => {
      let hostList;
      let failedHost;
      let filteredHosts;

      beforeEach('generate the service host class objects', () => {
        hostList = ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[0],
          ...fixture
        });

        serviceCatalogs.load(hostList);
        failedHost = serviceCatalogs.hosts[0];
        failedHost.setStatus({failed: true, replaced: true});
      });

      it('should return all hosts when called without params', () => {
        filteredHosts = serviceCatalogs.filterActive();

        assert.equal(filteredHosts.length, hostList.length);
      });

      it('should return only active hosts when called with true', () => {
        filteredHosts = serviceCatalogs.filterActive(true);

        assert.isBelow(filteredHosts.length, hostList.length);
        assert.notInclude(filteredHosts, failedHost);
      });

      it('should return only inactive hosts when active is false', () => {
        filteredHosts = serviceCatalogs.filterActive(false);

        assert.equal(filteredHosts.length, 1);
        assert.include(filteredHosts[0], failedHost);
      });
    });

    describe('#filterCatalog()', () => {
      let filteredHosts;
      let hostsCustomA;
      let hostsCustomB;

      beforeEach('generate the service host class objects', () => {
        hostsCustomA = ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[0],
          ...fixture
        });

        hostsCustomB = ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[1],
          ...fixture
        });

        serviceCatalogs.load(hostsCustomA);
        serviceCatalogs.load(hostsCustomB);
      });

      it('should return all hosts when called without params', () => {
        filteredHosts = serviceCatalogs.filterCatalog();

        assert.deepEqual(filteredHosts, serviceCatalogs.hosts);
      });

      it('should return only service hosts in the specific catalog', () => {
        filteredHosts = serviceCatalogs.filterCatalog(SERVICE_CATALOGS[0]);

        assert.equal(filteredHosts.length, hostsCustomA.length);
        assert.isTrue(filteredHosts.every(
          (host) => host.catalog === SERVICE_CATALOGS[0]
        ));
      });

      it('should return service hosts for an array of catalogs', () => {
        filteredHosts = serviceCatalogs.filterCatalog(
          [SERVICE_CATALOGS[0], SERVICE_CATALOGS[1]]
        );

        assert.equal(
          filteredHosts.length,
          (hostsCustomA.length + hostsCustomB.length)
        );

        assert.isTrue(filteredHosts.every(
          (host) => [SERVICE_CATALOGS[0], SERVICE_CATALOGS[1]].includes(
            host.catalog
          )
        ));
      });

      it('should return only service hosts from valid catalogs', () => {
        filteredHosts = serviceCatalogs.filterCatalog(
          [SERVICE_CATALOGS[0], 'invalid', -1]
        );

        assert.equal(filteredHosts.length, hostsCustomA.length);
        assert.isTrue(filteredHosts.every(
          (host) => host.catalog === SERVICE_CATALOGS[0]
        ));
      });
    });

    describe('#filterLocal()', () => {
      let filteredHosts;
      let remoteHosts;
      let localHosts;

      beforeEach('generate the service host class objects', () => {
        serviceCatalogs.load(
          ServiceCatalogs.mapRemoteCatalog({
            catalog: SERVICE_CATALOGS[0],
            ...fixture
          })
        );

        remoteHosts = fixture.hostCatalog['example-service-c'];
        localHosts = [
          ...fixture.hostCatalog['example-service-a'],
          ...fixture.hostCatalog['example-service-b']
        ];
      });

      it('should return all hosts when called without params', () => {
        filteredHosts = serviceCatalogs.filterLocal();

        assert.deepEqual(filteredHosts, serviceCatalogs.hosts);
      });

      it('should return only local hosts when called with true', () => {
        filteredHosts = serviceCatalogs.filterLocal(true);

        assert.equal(filteredHosts.length, localHosts.length);
        assert.isTrue(filteredHosts.every(
          (host) => host.local === true
        ));
      });

      it('should return only hosts remote hosts when called with false', () => {
        filteredHosts = serviceCatalogs.filterLocal(false);

        assert.equal(filteredHosts.length, remoteHosts.length);
        assert.isTrue(filteredHosts.every(
          (host) => host.local === false
        ));
      });
    });

    describe('#filterPriority()', () => {
      let filteredHosts;
      let priorityHosts;

      beforeEach('generate the service host class objects', () => {
        serviceCatalogs.load(
          ServiceCatalogs.mapRemoteCatalog({
            catalog: SERVICE_CATALOGS[0],
            ...fixture
          })
        );

        priorityHosts = [
          fixture.hostCatalog['example-service-a'][0],
          fixture.hostCatalog['example-service-b'][0],
          fixture.hostCatalog['example-service-c'][0]
        ];
      });

      it('should return all hosts when called without params', () => {
        filteredHosts = serviceCatalogs.filterPriority();

        assert.deepEqual(filteredHosts, serviceCatalogs.hosts);
      });

      it('should return only priority hosts when called with true', () => {
        filteredHosts = serviceCatalogs.filterPriority(true);

        assert.equal(filteredHosts.length, priorityHosts.length);
      });

      it('should not return inactive hosts when called with true', () => {
        filteredHosts = serviceCatalogs.filterPriority(true);
        filteredHosts[0].setStatus({failed: true});

        const failedHost = filteredHosts[0];

        filteredHosts = serviceCatalogs.filterPriority(true);

        assert.notInclude(filteredHosts, failedHost);
      });

      it('should return all hosts when called with false', () => {
        filteredHosts = serviceCatalogs.filterPriority(false);

        assert.deepEqual(filteredHosts, serviceCatalogs.hosts);
      });
    });

    describe('#filterService()', () => {
      let filteredHosts;
      let otherHosts;
      let otherServiceName;
      let serviceHosts;
      let serviceName;

      beforeEach('generate the service host class objects', () => {
        serviceCatalogs.load(
          ServiceCatalogs.mapRemoteCatalog({
            catalog: SERVICE_CATALOGS[0],
            ...fixture
          })
        );

        otherHosts = [
          ...fixture.hostCatalog['example-service-b']
        ];

        serviceHosts = [
          ...fixture.hostCatalog['example-service-a'],
          ...fixture.hostCatalog['example-service-c']
        ];

        otherServiceName = 'example-service-b-name';
        serviceName = 'example-service-a-name';
      });

      it('should return all hosts when called without params', () => {
        filteredHosts = serviceCatalogs.filterService();

        assert.equal(filteredHosts.length, serviceCatalogs.hosts.length);
      });

      it('should return hosts that belong to a service', () => {
        filteredHosts = serviceCatalogs.filterService(serviceName);

        assert.equal(filteredHosts.length, serviceHosts.length);
        assert.isTrue(filteredHosts.every(
          (host) => host.service === serviceName
        ));
      });

      it('should return all hosts that belong to an array of services', () => {
        filteredHosts = serviceCatalogs.filterService([
          otherServiceName,
          serviceName
        ]);

        assert.equal(
          filteredHosts.length,
          [...otherHosts, ...serviceHosts].length
        );

        assert.isTrue(filteredHosts.every(
          (host) => [otherServiceName, serviceName].includes(host.service)
        ));
      });

      it('should return no hosts with an invalid service', () => {
        filteredHosts = serviceCatalogs.filterService('invalid');

        assert.equal(filteredHosts.length, 0);
      });
    });

    describe('#find()', () => {
      let filter;
      let host;

      beforeEach('generate the service host class objects', () => {
        serviceCatalogs.load(ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[0],
          ...fixture
        }));

        host = serviceCatalogs.hosts[0];

        filter = {
          active: true,
          catalog: host.catalog,
          cluster: host.id,
          local: true,
          priority: true,
          service: host.service
        };
      });

      it('should call the \'filterActive()\' method with params', () => {
        sinon.spy(serviceCatalogs, 'filterActive');
        serviceCatalogs.find(filter);
        assert.calledWith(serviceCatalogs.filterActive, filter.active);
      });

      it('should call the \'filterCatalog()\' method with params', () => {
        sinon.spy(serviceCatalogs, 'filterCatalog');
        serviceCatalogs.find(filter);
        assert.calledWith(serviceCatalogs.filterCatalog, filter.catalog);
      });

      it('should call the \'filterCluster()\' method with params', () => {
        sinon.spy(serviceCatalogs, 'filterCluster');
        serviceCatalogs.find(filter);
        assert.calledWith(serviceCatalogs.filterCluster, filter.cluster);
      });

      it('should call the \'filterLocal()\' method with params', () => {
        sinon.spy(serviceCatalogs, 'filterLocal');
        serviceCatalogs.find(filter);
        assert.calledWith(serviceCatalogs.filterLocal, filter.local);
      });

      it('should call the \'filterPriority()\' method with params', () => {
        sinon.spy(serviceCatalogs, 'filterPriority');
        serviceCatalogs.find(filter);
        assert.calledWith(serviceCatalogs.filterPriority, filter.priority);
      });

      it('should call the \'filterService()\' method with params', () => {
        sinon.spy(serviceCatalogs, 'filterService');
        serviceCatalogs.find(filter);
        assert.calledWith(serviceCatalogs.filterService, filter.service);
      });

      it('should return an array of filtered hosts', () => {
        const foundHosts = serviceCatalogs.find(filter);

        assert.equal(foundHosts[0], host);
        assert.equal(foundHosts.length, 1);
      });

      it('should return all of the hosts when called without params', () => {
        const foundHosts = serviceCatalogs.find();

        assert.deepEqual(foundHosts, serviceCatalogs.hosts);
      });
    });

    describe('#load()', () => {
      it('should amend all provided hosts to the hosts array', () => {
        serviceCatalogs.load(ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[0],
          ...fixture
        }));

        assert.equal(serviceCatalogs.hosts.length, fixtureHosts.length);
      });

      it('should ignore unloadable hosts', () => {
        const unloadables = ServiceCatalogs.mapRemoteCatalog({
          catalog: SERVICE_CATALOGS[0],
          ...fixture
        }).map((unloadable) => ({...unloadable, catalog: 'invalid'}));

        serviceCatalogs.load(unloadables);

        assert.equal(serviceCatalogs.hosts.length, 0);
      });

      it('should return itself', () => {
        assert.equal(serviceCatalogs.load([]), serviceCatalogs);
      });
    });

    describe('static methods', () => {
      describe('#mapCatalogName()', () => {
        let index;
        let name;

        beforeEach(() => {
          index = 0;
          name = SERVICE_CATALOGS[index];
        });

        it('should map an index to the matching name', () => {
          assert.equal(
            ServiceCatalogs.mapCatalogName({id: index, type: SCET.STRING}),
            name
          );
        });

        it('should map an index to the matching index', () => {
          assert.equal(
            ServiceCatalogs.mapCatalogName({id: index, type: SCET.NUMBER}),
            index
          );
        });

        it('should map a name to the matching index', () => {
          assert.equal(
            ServiceCatalogs.mapCatalogName({id: name, type: SCET.NUMBER}),
            index
          );
        });

        it('should map a name to the matching name', () => {
          assert.equal(
            ServiceCatalogs.mapCatalogName({id: name, type: SCET.STRING}),
            name
          );
        });

        it('should return undefined if an index doesn\'t exist', () => {
          assert.isUndefined(
            ServiceCatalogs.mapCatalogName({id: -1, type: SCET.NUMBER})
          );
        });

        it('should return undefined if a name doesn\'t exist', () => {
          assert.isUndefined(
            ServiceCatalogs.mapCatalogName({id: 'invalid', type: SCET.NUMBER})
          );
        });
      });

      describe('#mapRemoteCatalog()', () => {
        it('should return an array', () => {
          const mappedHosts = ServiceCatalogs.mapRemoteCatalog({
            catalog: SERVICE_CATALOGS[0],
            ...fixture
          });

          assert.isArray(mappedHosts);
        });

        it('should include all provided hosts', () => {
          const mappedHosts = ServiceCatalogs.mapRemoteCatalog({
            catalog: SERVICE_CATALOGS[0],
            ...fixture
          });

          assert.equal(mappedHosts.length, fixtureHosts.length);
        });

        it('should not map using an invalid catalog name', () => {
          assert.throws(() => ServiceCatalogs.mapRemoteCatalog({
            catalog: 'invalid',
            ...fixture
          }));
        });

        it('should map catalog indexes to catalog names', () => {
          const catalogIndex = 4;

          const mappedHosts = ServiceCatalogs.mapRemoteCatalog({
            catalog: catalogIndex,
            ...fixture
          });

          assert.equal(
            mappedHosts[0].catalog,
            SERVICE_CATALOGS[catalogIndex]
          );
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>/*
Handles the requests by executing stuff and replying to the client. Uses promises to get stuff done.
*/

'use strict';

const boom = require('boom'), //Boom gives us some predefined http codes and proper responses
  notificationsDB = require('../database/notificationsDatabase'), //Database functions specific for notifications
  co = require('../common');

module.exports = {
  //Get notification from database or return NOT FOUND
  getNotification: function(request, reply) {
    notificationsDB.get(encodeURIComponent(request.params.id)).then((notification) => {
      if (co.isEmpty(notification))
        reply(boom.notFound());
      else {
        notification.author = authorsMap.get(notification.user_id);//insert author data
        if (notification.author === undefined) {
          notification.author = authorsMap.get('112233445566778899000000');
        }
        reply(co.rewriteID(notification));
      }
    }).catch((error) => {

      request.log('error', error);
      reply(boom.badImplementation());
    });
  },

  //Create notification with new id and payload or return INTERNAL_SERVER_ERROR
  newNotification: function(request, reply) {
    notificationsDB.insert(request.payload).then((inserted) => {
      //console.log('inserted: ', inserted);
      if (co.isEmpty(inserted.ops) || co.isEmpty(inserted.ops[0]))
        throw inserted;
      else {
        inserted.ops[0].author = authorsMap.get(inserted.ops[0].user_id);//insert author data
        reply(co.rewriteID(inserted.ops[0]));
      }
    }).catch((error) => {
      request.log('error', error);
      reply(boom.badImplementation());
    });
  },

  //Update notification with id id and payload or return INTERNAL_SERVER_ERROR
  updateNotification: function(request, reply) {
    notificationsDB.replace(encodeURIComponent(request.params.id), request.payload).then((replaced) => {
      //console.log('updated: ', replaced);
      if (co.isEmpty(replaced.value))
        throw replaced;
      else
        reply(replaced.value);
    }).catch((error) => {
      request.log('error', error);
      reply(boom.badImplementation());
    });
  },

  //Delete notification with id id
  deleteNotification: function(request, reply) {
    notificationsDB.delete(encodeURIComponent(request.payload.id)).then(() =>
      reply({'msg': 'notification is successfully deleted...'})
    ).catch((error) => {
      request.log('error', error);
      reply(boom.badImplementation());
    });
  },

  //Delete notifications with subscribed_user_id
  deleteNotifications: function(request, reply) {
    notificationsDB.deleteAllWithSubscribedUserID(encodeURIComponent(request.payload.subscribed_user_id)).then(() =>
      reply({'msg': 'notifications were successfully deleted...'})
    ).catch((error) => {
      request.log('error', error);
      reply(boom.badImplementation());
    });
  },

  //Get All notifications from database for the id in the request
  getNotifications: function(request, reply) {
    //Clean collection and insert mockup notifications - only if request.params.id === 0
    initMockupData(request.params.id)
      .then(() => notificationsDB.getAllFromCollection()//TODO call getAllWithSubscribedUserID(identifier)
      // .then(() => notificationsDB.getAllWithSubscribedUserID(encodeURIComponent(request.params.id))
      .then((notifications) => {
        insertAuthorData(notifications);

        let jsonReply = JSON.stringify(notifications);
        reply(jsonReply);

      })).catch((error) => {
        request.log('error', error);
        reply(boom.badImplementation());
      });
  },

  //Get All notifications from database
  getAllNotifications: function(request, reply) {
    notificationsDB.getAllFromCollection()
      .then((notifications) => {
        insertAuthorData(notifications);

        let jsonReply = JSON.stringify(notifications);
        reply(jsonReply);

      }).catch((error) => {
        request.log('error', error);
        reply(boom.badImplementation());
      });
  }
};

//Delete all and insert mockup data
function initMockupData(identifier) {
  if (identifier === '000000000000000000000000') {//create collection, delete all and insert mockup data only if the user has explicitly sent 000000000000000000000000
    return notificationsDB.createCollection()
      .then(() => notificationsDB.deleteAll())
      .then(() => insertMockupData());
  }
  return new Promise((resolve) => {resolve (1);});
}

function insertAuthorData(notifications) {
  notifications.forEach((notification) => {
    co.rewriteID(notification);
    notification.author = authorsMap.get(notification.user_id);//insert author data
  });
}

// function getFirstTwoActivities() {
//   let http = require('http');
//   const Microservices = require('../configs/microservices');
//   let options = {
//     //CHANGES FOR LOCALHOST IN PUPIN (PROXY)
//     // host: 'proxy.rcub.bg.ac.rs',
//     // port: 8080,
//     // path: 'http://activitiesservice.manfredfris.ch/activity/new',
//     // path: 'http://' + Microservices.activities.uri + '/activity/new',
//
//     // host: 'activitiesservice.manfredfris.ch',
//     host: Microservices.activities.uri,
//     port: 80,
//     path: '/activities/112233445566778899000671',
//   };
//
//   let req = http.get(options, (res) => {
//     // console.log('STATUS: ' + res.statusCode);
//     // console.log('HEADERS: ' + JSON.stringify(res.headers));
//     let body = '';
//     res.on('data', (chunk) => {
//       body += chunk;
//     });
//     res.on('end', () => {
//       let data = JSON.parse(body);
//       console.log(data);
//       return data;
//     });
//   });
//   req.on('error', (e) => {
//     console.log('problem with request: ' + e.message);
//   });
//
// }
//Insert mockup data to the collection
function insertMockupData() {
  //get real ids for the first 2 activities
  // const firstTwoActivities = getFirstTwoActivities();
  const firstTwoActivities = [
    {activity_id: '574d7da5d46fe91000cc3a77'},
    {activity_id: '574d7da5d46fe91000cc3a76'}
  ];
  let notification1 = {
    activity_id: firstTwoActivities[0].activity_id,
    activity_type: 'react',
    content_id: '112233445566778899000671',
    content_kind: 'slide',
    content_name: 'Introduction',
    user_id: '112233445566778899000002',
    react_type: 'like',
    subscribed_user_id: '112233445566778899000001'
  };
  let ins1 = notificationsDB.insert(notification1);
  let notification2 = {
    activity_id: firstTwoActivities[0].activity_id,
    activity_type: 'download',
    content_id: '112233445566778899000671',
    content_kind: 'slide',
    content_name: 'Introduction',
    user_id: '112233445566778899000001',
    subscribed_user_id: '112233445566778899000001'
  };
  let ins2 = ins1.then(() => notificationsDB.insert(notification2));

  return ins2;
}

let authorsMap = new Map([
  ['112233445566778899000001', {
    id: 7,
    username: 'Dejan P.',
    avatar: '/assets/images/mock-avatars/deadpool_256.png'
  }],
  ['112233445566778899000002', {
    id: 8,
    username: 'Nikola T.',
    avatar: '/assets/images/mock-avatars/man_512.png'
  }],
  ['112233445566778899000003', {
    id: 9,
    username: 'Marko B.',
    avatar: '/assets/images/mock-avatars/batman_512.jpg'
  }],
  ['112233445566778899000004', {
    id: 10,
    username: 'Valentina J.',
    avatar: '/assets/images/mock-avatars/ninja-simple_512.png'
  }],
  ['112233445566778899000005', {
    id: 11,
    username: 'Voice in the crowd',
    avatar: '/assets/images/mock-avatars/anon_256.jpg'
  }],
  ['112233445566778899000006', {
    id: 12,
    username: 'SlideWiki FTW',
    avatar: '/assets/images/mock-avatars/spooky_256.png'
  }],
  ['112233445566778899000000', {
    id: 13,
    username: 'Dutch',
    avatar: '/assets/images/mock-avatars/dgirl.jpeg'
  }]
]);
<commit_msg>Corrected mockup data<commit_after>/*
Handles the requests by executing stuff and replying to the client. Uses promises to get stuff done.
*/

'use strict';

const boom = require('boom'), //Boom gives us some predefined http codes and proper responses
  notificationsDB = require('../database/notificationsDatabase'), //Database functions specific for notifications
  co = require('../common');

module.exports = {
  //Get notification from database or return NOT FOUND
  getNotification: function(request, reply) {
    notificationsDB.get(encodeURIComponent(request.params.id)).then((notification) => {
      if (co.isEmpty(notification))
        reply(boom.notFound());
      else {
        notification.author = authorsMap.get(notification.user_id);//insert author data
        if (notification.author === undefined) {
          notification.author = authorsMap.get('112233445566778899000000');
        }
        reply(co.rewriteID(notification));
      }
    }).catch((error) => {

      request.log('error', error);
      reply(boom.badImplementation());
    });
  },

  //Create notification with new id and payload or return INTERNAL_SERVER_ERROR
  newNotification: function(request, reply) {
    notificationsDB.insert(request.payload).then((inserted) => {
      //console.log('inserted: ', inserted);
      if (co.isEmpty(inserted.ops) || co.isEmpty(inserted.ops[0]))
        throw inserted;
      else {
        inserted.ops[0].author = authorsMap.get(inserted.ops[0].user_id);//insert author data
        reply(co.rewriteID(inserted.ops[0]));
      }
    }).catch((error) => {
      request.log('error', error);
      reply(boom.badImplementation());
    });
  },

  //Update notification with id id and payload or return INTERNAL_SERVER_ERROR
  updateNotification: function(request, reply) {
    notificationsDB.replace(encodeURIComponent(request.params.id), request.payload).then((replaced) => {
      //console.log('updated: ', replaced);
      if (co.isEmpty(replaced.value))
        throw replaced;
      else
        reply(replaced.value);
    }).catch((error) => {
      request.log('error', error);
      reply(boom.badImplementation());
    });
  },

  //Delete notification with id id
  deleteNotification: function(request, reply) {
    notificationsDB.delete(encodeURIComponent(request.payload.id)).then(() =>
      reply({'msg': 'notification is successfully deleted...'})
    ).catch((error) => {
      request.log('error', error);
      reply(boom.badImplementation());
    });
  },

  //Delete notifications with subscribed_user_id
  deleteNotifications: function(request, reply) {
    notificationsDB.deleteAllWithSubscribedUserID(encodeURIComponent(request.payload.subscribed_user_id)).then(() =>
      reply({'msg': 'notifications were successfully deleted...'})
    ).catch((error) => {
      request.log('error', error);
      reply(boom.badImplementation());
    });
  },

  //Get All notifications from database for the id in the request
  getNotifications: function(request, reply) {
    //Clean collection and insert mockup notifications - only if request.params.id === 0
    initMockupData(request.params.id)
      .then(() => notificationsDB.getAllFromCollection()//TODO call getAllWithSubscribedUserID(identifier)
      // .then(() => notificationsDB.getAllWithSubscribedUserID(encodeURIComponent(request.params.id))
      .then((notifications) => {
        insertAuthorData(notifications);

        let jsonReply = JSON.stringify(notifications);
        reply(jsonReply);

      })).catch((error) => {
        request.log('error', error);
        reply(boom.badImplementation());
      });
  },

  //Get All notifications from database
  getAllNotifications: function(request, reply) {
    notificationsDB.getAllFromCollection()
      .then((notifications) => {
        insertAuthorData(notifications);

        let jsonReply = JSON.stringify(notifications);
        reply(jsonReply);

      }).catch((error) => {
        request.log('error', error);
        reply(boom.badImplementation());
      });
  }
};

//Delete all and insert mockup data
function initMockupData(identifier) {
  if (identifier === '000000000000000000000000') {//create collection, delete all and insert mockup data only if the user has explicitly sent 000000000000000000000000
    return notificationsDB.createCollection()
      .then(() => notificationsDB.deleteAll())
      .then(() => insertMockupData());
  }
  return new Promise((resolve) => {resolve (1);});
}

function insertAuthorData(notifications) {
  notifications.forEach((notification) => {
    co.rewriteID(notification);
    notification.author = authorsMap.get(notification.user_id);//insert author data
  });
}

// function getFirstTwoActivities() {
//   let http = require('http');
//   const Microservices = require('../configs/microservices');
//   let options = {
//     //CHANGES FOR LOCALHOST IN PUPIN (PROXY)
//     // host: 'proxy.rcub.bg.ac.rs',
//     // port: 8080,
//     // path: 'http://activitiesservice.manfredfris.ch/activity/new',
//     // path: 'http://' + Microservices.activities.uri + '/activity/new',
//
//     // host: 'activitiesservice.manfredfris.ch',
//     host: Microservices.activities.uri,
//     port: 80,
//     path: '/activities/112233445566778899000671',
//   };
//
//   let req = http.get(options, (res) => {
//     // console.log('STATUS: ' + res.statusCode);
//     // console.log('HEADERS: ' + JSON.stringify(res.headers));
//     let body = '';
//     res.on('data', (chunk) => {
//       body += chunk;
//     });
//     res.on('end', () => {
//       let data = JSON.parse(body);
//       console.log(data);
//       return data;
//     });
//   });
//   req.on('error', (e) => {
//     console.log('problem with request: ' + e.message);
//   });
//
// }
//Insert mockup data to the collection
function insertMockupData() {
  //get real ids for the first 2 activities
  // const firstTwoActivities = getFirstTwoActivities();
  const firstTwoActivities = [
    {activity_id: '574d7da5d46fe91000cc3a77'},
    {activity_id: '574d7da5d46fe91000cc3a76'}
  ];
  let notification1 = {
    activity_id: firstTwoActivities[0].activity_id,
    activity_type: 'react',
    content_id: '112233445566778899000671',
    content_kind: 'slide',
    content_name: 'Introduction',
    user_id: '112233445566778899000002',
    react_type: 'like',
    subscribed_user_id: '112233445566778899000001'
  };
  let ins1 = notificationsDB.insert(notification1);
  let notification2 = {
    activity_id: firstTwoActivities[1].activity_id,
    activity_type: 'download',
    content_id: '112233445566778899000671',
    content_kind: 'slide',
    content_name: 'Introduction',
    user_id: '112233445566778899000001',
    subscribed_user_id: '112233445566778899000001'
  };
  let ins2 = ins1.then(() => notificationsDB.insert(notification2));

  return ins2;
}

let authorsMap = new Map([
  ['112233445566778899000001', {
    id: 7,
    username: 'Dejan P.',
    avatar: '/assets/images/mock-avatars/deadpool_256.png'
  }],
  ['112233445566778899000002', {
    id: 8,
    username: 'Nikola T.',
    avatar: '/assets/images/mock-avatars/man_512.png'
  }],
  ['112233445566778899000003', {
    id: 9,
    username: 'Marko B.',
    avatar: '/assets/images/mock-avatars/batman_512.jpg'
  }],
  ['112233445566778899000004', {
    id: 10,
    username: 'Valentina J.',
    avatar: '/assets/images/mock-avatars/ninja-simple_512.png'
  }],
  ['112233445566778899000005', {
    id: 11,
    username: 'Voice in the crowd',
    avatar: '/assets/images/mock-avatars/anon_256.jpg'
  }],
  ['112233445566778899000006', {
    id: 12,
    username: 'SlideWiki FTW',
    avatar: '/assets/images/mock-avatars/spooky_256.png'
  }],
  ['112233445566778899000000', {
    id: 13,
    username: 'Dutch',
    avatar: '/assets/images/mock-avatars/dgirl.jpeg'
  }]
]);
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015, Facility for Rare Isotope Beams
 *
 */

$('#lattice_name').typeahead({}, {
	source:function(query, syncResults, asyncResults) {
		latticemodel.data.find_lattice_names(query, asyncResults);
	}
});

$('#lattice_branch').typeahead({}, {
	source:function(query, syncResults, asyncResults) {
		latticemodel.data.find_lattice_branches(query, asyncResults);
	}
});

$('#lattice_autoversion').on('change', function() {
	$('#lattice_version').val('').prop('disabled', this.checked);
});

<commit_msg>Update typeahead configuration for IMPACT Lattice upload.<commit_after>/*
 * Copyright (c) 2015, Facility for Rare Isotope Beams
 *
 */

$('#lattice_name').typeahead({hint:false}, {
	source:function(query, syncResults, asyncResults) {
		latticemodel.data.find_lattice_names(query, asyncResults);
	},
	limit:10
});

$('#lattice_branch').typeahead({hint:false}, {
	source:function(query, syncResults, asyncResults) {
		latticemodel.data.find_lattice_branches(query, asyncResults);
	},
	limit:10
});

$('#lattice_autoversion').on('change', function() {
	$('#lattice_version').val('').prop('disabled', this.checked);
});

<|endoftext|>


<commit_before>define(
  'ephox.alloy.api.system.ForeignGui',

  [
    'ephox.alloy.api.component.GuiFactory',
    'ephox.alloy.api.system.Gui',
    'ephox.alloy.events.DescribedHandler',
    'ephox.alloy.foreign.ForeignCache',
    'ephox.alloy.registry.Tagger',
    'ephox.boulder.api.FieldSchema',
    'ephox.boulder.api.Objects',
    'ephox.boulder.api.ValueSchema',
    'ephox.katamari.api.Arr',
    'ephox.katamari.api.Cell',
    'ephox.katamari.api.Fun',
    'ephox.katamari.api.Options',
    'ephox.sugar.api.dom.Insert',
    'ephox.sugar.api.events.DomEvent'
  ],

  function (GuiFactory, Gui, DescribedHandler, ForeignCache, Tagger, FieldSchema, Objects, ValueSchema, Arr, Cell, Fun, Options, Insert, DomEvent) {
    var schema = ValueSchema.objOf([
      FieldSchema.strict('root'),
      FieldSchema.strictArrayOfObj('dispatchers', [
        FieldSchema.strict('getTarget'),
        FieldSchema.strict('alloyConfig')
      ]),
      FieldSchema.defaulted('insertion', function (root, system) {
        Insert.append(root, system.element());
      })
    ]);

    var supportedEvents = [
      'click', 'mousedown', 'mousemove', 'touchstart', 'touchend', 'gesturestart'
    ];

    // Find the dispatcher information for the target if available. Note, the
    // dispatcher may also change the target.
    var findDispatcher = function (dispatchers, target) {
      return Options.findMap(dispatchers, function (dispatcher) {
        return dispatcher.getTarget()(target).map(function (newTarget) {
          return {
            target: Fun.constant(newTarget),
            dispatcher: Fun.constant(dispatcher)
          };
        });
      });
    };

    var createEvent = function (event, target) {
      var source = Cell(target);

      var stopper = Cell(false);

      var cutter = Cell(false);

      var stop = function () {
        stopper.set(true);
      };

      var cut = function () {
        cutter.set(true);
      };

      return {
        stop: stop,
        cut: cut,
        event: Fun.constant(event),
        setSource: source.set,
        getSource: source.get
      };
    };

    var getProxy = function (event, target) {
      // Setup the component wrapping for the target element
      var component = GuiFactory.build(
        GuiFactory.external({ element: target })
      );

      // Create a simulated event
      var simulatedEvent = createEvent(event, target);

      return {
        component: Fun.constant(component),
        simulatedEvent: Fun.constant(simulatedEvent)
      };
    };

    var engage = function (spec) {
      var detail = ValueSchema.asStructOrDie('ForeignGui', schema, spec);

      // Creates an inner GUI and inserts it appropriately. This will be used
      // as the system for all behaviours
      var gui = Gui.create();
      detail.insertion()(detail.root(), gui);

      var cache = ForeignCache();

      var domEvents = Arr.map(supportedEvents, function (type) {
        return DomEvent.bind(detail.root(), type, function (event) {
          dispatchTo(type, event);
        });
      });

      var proxyFor = function (event, target, descHandler) {
        // create a simple alloy wrapping around the element, and add it to the world
        var proxy = getProxy(event, target);
        var component = proxy.component();
        gui.addToWorld(component);
        // fire the event
        var handler = DescribedHandler.getHandler(descHandler);
        handler(component, proxy.simulatedEvent());

        // now remove from the world and
        unproxy(component);
      };

      var dispatchTo = function (type, event) {
        // Do not delegate anything that happened within the internal system. It is
        // already being handled.
        if (gui.element().dom().contains(event.target().dom())) return;

        // Find if the target has an assigned dispatcher
        findDispatcher(detail.dispatchers(), event.target()).each(function (dispatchData) {
          var target = dispatchData.target();
          var dispatcher = dispatchData.dispatcher();

          // get any info for this current element, creating it if necessary
          var data = cache.getEvents(target, dispatcher.alloyConfig());
          var events = data.evts();

          // if this dispatcher defines this event, proxy it and fire the handler\
          if (Objects.hasKey(events, type)) proxyFor(event, target, events[type]);
        });
      };

      // Remove any traces of the foreign component from the internal alloy system.
      var unproxy = function (component) {
        gui.removeFromWorld(component);
        Tagger.revoke(component.element());
      };

      var disengage = function () {
        Arr.each(domEvents, function (e) {
          e.unbind();
        });
      };

      return {
        dispatchTo: dispatchTo,
        unproxy: unproxy,
        disengage: disengage
      };
    };

    return {
      engage: engage
    };
  }
);
<commit_msg>TM-12: slightly clearer explanations<commit_after>define(
  'ephox.alloy.api.system.ForeignGui',

  [
    'ephox.alloy.api.component.GuiFactory',
    'ephox.alloy.api.system.Gui',
    'ephox.alloy.events.DescribedHandler',
    'ephox.alloy.foreign.ForeignCache',
    'ephox.alloy.registry.Tagger',
    'ephox.boulder.api.FieldSchema',
    'ephox.boulder.api.Objects',
    'ephox.boulder.api.ValueSchema',
    'ephox.katamari.api.Arr',
    'ephox.katamari.api.Cell',
    'ephox.katamari.api.Fun',
    'ephox.katamari.api.Options',
    'ephox.sugar.api.dom.Insert',
    'ephox.sugar.api.events.DomEvent'
  ],

  function (GuiFactory, Gui, DescribedHandler, ForeignCache, Tagger, FieldSchema, Objects, ValueSchema, Arr, Cell, Fun, Options, Insert, DomEvent) {
    var schema = ValueSchema.objOf([
      FieldSchema.strict('root'),
      FieldSchema.strictArrayOfObj('dispatchers', [
        FieldSchema.strict('getTarget'),
        FieldSchema.strict('alloyConfig')
      ]),
      FieldSchema.defaulted('insertion', function (root, system) {
        Insert.append(root, system.element());
      })
    ]);

    var supportedEvents = [
      'click', 'mousedown', 'mousemove', 'touchstart', 'touchend', 'gesturestart'
    ];

    // Find the dispatcher information for the target if available. Note, the
    // dispatcher may also change the target.
    var findDispatcher = function (dispatchers, target) {
      return Options.findMap(dispatchers, function (dispatcher) {
        return dispatcher.getTarget()(target).map(function (newTarget) {
          return {
            target: Fun.constant(newTarget),
            dispatcher: Fun.constant(dispatcher)
          };
        });
      });
    };

    var createEvent = function (event, target) {
      var source = Cell(target);

      var stopper = Cell(false);

      var cutter = Cell(false);

      var stop = function () {
        stopper.set(true);
      };

      var cut = function () {
        cutter.set(true);
      };

      return {
        stop: stop,
        cut: cut,
        event: Fun.constant(event),
        setSource: source.set,
        getSource: source.get
      };
    };

    var getProxy = function (event, target) {
      // Setup the component wrapping for the target element
      var component = GuiFactory.build(
        GuiFactory.external({ element: target })
      );

      // Create a simulated event
      var simulatedEvent = createEvent(event, target);

      return {
        component: Fun.constant(component),
        simulatedEvent: Fun.constant(simulatedEvent)
      };
    };

    var engage = function (spec) {
      var detail = ValueSchema.asStructOrDie('ForeignGui', schema, spec);

      // Creates an inner GUI and inserts it appropriately. This will be used
      // as the system for all behaviours
      var gui = Gui.create();
      detail.insertion()(detail.root(), gui);

      var cache = ForeignCache();

      var domEvents = Arr.map(supportedEvents, function (type) {
        return DomEvent.bind(detail.root(), type, function (event) {
          dispatchTo(type, event);
        });
      });

      var proxyFor = function (event, target, descHandler) {
        // create a simple alloy wrapping around the element, and add it to the world
        var proxy = getProxy(event, target);
        var component = proxy.component();
        gui.addToWorld(component);
        // fire the event
        var handler = DescribedHandler.getHandler(descHandler);
        handler(component, proxy.simulatedEvent());

        // now remove from the world and revoke any alloy ids
        unproxy(component);
      };

      var dispatchTo = function (type, event) {
        // Do not delegate anything that happened within the internal system. It is
        // already being handled.
        if (gui.element().dom().contains(event.target().dom())) return;

        // Find if the target has an assigned dispatcher
        findDispatcher(detail.dispatchers(), event.target()).each(function (dispatchData) {
          var target = dispatchData.target();
          var dispatcher = dispatchData.dispatcher();

          // get any info for this current element, creating it if necessary
          var data = cache.getEvents(target, dispatcher.alloyConfig());
          var events = data.evts();

          // if this dispatcher defines this event, proxy it and fire the handler\
          if (Objects.hasKey(events, type)) proxyFor(event, target, events[type]);
        });
      };

      // Remove any traces of the foreign component from the internal alloy system.
      var unproxy = function (component) {
        gui.removeFromWorld(component);
        Tagger.revoke(component.element());
      };

      var disengage = function () {
        Arr.each(domEvents, function (e) {
          e.unbind();
        });
      };

      return {
        dispatchTo: dispatchTo,
        unproxy: unproxy,
        disengage: disengage
      };
    };

    return {
      engage: engage
    };
  }
);
<|endoftext|>


<commit_before>var Map = {
  dataInput: [],
  defaultView: function(topic, mapData, width) {
    var self = this,
        width = width,
        title = topic;
    $('#map-container').highcharts('Map', {
      chart: {
        width: width,
        height: 800,
        backgroundColor: '#FFFFFF'
      },
      title: {
        text: "",
        style: {
          color: '#0099CC',
          font: '36px "HelveticaNeue", Arial, sans-serif'
        }
      },
      mapNavigation: {
        enabled: true,
        buttonOptions: {
          align: 'right',
          verticalAlign: 'bottom'
        },
        enableMouseWheelZoom: false
      },
      colorAxis: {
        type: 'linear',
        endOnTick: false,
        startOnTick: false,
        min: -1,
        max: 1,
        stops: [
          [0, '#CC0033'],
          [0.5, '#FFFFFF'],
          [1, '#00CC33']
        ],
      },
      colors: ['#0099CC'],
      tooltip: {
        animation: true,
        shadow: false,
        followPointer: true,
        headerFormat: '{series.name}
',
        pointFormat: '{point.name}
S: {point.value} | TS: {point.overall} | TC: {point.tweet_count}
',
        footerFormat: 'Source: AlchemyAPI',
        hideDelay: 50
      },
      legend: {
        align: 'center',
        itemWidth: 200,
        reversed: false,
        title: {
          text: 'Sentiment Index',
          style: {
            color: '#333',
            font: '16px "HelveticaNeue", Arial, sans-serif',
            fontWeight: 'normal'

          }
        }
      },
      plotOptions: {
        series: {
          joinBy: ['iso-a2', 'code'],
        },
        states: {
          hover: {
            enabled: true
          },
          select: {
            borderColor: 'black',
            dashStyle: 'shortdot',
            color: '#B4DA55'
          }
        }
      },
      series: [{
        data: self.dataInput,
        mapData: mapData,
        name: 'Sentiment Analysis',
      }]
    })
  }
};

var createMapView = {
  init: function(trend, tweetData) {
    var map = Highcharts.maps['custom/world'];
    var mapData = Highcharts.geojson(map);
    this.inputData(tweetData);
    this.layoutMap(trend, mapData);
  },
  inputData: function(data) {
    Map.dataInput = [];
    for (var i in data) {
      Map.dataInput.push(data[i]);
    }
  },
  layoutMap: function(topic, mapData) {
    var deviceWidth = this.setMapWidth();
    Map.defaultView(topic, mapData, deviceWidth);
    this.addMapTitle(topic);
  },
  setMapWidth: function() {
    var $width = $(document).width();
    var mapPadding = 50;
    return $width - (mapPadding * 2);
  },
  addMapTitle: function(title) {
    $('h2').html(title);
  }
};

<commit_msg>change key title<commit_after>var Map = {
  dataInput: [],
  defaultView: function(topic, mapData, width) {
    var self = this,
        width = width,
        title = topic;
    $('#map-container').highcharts('Map', {
      chart: {
        width: width,
        height: 800,
        backgroundColor: '#FFFFFF'
      },
      title: {
        text: "",
        style: {
          color: '#0099CC',
          font: '36px "HelveticaNeue", Arial, sans-serif'
        }
      },
      mapNavigation: {
        enabled: true,
        buttonOptions: {
          align: 'right',
          verticalAlign: 'bottom'
        },
        enableMouseWheelZoom: false
      },
      colorAxis: {
        type: 'linear',
        endOnTick: false,
        startOnTick: false,
        min: -1,
        max: 1,
        stops: [
          [0, '#CC0033'],
          [0.5, '#FFFFFF'],
          [1, '#00CC33']
        ],
      },
      colors: ['#0099CC'],
      tooltip: {
        animation: true,
        shadow: false,
        followPointer: true,
        headerFormat: '{series.name}
',
        pointFormat: '{point.name}
S: {point.value} | TS: {point.overall} | TC: {point.tweet_count}
',
        footerFormat: 'Source: AlchemyAPI',
        hideDelay: 50
      },
      legend: {
        reversed: false,
        title: {
          text: ' red is negative | green is positive',
          style: {
            color: '#333',
            font: '13.5px "HelveticaNeue", Arial, sans-serif',
            fontWeight: 'normal'
          }
        }
      },
      plotOptions: {
        series: {
          joinBy: ['iso-a2', 'code'],
        },
        states: {
          hover: {
            enabled: true
          },
          select: {
            borderColor: 'black',
            dashStyle: 'shortdot',
            color: '#B4DA55'
          }
        }
      },
      series: [{
        data: self.dataInput,
        mapData: mapData,
        name: 'Sentiment Analysis',
      }]
    })
  }
};

var createMapView = {
  init: function(trend, tweetData) {
    var map = Highcharts.maps['custom/world'];
    var mapData = Highcharts.geojson(map);
    this.inputData(tweetData);
    this.layoutMap(trend, mapData);
  },
  inputData: function(data) {
    Map.dataInput = [];
    for (var i in data) {
      Map.dataInput.push(data[i]);
    }
  },
  layoutMap: function(topic, mapData) {
    var deviceWidth = this.setMapWidth();
    Map.defaultView(topic, mapData, deviceWidth);
    this.addMapTitle(topic);
  },
  setMapWidth: function() {
    var $width = $(document).width();
    var mapPadding = 50;
    return $width - (mapPadding * 2);
  },
  addMapTitle: function(title) {
    $('h2').html(title);
  }
};

<|endoftext|>


<commit_before>var cy;
var default_node_width = 200;
var default_node_height = 65;
var default_font_size = 16;
var default_color = '#323232';
var default_text_max_width = 195;
var background_image_size = default_node_height - 10;
var originNode;

jQuery.noConflict();
var $j = jQuery;

function drawGraph(elements, current_element_id){
    cy=cytoscape({
        container: document.getElementById('cy'),

        userZoomingEnabled: false,
        panningEnabled: true,
        userPanningEnabled: true,

        layout: {
            name: 'breadthfirst',
            directed: true,
            spacingFactor: 1.25,
            padding: 50
        },

        style: [
            {
                selector: 'node',
                css: {
                    'shape': 'roundrectangle',
                    'border-color': 'data(borderColor)',
                    'border-width': 2,
                    'das': 'mapData(weight, 40, 80, 20, 60)',
                    'content': 'data(name)',
                    'text-valign': 'center',
                    'text-outline-width': 1,
                    'text-outline-color': 'data(faveColor)',
                    'background-color': 'data(faveColor)',
                    'padding-left': background_image_size + 10,
                    'padding-right': background_image_size + 10,
                    'color': default_color,
                    'width': default_node_width,
                    'height': default_node_height,
                    'font-size': default_font_size,
                    'text-wrap': 'wrap',
                    'text-max-width': default_text_max_width
                }
            },
            {
                selector: 'node[imageUrl]',
                css: {
                    'background-image': 'data(imageUrl)',
                    'background-width': background_image_size,
                    'background-height': background_image_size,
                    // The following is a hacky way of making sure the image doesn't overlap the text
                    'background-position-x': -background_image_size,
                    'background-position-y': '50%'
                }
            },
            {
                selector: 'edge',
                css: {
                    'width': 1.5,
                    'target-arrow-shape': 'none',
                    'line-color': '#191975',
                    'source-arrow-color': 'data(faveColor)',
                    'target-arrow-color': 'data(faveColor)',
                    'content': 'data(name)',
                    'color': '#222222',
                    'text-background-color': '#eeeeff',
                    'text-background-shape': 'roundrectangle',
                    'text-background-opacity': 0.7,
                    'text-border-width': 1,
                    'text-border-style': 'solid',
                    'text-border-color': '#ccccdd',
                    'text-border-opacity': 0.7,
                    'font-size': (default_font_size)
                }
            },
            {
                selector: ':selected',
                css: {
                    'font-weight': 'bold',
                    'font-size': default_font_size,
                    'text-max-width': default_text_max_width + 15
                }
            }
        ],
        elements: elements,

        ready: function(){
            var nodes = cy.$('node');

            //process only when having nodes
            if (nodes.length > 0){
                //animate the current node
                originNode = cy.nodes('[id=\''+ current_element_id +'\']')[0];
                originNode.select();
                cy.animate({ zoom: 0.75, center: { eles: originNode } });
            }else{
                $j('.isa_graph')[0].hide();
            }
        }
    });
    cy.panzoom({
        panSpeed: 1,
        zoomInIcon: 'glyphicon glyphicon-plus',
        zoomOutIcon: 'glyphicon glyphicon-minus',
        resetIcon: 'glyphicon glyphicon-resize-full'
    });

    cy.on('tap', 'node:selected', function (event) {
        if(event.cyTarget != originNode && event.cyTarget.data('url'))
            window.location = event.cyTarget.data('url');
    });

    cy.on('select', 'node', function (event) {
        animateNode(event.cyTarget);
        displayNodeInfo(event.cyTarget);
    });
}

function animateNode(node){
    var nodes = cy.$('node');
    var edges = cy.$('edge');

    var excluded_selected_nodes = [];
    for (var i=0; i<nodes.length; i++){
        var node_tmp = nodes[i];
        if (node_tmp.data().id !== node.data().id)
            excluded_selected_nodes.push(node_tmp);
    }

    //first normalizing all nodes and fading all nodes and edges
    normalizingNodes(excluded_selected_nodes);

    fadingNodes(nodes);
    fadingEdges(edges);

    //then appearing the chosen node and the connected nodes and edges
    appearingNodes(node);
    edges.each(function(i, edge){
        var source = edge.source();
        var target =edge.target();
        if (source.id() === node.id()){
            appearingEdges(edge);
            appearingNodes(target);
        }
        if (target.id() === node.id()){
            appearingEdges(edge);
            appearingNodes(source);
        }
    });

    node.animate({
        css: { 'width':default_node_width+35, 'height':default_node_height+15 }
    }, {
        duration: 300
    });

    cy.animate({ center: { eles: cy.$(':selected') } });
}

function displayNodeInfo(node) {
    html = "
Selected item: ";
    var item_data = node.data();
    html += itemInfo(item_data);
    html += '
';

    var node_info = $('node_info');
    $('node_info').innerHTML = html;
}

function itemInfo(item_data){
    var html = '';
    html += item_data.item_info;
    html += '';
    return html;
}

function connectedNodes(node){
    var edges = cy.$('edge');
    var connected_nodes = [];
    edges.each(function(i, edge){
        var source = edge.source();
        var target =edge.target();
        if (source.id() === node.id()){
            connected_nodes.push(target);
        }
        if (target.id() === node.id()){
            connected_nodes.push(source);
        }
    });
    return connected_nodes;
}

function alignCenterVertical(element, element_height){
    var graph_height = cy.container().style.height.split('px')[0];
    var distance_from_top = (graph_height - element_height)/2;
    if (distance_from_top > 0){
        element.style.top=distance_from_top+'px';
    }else{
        element.style.top='0px';
    }
}

function appearingNodes(nodes){
    nodes.css({'opacity': 1});
}

function appearingEdges(edges){
    edges.css({'opacity': 1});
}

function fadingNodes(nodes){
    nodes.css({'opacity': 0.6});
}

function fadingEdges(edges){
    edges.css({'opacity': 0.5});
}

function normalizingNodes(nodes){
    for (var i=0; i<nodes.length; i++){
        var node = nodes[i];
        node.css({
            'width': default_node_width,
            'height': default_node_height,
            'font-size': default_font_size,
            'font-weight': 'normal',
            'color': default_color,
            'text-max-width': default_text_max_width
        });
        node.unselect();

    }
}

function labelPosition(node, label_part, line_index, total_line){
    var label_pos = {};
    var graph_pos = $j('#cy')[0].getBoundingClientRect();
    var node_posX = node.renderedPosition().x + graph_pos.left;
    var node_posY = node.renderedPosition().y + graph_pos.top;
    var font_size = node.renderedCss()['font-size'];
    var ruler = $j('#ruler')[0];
    ruler.style.fontSize = font_size;
    ruler.style.fontWeight = 'bolder';
    ruler.innerHTML = label_part;
    var label_width = ruler.offsetWidth;
    var label_height = ruler.offsetHeight;
    label_pos.minX = node_posX - label_width/2;
    label_pos.maxX = node_posX + label_width/2;
    label_pos.maxY = node_posY + (line_index - total_line/2)*label_height;
    label_pos.minY = label_pos.maxY - label_height;

    return label_pos;
}

function labelLines(node){
    var label = node.data().name;
    var font_size = node.renderedCss()['font-size'];
    var ruler = $j('#ruler')[0];
    ruler.style.fontSize = font_size;
    //ruler.style.fontWeight = 'bolder';
    ruler.innerHTML = label;
    var label_width = ruler.offsetWidth;
    var text_max_width = node.renderedCss()['text-max-width'];
    var max_width = text_max_width.split('px')[0];
    var max_width_integer = parseInt(max_width);
    var lines = [];
    if (label_width > max_width_integer){
        var words = label.split(' ');
        var line = '';
        for( var i=0; i<words.length; i++){
            var testLine = line + words[i] + ' ';
            ruler.innerHTML = testLine;
            var testWidth = ruler.offsetWidth;
            if (testWidth > max_width_integer && i > 0) {
                lines.push(line.trim());
                line = words[i] + ' ';
            }
            else {
                line = testLine;
            }
            //when last word, push line to lines
            if (i === words.length-1){
                lines.push(line.trim());
            }
        }
    }else{
        lines.push(label);
    }
    return lines;
}

function decodeHTMLForElements(elements){
    for( var i=0; i<elements.length; i++){
        elements[i].data.name = decodeHTML(elements[i].data.name);
        elements[i].data.item_info = decodeHTML(elements[i].data.item_info);
    }
}
<commit_msg>Simplified the node selection animation code<commit_after>var cy;
var default_node_width = 200;
var default_node_height = 65;
var default_font_size = 16;
var default_color = '#323232';
var default_text_max_width = 195;
var background_image_size = default_node_height - 10;
var originNode;

jQuery.noConflict();
var $j = jQuery;

function drawGraph(elements, current_element_id){
    cy=cytoscape({
        container: document.getElementById('cy'),

        userZoomingEnabled: false,
        panningEnabled: true,
        userPanningEnabled: true,

        layout: {
            name: 'breadthfirst',
            directed: true,
            spacingFactor: 1.25,
            padding: 50
        },

        style: [
            {
                selector: 'node',
                css: {
                    'shape': 'roundrectangle',
                    'border-color': 'data(borderColor)',
                    'border-width': 2,
                    'das': 'mapData(weight, 40, 80, 20, 60)',
                    'content': 'data(name)',
                    'text-valign': 'center',
                    'text-outline-width': 1,
                    'text-outline-color': 'data(faveColor)',
                    'background-color': 'data(faveColor)',
                    'padding-left': background_image_size + 10,
                    'padding-right': background_image_size + 10,
                    'color': default_color,
                    'width': default_node_width,
                    'height': default_node_height,
                    'font-size': default_font_size,
                    'text-wrap': 'wrap',
                    'text-max-width': default_text_max_width,
                    'opacity': 0.6
                }
            },
            {
                selector: 'node[imageUrl]',
                css: {
                    'background-image': 'data(imageUrl)',
                    'background-width': background_image_size,
                    'background-height': background_image_size,
                    // The following is a hacky way of making sure the image doesn't overlap the text
                    'background-position-x': -background_image_size,
                    'background-position-y': '50%'
                }
            },
            {
                selector: 'edge',
                css: {
                    'width': 1.5,
                    'target-arrow-shape': 'none',
                    'line-color': '#191975',
                    'source-arrow-color': 'data(faveColor)',
                    'target-arrow-color': 'data(faveColor)',
                    'content': 'data(name)',
                    'color': '#222222',
                    'text-background-color': '#eeeeff',
                    'text-background-shape': 'roundrectangle',
                    'text-background-opacity': 0.7,
                    'text-border-width': 1,
                    'text-border-style': 'solid',
                    'text-border-color': '#ccccdd',
                    'text-border-opacity': 0.7,
                    'font-size': (default_font_size),
                    'opacity': 0.5
                }
            },
            {
                selector: '.connected',
                css: {
                    'opacity': 1
                }
            },
            {
                selector: '.selected', // Note this is not the same as cytoscape's ':selected'
                css: {
                    'font-weight': 'bold',
                    'font-size': default_font_size,
                    'text-max-width': default_text_max_width + 15,
                    'width': default_node_width + 35,
                    'height': default_node_height + 15,
                    'transition-property': 'width, height',
                    'transition-duration': 300,
                    'opacity': 1
                }
            }
        ],
        elements: elements,

        ready: function(){
            var nodes = cy.$('node');

            //process only when having nodes
            if (nodes.length > 0){
                //animate the current node
                originNode = cy.nodes('[id=\''+ current_element_id +'\']')[0];
                originNode.select();
                cy.animate({ zoom: 0.75, center: { eles: originNode } });
            }else{
                $j('.isa_graph')[0].hide();
            }
        }
    });
    cy.panzoom({
        panSpeed: 1,
        zoomInIcon: 'glyphicon glyphicon-plus',
        zoomOutIcon: 'glyphicon glyphicon-minus',
        resetIcon: 'glyphicon glyphicon-resize-full'
    });

    cy.on('tap', 'node:selected', function (event) {
        if(event.cyTarget != originNode && event.cyTarget.data('url'))
            window.location = event.cyTarget.data('url');
    });

    cy.on('select', 'node', function (event) {
        animateNode(event.cyTarget);
        displayNodeInfo(event.cyTarget);
    });
}

function animateNode(node){
    //first normalizing all nodes and fading all nodes and edges
    cy.$('node.connected').removeClass('connected');
    cy.$('edge.connected').removeClass('connected');

    //then appearing the chosen node and the connected nodes and edges
    node.addClass('connected');
    node.connectedEdges().addClass('connected');
    node.connectedEdges().connectedNodes().addClass('connected');

    // Animate the selected node
    cy.$('node.selected').removeClass('selected');
    node.addClass('selected');

    // Center the view on the node
    cy.animate({ center: { eles: cy.$(':selected') } });
}

function displayNodeInfo(node) {
    html = "
Selected item: ";
    var item_data = node.data();
    html += itemInfo(item_data);
    html += '
';

    var node_info = $('node_info');
    $('node_info').innerHTML = html;
}

function itemInfo(item_data){
    var html = '';
    html += item_data.item_info;
    html += '';
    return html;
}

function decodeHTMLForElements(elements){
    for( var i=0; i<elements.length; i++){
        elements[i].data.name = decodeHTML(elements[i].data.name);
        elements[i].data.item_info = decodeHTML(elements[i].data.item_info);
    }
}
<|endoftext|>


<commit_before>MapStyle = {
  editStyle: function() {
    var styleRules = [new OpenLayers.Rule({
      symbolizer: {"Line" : {strokeWidth: 3}},
      elseFilter: true
      })];
    var styleMap = new OpenLayers.StyleMap();
    styleMap.styles["default"].addRules(styleRules);
    styleMap.styles["select"].addRules(styleRules);
    return styleMap;
  },

  displayStyle: function() {
    var styleRules = [new OpenLayers.Rule({
        symbolizer: { "Line" : { strokeWidth: 8,
                                strokeColor: '#00ff00',
                                strokeOpacity: 0.8 },
                      "Point" : { pointRadius: 14,
                                  strokeColor: '#004400',
                                  strokeOpacity: 0.9,
                                  strokeWidth: 2,
                                  fillOpacity: 0.3,
                                  fillColor: '#00ff00' },
                      "Polygon" : { strokeWidth: 2.5,
                                    strokeOpacity: 0.8,
                                    strokeColor: '#004400',
                                    fillColor: '#00ff00' }
                    },
        elseFilter: true
      })];
    var styleMap = new OpenLayers.StyleMap();
    styleMap.styles["default"].addRules(styleRules);
    styleMap.styles["select"].addRules(styleRules);
    return styleMap;
  }
}
<commit_msg>Use same display style when editing, and control the temporary style seen when editing<commit_after>MapStyle = {
  displayRules: [new OpenLayers.Rule({
      symbolizer: {"Line" : { strokeWidth: 8,
                              strokeColor: '#00ff00',
                              strokeOpacity: 0.8 },
                    "Point" : { pointRadius: 8,
                                strokeColor: '#004400',
                                strokeOpacity: 0.9,
                                strokeWidth: 2,
                                fillOpacity: 0.3,
                                fillColor: '#00ff00' },
                    "Polygon" : { strokeWidth: 2.5,
                                  strokeOpacity: 0.8,
                                  strokeColor: '#004400',
                                  fillColor: '#00ff00' }
      },
      elseFilter: true
  })],

  editRules: [new OpenLayers.Rule({
      symbolizer: {"Line" : { strokeWidth: 2,
                              strokeColor: '#000000',
                              strokeOpacity: 0.8 },
                    "Point" : { pointRadius: 8,
                                strokeColor: '#000000',
                                strokeOpacity: 0.9,
                                strokeWidth: 2,
                                fillOpacity: 0.3,
                                fillColor: '#000000' },
                    "Polygon" : { strokeWidth: 2.5,
                                  strokeOpacity: 0.8,
                                  strokeColor: '#000000',
                                  fillColor: '#000000' }
      },
      elseFilter: true
  })],

  editStyle: function() {
    var styleMap = new OpenLayers.StyleMap();
    styleMap.styles["default"].addRules(this.displayRules);
    styleMap.styles["select"].addRules(this.displayRules);
    styleMap.styles["temporary"].addRules(this.editRules);
    return styleMap;
  },

  displayStyle: function() {
    var styleMap = new OpenLayers.StyleMap();
    styleMap.styles["default"].addRules(this.displayRules);
    styleMap.styles["select"].addRules(this.displayRules);
    return styleMap;
  }
}
<|endoftext|>