<commit_before>(function() {

TG.load_templates = function() {
    TG.templates = {};
    $('.template-src').each(function() {
        var name = $(this).attr('data-name');
        var template = _.template($(this).text());
        TG.templates[name] = template;
    });
};

TG.MapLayerCollection = Backbone.Collection.extend();

TG.Layer = Backbone.Model.extend();

TG.MapLayer = Backbone.View.extend({
    initialize: function(options) {
        this.olLayer = options['olLayer'];
        this.olLayer.events.register('visibilitychanged',
                                     this, this.mapUpdateVisibility);
        this.mapUpdateVisibility();
        this.model.on('change:visible', this.modelUpdateVisibility, this);
    },

    modelUpdateVisibility: function(model, visible) {
        if(this.olLayer.isBaseLayer) {
            if(visible) {
                this.olLayer.map.setBaseLayer(this.olLayer);
            }
        }
        else {
            this.olLayer.setVisibility(visible);
        }
    },

    mapUpdateVisibility: function(options) {
        this.model.set('visible', this.olLayer.visibility);
    }
});

TG.Map = Backbone.View.extend({

    tagName: 'div',
    id: 'tinygis-map',

    initialize: function() {
        this.parent = this.options['parent'];
        this.$el.prependTo(this.parent);
        this.olMap = new OpenLayers.Map(this.el.id);

        this.baseLayerCollection = new TG.MapLayerCollection;
        this.overlayCollection = new TG.MapLayerCollection;
        this.olMap.events.register('addlayer', this, this.layerAdded);

        var osm_layer = new OpenLayers.Layer.OSM("OpenStreetMap");
        this.olMap.addLayer(osm_layer);
        this.olMap.setCenter(this.project(new OpenLayers.LonLat(25, 46)), 7);

        this.olMap.events.register("mousemove", this, function(e) {
            lonLat = this.invproject(this.olMap.getLonLatFromPixel(e.xy));
            this.trigger("mousemove", {lng: lonLat.lon, lat: lonLat.lat});
        });

        this.olMap.addControl(new OpenLayers.Control.LayerSwitcher());
    },

    layerAdded: function(evt) {
        var olLayer = evt.layer;
        var collection = (olLayer.isBaseLayer
                          ? this.baseLayerCollection
                          : this.overlayCollection);
        var layer = collection.get(olLayer.id);
        if(layer === undefined) {
            layer = new TG.Layer({
                id: olLayer.id,
                name: olLayer.name
            });
            collection.add(layer);
        }
        var mapLayer = new TG.MapLayer({model: layer, olLayer: olLayer});
    },

    updateSize: function() {
        this.olMap.updateSize();
    },

    project: function(value) {
        var wgs84 = new OpenLayers.Projection("EPSG:4326");
        var map_proj = this.olMap.getProjectionObject();
        return value.transform(wgs84, map_proj);
    },

    invproject: function(value) {
        var wgs84 = new OpenLayers.Projection("EPSG:4326");
        var map_proj = this.olMap.getProjectionObject();
        return value.transform(map_proj, wgs84);
    },

    addOverlay: function(olLayer, options) {
        if(options === undefined) { options = {}; }
        if(options['model'] !== undefined) {
            this.overlayCollection.add(options['model'], options);
        }
        this.olMap.addLayer(olLayer);
    },

    addBingLayers: function(bingKey) {
        var road = new OpenLayers.Layer.Bing({
            name: "Bing Road",
            key: bingKey,
            type: "Road"
        });
        var hybrid = new OpenLayers.Layer.Bing({
            name: "Bing Hybrid",
            key: bingKey,
            type: "AerialWithLabels"
        });
        var aerial = new OpenLayers.Layer.Bing({
            name: "Bing Aerial",
            key: bingKey,
            type: "Aerial"
        });
        this.olMap.addLayers([road, hybrid, aerial]);
    },

    addGoogleLayers: function() {
        var gsat = new OpenLayers.Layer.Google("Google Satellite", {
            type: google.maps.MapTypeId.SATELLITE,
            animationEnabled: false,
            numZoomLevels: 22
        });
        var gphy = new OpenLayers.Layer.Google("Google Physical", {
            type: google.maps.MapTypeId.TERRAIN,
            animationEnabled: false
        });
        var gmap = new OpenLayers.Layer.Google("Google Streets", {
            animationEnabled: false,
            numZoomLevels: 20
        });
        var ghyb = new OpenLayers.Layer.Google("Google Hybrid", {
            type: google.maps.MapTypeId.HYBRID,
            animationEnabled: false,
            numZoomLevels: 22
        });
        this.olMap.addLayers([gsat, gphy, gmap, ghyb]);
    }

});

TG.TileLayer = Backbone.Model.extend({
    initialize: function() {
        this.olLayer = new OpenLayers.Layer.XYZ(
            this.attributes.name,
            this.attributes.url_template,
            {
                isBaseLayer: false,
                sphericalMercator: true
            }
        );
    }
});

TG.Identify = Backbone.Model.extend({

    initialize: function() {
        this._pending = false;
        this._in_flight = false;
    },

    updateCoordinates: function(coords) {
        this.set(coords);
        this._next_coords = coords;
        this._pending = true;
        this._tick();
    },

    _tick: function() {
        if(this._in_flight) { return; }
        if(! this._pending) { return; }
        this._in_flight = true;
        this._pending = false;
        this.trigger('update-start');
        $.ajax({
            url: 'get_features_at',
            data: {lat: this.get('lat'), lng: this.get('lng')},
            context: this
        }).done(function(data) {
            this.set(_.extend({error: false}, data));
            this.trigger('change');
        }).fail(function() {
            this.set({error: true, hit_list: []});
            this.trigger('change');
            this.trigger('update-error');
        }).always(function() {
            this._in_flight = false;
            this.trigger('update-end');
            this._tick();
        });
    }

});

TG.IdentifyView = Backbone.View.extend({
    tagName: 'div',
    className: 'identify',
    templateName: 'identify',

    initialize: function() {
        this.model.on('change', this.render, this);
        this.model.on('update-start', function() {
            this.$el.addClass('update-in-progress');
        }, this);
        this.model.on('update-end', function() {
            this.$el.removeClass('update-in-progress');
        }, this);
    },

    render: function() {
        var template = TG.templates[this.templateName];
        this.$el.html(template(this.model.attributes));
    }

});

})();
<commit_msg>add layer to collection after creating view<commit_after>(function() {

TG.load_templates = function() {
    TG.templates = {};
    $('.template-src').each(function() {
        var name = $(this).attr('data-name');
        var template = _.template($(this).text());
        TG.templates[name] = template;
    });
};

TG.MapLayerCollection = Backbone.Collection.extend();

TG.Layer = Backbone.Model.extend();

TG.MapLayer = Backbone.View.extend({
    initialize: function(options) {
        this.olLayer = options['olLayer'];
        this.olLayer.events.register('visibilitychanged',
                                     this, this.mapUpdateVisibility);
        this.mapUpdateVisibility();
        this.model.on('change:visible', this.modelUpdateVisibility, this);
    },

    modelUpdateVisibility: function(model, visible) {
        if(this.olLayer.isBaseLayer) {
            if(visible) {
                this.olLayer.map.setBaseLayer(this.olLayer);
            }
        }
        else {
            this.olLayer.setVisibility(visible);
        }
    },

    mapUpdateVisibility: function(options) {
        this.model.set('visible', this.olLayer.visibility);
    }
});

TG.Map = Backbone.View.extend({

    tagName: 'div',
    id: 'tinygis-map',

    initialize: function() {
        this.parent = this.options['parent'];
        this.$el.prependTo(this.parent);
        this.olMap = new OpenLayers.Map(this.el.id);

        this.baseLayerCollection = new TG.MapLayerCollection;
        this.overlayCollection = new TG.MapLayerCollection;
        this.olMap.events.register('addlayer', this, this.layerAdded);

        var osm_layer = new OpenLayers.Layer.OSM("OpenStreetMap");
        this.olMap.addLayer(osm_layer);
        this.olMap.setCenter(this.project(new OpenLayers.LonLat(25, 46)), 7);

        this.olMap.events.register("mousemove", this, function(e) {
            lonLat = this.invproject(this.olMap.getLonLatFromPixel(e.xy));
            this.trigger("mousemove", {lng: lonLat.lon, lat: lonLat.lat});
        });

        this.olMap.addControl(new OpenLayers.Control.LayerSwitcher());
    },

    layerAdded: function(evt) {
        var olLayer = evt.layer;
        var collection = (olLayer.isBaseLayer
                          ? this.baseLayerCollection
                          : this.overlayCollection);
        var layer = collection.get(olLayer.id);
        if(layer === undefined) {
            layer = new TG.Layer({
                id: olLayer.id,
                name: olLayer.name
            });
        }
        var mapLayer = new TG.MapLayer({model: layer, olLayer: olLayer});
        collection.add(layer);
    },

    updateSize: function() {
        this.olMap.updateSize();
    },

    project: function(value) {
        var wgs84 = new OpenLayers.Projection("EPSG:4326");
        var map_proj = this.olMap.getProjectionObject();
        return value.transform(wgs84, map_proj);
    },

    invproject: function(value) {
        var wgs84 = new OpenLayers.Projection("EPSG:4326");
        var map_proj = this.olMap.getProjectionObject();
        return value.transform(map_proj, wgs84);
    },

    addOverlay: function(olLayer, options) {
        if(options === undefined) { options = {}; }
        if(options['model'] !== undefined) {
            this.overlayCollection.add(options['model'], options);
        }
        this.olMap.addLayer(olLayer);
    },

    addBingLayers: function(bingKey) {
        var road = new OpenLayers.Layer.Bing({
            name: "Bing Road",
            key: bingKey,
            type: "Road"
        });
        var hybrid = new OpenLayers.Layer.Bing({
            name: "Bing Hybrid",
            key: bingKey,
            type: "AerialWithLabels"
        });
        var aerial = new OpenLayers.Layer.Bing({
            name: "Bing Aerial",
            key: bingKey,
            type: "Aerial"
        });
        this.olMap.addLayers([road, hybrid, aerial]);
    },

    addGoogleLayers: function() {
        var gsat = new OpenLayers.Layer.Google("Google Satellite", {
            type: google.maps.MapTypeId.SATELLITE,
            animationEnabled: false,
            numZoomLevels: 22
        });
        var gphy = new OpenLayers.Layer.Google("Google Physical", {
            type: google.maps.MapTypeId.TERRAIN,
            animationEnabled: false
        });
        var gmap = new OpenLayers.Layer.Google("Google Streets", {
            animationEnabled: false,
            numZoomLevels: 20
        });
        var ghyb = new OpenLayers.Layer.Google("Google Hybrid", {
            type: google.maps.MapTypeId.HYBRID,
            animationEnabled: false,
            numZoomLevels: 22
        });
        this.olMap.addLayers([gsat, gphy, gmap, ghyb]);
    }

});

TG.TileLayer = Backbone.Model.extend({
    initialize: function() {
        this.olLayer = new OpenLayers.Layer.XYZ(
            this.attributes.name,
            this.attributes.url_template,
            {
                isBaseLayer: false,
                sphericalMercator: true
            }
        );
    }
});

TG.Identify = Backbone.Model.extend({

    initialize: function() {
        this._pending = false;
        this._in_flight = false;
    },

    updateCoordinates: function(coords) {
        this.set(coords);
        this._next_coords = coords;
        this._pending = true;
        this._tick();
    },

    _tick: function() {
        if(this._in_flight) { return; }
        if(! this._pending) { return; }
        this._in_flight = true;
        this._pending = false;
        this.trigger('update-start');
        $.ajax({
            url: 'get_features_at',
            data: {lat: this.get('lat'), lng: this.get('lng')},
            context: this
        }).done(function(data) {
            this.set(_.extend({error: false}, data));
            this.trigger('change');
        }).fail(function() {
            this.set({error: true, hit_list: []});
            this.trigger('change');
            this.trigger('update-error');
        }).always(function() {
            this._in_flight = false;
            this.trigger('update-end');
            this._tick();
        });
    }

});

TG.IdentifyView = Backbone.View.extend({
    tagName: 'div',
    className: 'identify',
    templateName: 'identify',

    initialize: function() {
        this.model.on('change', this.render, this);
        this.model.on('update-start', function() {
            this.$el.addClass('update-in-progress');
        }, this);
        this.model.on('update-end', function() {
            this.$el.removeClass('update-in-progress');
        }, this);
    },

    render: function() {
        var template = TG.templates[this.templateName];
        this.$el.html(template(this.model.attributes));
    }

});

})();
<|endoftext|>


<commit_before>async function lastmatch(message, client, helper) {
    let locale = client.core.locale[message.gcfg.locale];

    try {
        await message.channel.sendTyping();
    } catch (err) {
        helper.handle(message, err);
    }

    let response = await client.core.util.eat(message, {
        "with": "member",
        "of": "member",
        "as": "string"
    });

    if ((!response.with && !response.of && !response.as) && !["lastmatch", "lm"].includes(message.content)) {
        let found_obj = await client.core.util.search_members(message.channel.guild.members, message.content.split(" ").slice(1));
        response.of = found_obj.all;
    }

    if (response.err) {
        message.channel.createMessage(locale.generic.generic).catch(err => helper.handle(message, err));
        helper.log(message, response.err);
        return;
    }

    let qids = [];

    if (response.with) {
        qids.push(message.author.id);
        qids.push(...response.with);
        qids.filter((el, i, arr) => arr.indexOf(el) === i);
    }

    if (response.of) {
        qids = [];
        qids.push(...response.of);
        if (response.with) qids.push(...response.with);
        qids.filter((el, i, arr) => arr.indexOf(el) === i);
    }

    if (!response.with && !response.of) qids.push(message.author.id);

    let hero_id = false;
    try {
        let found_hero = await client.core.util.find_hero(response.as);
        hero_id = client.core.json.od_heroes.find(hero => hero.name == `npc_dota_hero_${found_hero}`).id;
    } catch (err) {
        if (err === false) {
            helper.log(message, `couldn't find hero ${response.as}`);
            message.channel.createMessage(locale.generic.noheroerror).catch(err => helper.handle(message, err));
            return;
        }
    }

    Promise.all(qids.map(id => client.core.util.resolve_dota_id(locale.resolve_dota_id, message, id))).then(results => {
        results.forEach(result => {
            if (result.length < 1) {
                message.channel.createMessage(locale.generic.privateaccount).catch(err => helper.handle(message, err));
                return;
            }
        });

        let logmsg = `lastmatch: ${results.join(", ")}`;
        if (hero_id) logmsg += ` as ${hero_id}`;
        helper.log(message, logmsg);

        let mika_opt = {
            "limit": 1,
            "included_account_id": results.slice(1)
        };

        if (hero_id) mika_opt.hero_id = hero_id;

        client.mika.getPlayerMatches(results[0], mika_opt).then(match => {
            if (match) {
                let match_id = match[0].match_id;
                message.content = `matchinfo ${match_id}`;
                client.core.commands.matchinfo(message, client, helper);
            }
        }).catch(err => {
            helper.log(message, err);
            message.channel.createMessage(locale.generic.generic).catch(err => helper.handle(message, err));
        });
    }).catch(err => {
        if (err.err) {
            message.channel.createMessage(err.text || locale.generic.generic).catch(err => helper.handle(message, err));
            helper.log(message, err.text);
            helper.log(message, err.err);
        } else if (err.text) {
            message.channel.createMessage(err.text).catch(err => helper.handle(message, err));
            helper.log(message, err.log);
        } else {
            message.channel.createMessage(locale.generic.generic).catch(err => helper.handle(message, err));
            helper.log(message, err);
        }
    });
}

module.exports = lastmatch;
<commit_msg>delete my github account<commit_after>async function lastmatch(message, client, helper) {
    let locale = client.core.locale[message.gcfg.locale];

    try {
        await message.channel.sendTyping();
    } catch (err) {
        helper.handle(message, err);
    }

    let response = await client.core.util.eat(message, {
        "with": "member",
        "of": "member",
        "as": "string"
    });

    if ((!response.with && !response.of && !response.as) && !["lastmatch", "lastgame", "lm"].includes(message.content)) {
        let found_obj = await client.core.util.search_members(message.channel.guild.members, message.content.split(" ").slice(1));
        response.of = found_obj.all;
    }

    if (response.err) {
        message.channel.createMessage(locale.generic.generic).catch(err => helper.handle(message, err));
        helper.log(message, response.err);
        return;
    }

    let qids = [];

    if (response.with) {
        qids.push(message.author.id);
        qids.push(...response.with);
        qids.filter((el, i, arr) => arr.indexOf(el) === i);
    }

    if (response.of) {
        qids = [];
        qids.push(...response.of);
        if (response.with) qids.push(...response.with);
        qids.filter((el, i, arr) => arr.indexOf(el) === i);
    }

    if (!response.with && !response.of) qids.push(message.author.id);

    let hero_id = false;
    try {
        let found_hero = await client.core.util.find_hero(response.as);
        hero_id = client.core.json.od_heroes.find(hero => hero.name == `npc_dota_hero_${found_hero}`).id;
    } catch (err) {
        if (err === false) {
            helper.log(message, `couldn't find hero ${response.as}`);
            message.channel.createMessage(locale.generic.noheroerror).catch(err => helper.handle(message, err));
            return;
        }
    }

    Promise.all(qids.map(id => client.core.util.resolve_dota_id(locale.resolve_dota_id, message, id))).then(results => {
        results.forEach(result => {
            if (result.length < 1) {
                message.channel.createMessage(locale.generic.privateaccount).catch(err => helper.handle(message, err));
                return;
            }
        });

        let logmsg = `lastmatch: ${results.join(", ")}`;
        if (hero_id) logmsg += ` as ${hero_id}`;
        helper.log(message, logmsg);

        let mika_opt = {
            "limit": 1,
            "included_account_id": results.slice(1)
        };

        if (hero_id) mika_opt.hero_id = hero_id;

        client.mika.getPlayerMatches(results[0], mika_opt).then(match => {
            if (match) {
                let match_id = match[0].match_id;
                message.content = `matchinfo ${match_id}`;
                client.core.commands.matchinfo(message, client, helper);
            }
        }).catch(err => {
            helper.log(message, err);
            message.channel.createMessage(locale.generic.generic).catch(err => helper.handle(message, err));
        });
    }).catch(err => {
        if (err.err) {
            message.channel.createMessage(err.text || locale.generic.generic).catch(err => helper.handle(message, err));
            helper.log(message, err.text);
            helper.log(message, err.err);
        } else if (err.text) {
            message.channel.createMessage(err.text).catch(err => helper.handle(message, err));
            helper.log(message, err.log);
        } else {
            message.channel.createMessage(locale.generic.generic).catch(err => helper.handle(message, err));
            helper.log(message, err);
        }
    });
}

module.exports = lastmatch;
<|endoftext|>


<commit_before>const oauth2orize = require('oauth2orize');
const passport = require('passport');
const login = require('connect-ensure-login');
const uuid = require('node-uuid');
const db = require('./oauth');
const AuthorizationCode = require('mongoose').model('authorizationCode');
const AccessToken = require('mongoose').model('accessToken');
const RefreshToken = require('mongoose').model('refreshToken');
const User = require('mongoose').model('user');
const Client = require('mongoose').model('client');

module.exports = (() => {

// create OAuth 2.0 server
  const server = oauth2orize.createServer();

// Register supported grant types.
//
// OAuth 2.0 specifies a framework that allows users to grant client
// applications limited access to their protected resources.  It does this
// through a process of the user granting access, and the client exchanging
// the grant for an access token.

  /**
   * Grant authorization codes
   *
   * The callback takes the `client` requesting authorization, the `redirectURI`
   * (which is used as a verifier in the subsequent exchange), the authenticated
   * `user` granting access, and their response, which contains approved scope,
   * duration, etc. as parsed by the application.  The application issues a code,
   * which is bound to these values, and will be exchanged for an access token.
   */
  server.grant(oauth2orize.grant.code(function (client, redirectURI, user, ares, done) {
    const code = uuid.v4();
    const authorizationCode = new AuthorizationCode({
      authorization_code: code,
      redirect_uri: redirectURI,
      scope: client.scope,
      userID: user.id,
      clientID: client.id,
    });

    authorizationCode.save((err) => {
      if (err) {
        return done(err);
      }
      return done(null, code);

    });

  }));

  /**
   * Grant implicit authorization.
   *
   * The callback takes the `client` requesting authorization, the authenticated
   * `user` granting access, and their response, which contains approved scope,
   * duration, etc. as parsed by the application.  The application issues a token,
   * which is bound to these values.
   */
  server.grant(oauth2orize.grant.token(function (client, user, ares, done) {
    const token = uuid.v4();
    const accessToken = new AccessToken({
      token: token,
      userID:  user.id,
      expirationDate: calculateExpirationDate(),
      clientID: client.id,
      scope:  client.scope,
    });
    accessToken.save((err) => {
      if (err) {
        return done(err);
      }
      return done(null, token, {expires_in: 3600});
    });
  }));

  /**
   * Exchange authorization codes for access tokens.
   *
   * The callback accepts the `client`, which is exchanging `code` and any
   * `redirectURI` from the authorization request for verification.  If these values
   * are validated, the application issues an access token on behalf of the user who
   * authorized the code.
   */
  server.exchange(oauth2orize.exchange.code(function (client, code, redirectURI, done) {
    AuthorizationCode.findOne({authorization_code: code}).exec((err, authCode) => {
      if (err) {
        return done(err);
      }
      if (!authCode) {
        return done(null, false);
      }
      if (client.id !== authCode.clientID) {
        return done(null, false);
      }
      if (redirectURI !== authCode.redirectURI) {
        return done(null, false);
      }
      AuthorizationCode.remove({authorizationCode: code},function (err) {
        if (err) {
          return done(err);
        }
        const token = uuid.v4();
        const accessToken = new AccessToken({
          token: token,
          userID:  authCode.userID,
          expirationDate: calculateExpirationDate(),
          clientID: authCode.clientID,
          scope:  authCode.scope,
        });
        accessToken.save((err) => {
          if (err) {
            return done(err);
          }
          let refreshToken = null;
          //I mimic openid connect's offline scope to determine if we send
          //a refresh token or not
          if (authCode.scope && authCode.scope.indexOf("offline_access") === 0) {
            refreshToken = uuid.v4();
            const refreshTokenObject = new RefreshToken({
              token: refreshToken,
              userID: authCode.userID,
              clientID: authCode.clientID,
              scope: authCode.scope,
            });
            refreshTokenObject.save((err) => {
              if (err) {
                return done(err);
              }
              return done(null, token, refreshToken, {expires_in: 3600});
            });
          } else {
            return done(null, token, refreshToken, {expires_in: 3600});
          }
        });
      });
    });
  }));

  /**
   * Exchange user id and password for access tokens.
   *
   * The callback accepts the `client`, which is exchanging the user's name and password
   * from the token request for verification. If these values are validated, the
   * application issues an access token on behalf of the user who authorized the code.
   */
  server.exchange(oauth2orize.exchange.password(function (client, username, password, scope, done) {
    //Validate the user
    User.findOne({username: username}).exec((err, user) => {
      if (err) {
        return done(err);
      }
      if (!user) {
        return done(null, false);
      }
      if (password !== user.password) {
        return done(null, false);
      }
      var token = uuid.v4();
      const accessToken = new AccessToken({
        token: token,
        userID:  user.ID,
        expirationDate: calculateExpirationDate(),
        clientID: client.ID,
        scope:  scope,
      });

      accessToken.save((err) => {
        if (err) {
          return done(err);
        }
        var refreshToken = null;
        //I mimic openid connect's offline scope to determine if we send
        //a refresh token or not
        if (scope && scope.indexOf("offline_access") === 0) {
          refreshToken = uuid.v4();
          const refreshTokenObject = new RefreshToken({
            token: refreshToken,
            userID: user.ID,
            clientID: client.ID,
            scope: scope,
          });
          refreshTokenObject.save((err) => {
            if (err) {
              return done(err);
            }
            return done(null, token, refreshToken, {expires_in: 3600});
          });
        } else {
          return done(null, token, refreshToken, {expires_in: 3600});
        }
      });
    });
  }));

  /**
   * Exchange the client id and password/secret for an access token.
   *
   * The callback accepts the `client`, which is exchanging the client's id and
   * password/secret from the token request for verification. If these values are validated, the
   * application issues an access token on behalf of the client who authorized the code.
   */
  server.exchange(oauth2orize.exchange.clientCredentials(function (client, scope, done) {
    const token = uuid.v4();
    //Pass in a null for user id since there is no user when using this grant type
    const accessToken = new AccessToken({
      token: token,
      userID:  null,
      expirationDate: calculateExpirationDate(),
      clientID: client.ID,
      scope:  scope,
    });
    accessToken.save((err) => {
      if (err) {
        return done(err);
      }
      return done(null, token, null, {expires_in: 3600});
    });
  }));

  /**
   * Exchange the refresh token for an access token.
   *
   * The callback accepts the `client`, which is exchanging the client's id from the token
   * request for verification.  If this value is validated, the application issues an access
   * token on behalf of the client who authorized the code
   */
  server.exchange(oauth2orize.exchange.refreshToken(function (client, refreshToken, scope, done) {
    RefreshToken.findOne({token:refreshToken}).exec((err, authCode) => {
      if (err) {
        return done(err);
      }
      if (!authCode) {
        return done(null, false);
      }
      if (client.id !== authCode.clientID) {
        return done(null, false);
      }
      var token = uuid.v4();
      const accessToken = new AccessToken({
        token: token,
        userID:  authCode.userID,
        expirationDate: calculateExpirationDate(),
        clientID: authCode.clientID,
        scope:  authCode.scope,
      });
      accessToken.save(function (err){
        if (err) {
          return done(err);
        }
        return done(null, token, null, {expires_in: config.token.expiresIn});
      });
    });
  }));

  /**
   * User authorization endpoint
   *
   * `authorization` middleware accepts a `validate` callback which is
   * responsible for validating the client making the authorization request.  In
   * doing so, is recommended that the `redirectURI` be checked against a
   * registered value, although security requirements may vary accross
   * implementations.  Once validated, the `done` callback must be invoked with
   * a `client` instance, as well as the `redirectURI` to which the user will be
   * redirected after an authorization decision is obtained.
   *
   * This middleware simply initializes a new authorization transaction.  It is
   * the application's responsibility to authenticate the user and render a dialog
   * to obtain their approval (displaying details about the client requesting
   * authorization).  We accomplish that here by routing through `ensureLoggedIn()`
   * first, and rendering the `dialog` view.
   */

  authorization = [
    login.ensureLoggedIn(),
    server.authorization(function (clientID, redirectURI, scope, done) {
      Client.findOne({clientID: clientID}).exec((err, client) => {
        if (err) {
          return done(err);
        }
        if (client) {
          client.scope = scope;
        }
        // WARNING: For security purposes, it is highly advisable to check that
        //          redirectURI provided by the client matches one registered with
        //          the server.  For simplicity, this example does not.  You have
        //          been warned.
        return done(null, client, redirectURI);
      });
    }),
    function (req, res, next) {
      //Render the decision dialog if the client isn't a trusted client
      //TODO Make a mechanism so that if this isn't a trusted client, the user can recorded that they have consented
      //but also make a mechanism so that if the user revokes access to any of the clients then they will have to
      //re-consent.
      Client.findOne({clientID: req.query.client_id}).exec((err, client) => {
        if (!err && client && client.trustedClient && client.trustedClient === true) {
          //This is how we short call the decision like the dialog below does
          server.decision({loadTransaction: false}, function (req, callback) {
            callback(null, {allow: true});
          })(req, res, next);
        } else {
          res.render('dialog', {transactionID: req.oauth2.transactionID, user: req.user, client: req.oauth2.client});
        }
      });
    }
  ];

  /**
   * User decision endpoint
   *
   * `decision` middleware processes a user's decision to allow or deny access
   * requested by a client application.  Based on the grant type requested by the
   * client, the above grant middleware configured above will be invoked to send
   * a response.
   */
  decision = [
    login.ensureLoggedIn(),
    server.decision()
  ];

  /**
   * Token endpoint
   *
   * `token` middleware handles client requests to exchange authorization grants
   * for access tokens.  Based on the grant type being exchanged, the above
   * exchange middleware will be invoked to handle the request.  Clients must
   * authenticate when making requests to this endpoint.
   */
  token = [
    passport.authenticate(['basic', 'oauth2-client-password'], {session: false}),
    server.token(),
    server.errorHandler()
  ];

// Register serialialization and deserialization functions.
//
// When a client redirects a user to user authorization endpoint, an
// authorization transaction is initiated.  To complete the transaction, the
// user must authenticate and approve the authorization request.  Because this
// may involve multiple HTTPS request/response exchanges, the transaction is
// stored in the session.
//
// An application must supply serialization functions, which determine how the
// client object is serialized into the session.  Typically this will be a
// simple matter of serializing the client's ID, and deserializing by finding
// the client by ID from the database.

  server.serializeClient(function (client, done) {
    return done(null, client.id);
  });

  server.deserializeClient(function (id, done) {
    db.clients.find(id, function (err, client) {
      if (err) {
        return done(err);
      }
      return done(null, client);
    });
  });

  function calculateExpirationDate(){
    return new Date(new Date().getTime() + (3600 * 1000));
  }

  return {
    authorization,
    decision,
    token
  };
})();
<commit_msg>enabled strict mode in oauth.js<commit_after>const oauth2orize = require('oauth2orize');
const passport = require('passport');
const login = require('connect-ensure-login');
const uuid = require('node-uuid');
const db = require('./oauth');
const AuthorizationCode = require('mongoose').model('authorizationCode');
const AccessToken = require('mongoose').model('accessToken');
const RefreshToken = require('mongoose').model('refreshToken');
const User = require('mongoose').model('user');
const Client = require('mongoose').model('client');

module.exports = (() => {

  'use strict';

// create OAuth 2.0 server
  const server = oauth2orize.createServer();

// Register supported grant types.
//
// OAuth 2.0 specifies a framework that allows users to grant client
// applications limited access to their protected resources.  It does this
// through a process of the user granting access, and the client exchanging
// the grant for an access token.

  /**
   * Grant authorization codes
   *
   * The callback takes the `client` requesting authorization, the `redirectURI`
   * (which is used as a verifier in the subsequent exchange), the authenticated
   * `user` granting access, and their response, which contains approved scope,
   * duration, etc. as parsed by the application.  The application issues a code,
   * which is bound to these values, and will be exchanged for an access token.
   */
  server.grant(oauth2orize.grant.code(function (client, redirectURI, user, ares, done) {
    const code = uuid.v4();
    const authorizationCode = new AuthorizationCode({
      authorization_code: code,
      redirect_uri: redirectURI,
      scope: client.scope,
      userID: user.id,
      clientID: client.id,
    });

    authorizationCode.save((err) => {
      if (err) {
        return done(err);
      }
      return done(null, code);

    });

  }));

  /**
   * Grant implicit authorization.
   *
   * The callback takes the `client` requesting authorization, the authenticated
   * `user` granting access, and their response, which contains approved scope,
   * duration, etc. as parsed by the application.  The application issues a token,
   * which is bound to these values.
   */
  server.grant(oauth2orize.grant.token(function (client, user, ares, done) {
    const token = uuid.v4();
    const accessToken = new AccessToken({
      token: token,
      userID:  user.id,
      expirationDate: calculateExpirationDate(),
      clientID: client.id,
      scope:  client.scope,
    });
    accessToken.save((err) => {
      if (err) {
        return done(err);
      }
      return done(null, token, {expires_in: 3600});
    });
  }));

  /**
   * Exchange authorization codes for access tokens.
   *
   * The callback accepts the `client`, which is exchanging `code` and any
   * `redirectURI` from the authorization request for verification.  If these values
   * are validated, the application issues an access token on behalf of the user who
   * authorized the code.
   */
  server.exchange(oauth2orize.exchange.code(function (client, code, redirectURI, done) {
    AuthorizationCode.findOne({authorization_code: code}).exec((err, authCode) => {
      if (err) {
        return done(err);
      }
      if (!authCode) {
        return done(null, false);
      }
      if (client.id !== authCode.clientID) {
        return done(null, false);
      }
      if (redirectURI !== authCode.redirectURI) {
        return done(null, false);
      }
      AuthorizationCode.remove({authorizationCode: code},function (err) {
        if (err) {
          return done(err);
        }
        const token = uuid.v4();
        const accessToken = new AccessToken({
          token: token,
          userID:  authCode.userID,
          expirationDate: calculateExpirationDate(),
          clientID: authCode.clientID,
          scope:  authCode.scope,
        });
        accessToken.save((err) => {
          if (err) {
            return done(err);
          }
          let refreshToken = null;
          //I mimic openid connect's offline scope to determine if we send
          //a refresh token or not
          if (authCode.scope && authCode.scope.indexOf("offline_access") === 0) {
            refreshToken = uuid.v4();
            const refreshTokenObject = new RefreshToken({
              token: refreshToken,
              userID: authCode.userID,
              clientID: authCode.clientID,
              scope: authCode.scope,
            });
            refreshTokenObject.save((err) => {
              if (err) {
                return done(err);
              }
              return done(null, token, refreshToken, {expires_in: 3600});
            });
          } else {
            return done(null, token, refreshToken, {expires_in: 3600});
          }
        });
      });
    });
  }));

  /**
   * Exchange user id and password for access tokens.
   *
   * The callback accepts the `client`, which is exchanging the user's name and password
   * from the token request for verification. If these values are validated, the
   * application issues an access token on behalf of the user who authorized the code.
   */
  server.exchange(oauth2orize.exchange.password(function (client, username, password, scope, done) {
    //Validate the user
    User.findOne({username: username}).exec((err, user) => {
      if (err) {
        return done(err);
      }
      if (!user) {
        return done(null, false);
      }
      if (password !== user.password) {
        return done(null, false);
      }
      var token = uuid.v4();
      const accessToken = new AccessToken({
        token: token,
        userID:  user.ID,
        expirationDate: calculateExpirationDate(),
        clientID: client.ID,
        scope:  scope,
      });

      accessToken.save((err) => {
        if (err) {
          return done(err);
        }
        var refreshToken = null;
        //I mimic openid connect's offline scope to determine if we send
        //a refresh token or not
        if (scope && scope.indexOf("offline_access") === 0) {
          refreshToken = uuid.v4();
          const refreshTokenObject = new RefreshToken({
            token: refreshToken,
            userID: user.ID,
            clientID: client.ID,
            scope: scope,
          });
          refreshTokenObject.save((err) => {
            if (err) {
              return done(err);
            }
            return done(null, token, refreshToken, {expires_in: 3600});
          });
        } else {
          return done(null, token, refreshToken, {expires_in: 3600});
        }
      });
    });
  }));

  /**
   * Exchange the client id and password/secret for an access token.
   *
   * The callback accepts the `client`, which is exchanging the client's id and
   * password/secret from the token request for verification. If these values are validated, the
   * application issues an access token on behalf of the client who authorized the code.
   */
  server.exchange(oauth2orize.exchange.clientCredentials(function (client, scope, done) {
    const token = uuid.v4();
    //Pass in a null for user id since there is no user when using this grant type
    const accessToken = new AccessToken({
      token: token,
      userID:  null,
      expirationDate: calculateExpirationDate(),
      clientID: client.ID,
      scope:  scope,
    });
    accessToken.save((err) => {
      if (err) {
        return done(err);
      }
      return done(null, token, null, {expires_in: 3600});
    });
  }));

  /**
   * Exchange the refresh token for an access token.
   *
   * The callback accepts the `client`, which is exchanging the client's id from the token
   * request for verification.  If this value is validated, the application issues an access
   * token on behalf of the client who authorized the code
   */
  server.exchange(oauth2orize.exchange.refreshToken(function (client, refreshToken, scope, done) {
    RefreshToken.findOne({token:refreshToken}).exec((err, authCode) => {
      if (err) {
        return done(err);
      }
      if (!authCode) {
        return done(null, false);
      }
      if (client.id !== authCode.clientID) {
        return done(null, false);
      }
      var token = uuid.v4();
      const accessToken = new AccessToken({
        token: token,
        userID:  authCode.userID,
        expirationDate: calculateExpirationDate(),
        clientID: authCode.clientID,
        scope:  authCode.scope,
      });
      accessToken.save(function (err){
        if (err) {
          return done(err);
        }
        return done(null, token, null, {expires_in: config.token.expiresIn});
      });
    });
  }));

  /**
   * User authorization endpoint
   *
   * `authorization` middleware accepts a `validate` callback which is
   * responsible for validating the client making the authorization request.  In
   * doing so, is recommended that the `redirectURI` be checked against a
   * registered value, although security requirements may vary accross
   * implementations.  Once validated, the `done` callback must be invoked with
   * a `client` instance, as well as the `redirectURI` to which the user will be
   * redirected after an authorization decision is obtained.
   *
   * This middleware simply initializes a new authorization transaction.  It is
   * the application's responsibility to authenticate the user and render a dialog
   * to obtain their approval (displaying details about the client requesting
   * authorization).  We accomplish that here by routing through `ensureLoggedIn()`
   * first, and rendering the `dialog` view.
   */

  authorization = [
    login.ensureLoggedIn(),
    server.authorization(function (clientID, redirectURI, scope, done) {
      Client.findOne({clientID: clientID}).exec((err, client) => {
        if (err) {
          return done(err);
        }
        if (client) {
          client.scope = scope;
        }
        // WARNING: For security purposes, it is highly advisable to check that
        //          redirectURI provided by the client matches one registered with
        //          the server.  For simplicity, this example does not.  You have
        //          been warned.
        return done(null, client, redirectURI);
      });
    }),
    function (req, res, next) {
      //Render the decision dialog if the client isn't a trusted client
      //TODO Make a mechanism so that if this isn't a trusted client, the user can recorded that they have consented
      //but also make a mechanism so that if the user revokes access to any of the clients then they will have to
      //re-consent.
      Client.findOne({clientID: req.query.client_id}).exec((err, client) => {
        if (!err && client && client.trustedClient && client.trustedClient === true) {
          //This is how we short call the decision like the dialog below does
          server.decision({loadTransaction: false}, function (req, callback) {
            callback(null, {allow: true});
          })(req, res, next);
        } else {
          res.render('dialog', {transactionID: req.oauth2.transactionID, user: req.user, client: req.oauth2.client});
        }
      });
    }
  ];

  /**
   * User decision endpoint
   *
   * `decision` middleware processes a user's decision to allow or deny access
   * requested by a client application.  Based on the grant type requested by the
   * client, the above grant middleware configured above will be invoked to send
   * a response.
   */
  decision = [
    login.ensureLoggedIn(),
    server.decision()
  ];

  /**
   * Token endpoint
   *
   * `token` middleware handles client requests to exchange authorization grants
   * for access tokens.  Based on the grant type being exchanged, the above
   * exchange middleware will be invoked to handle the request.  Clients must
   * authenticate when making requests to this endpoint.
   */
  token = [
    passport.authenticate(['basic', 'oauth2-client-password'], {session: false}),
    server.token(),
    server.errorHandler()
  ];

// Register serialialization and deserialization functions.
//
// When a client redirects a user to user authorization endpoint, an
// authorization transaction is initiated.  To complete the transaction, the
// user must authenticate and approve the authorization request.  Because this
// may involve multiple HTTPS request/response exchanges, the transaction is
// stored in the session.
//
// An application must supply serialization functions, which determine how the
// client object is serialized into the session.  Typically this will be a
// simple matter of serializing the client's ID, and deserializing by finding
// the client by ID from the database.

  server.serializeClient(function (client, done) {
    return done(null, client.id);
  });

  server.deserializeClient(function (id, done) {
    db.clients.find(id, function (err, client) {
      if (err) {
        return done(err);
      }
      return done(null, client);
    });
  });

  function calculateExpirationDate(){
    return new Date(new Date().getTime() + (3600 * 1000));
  }

  return {
    authorization,
    decision,
    token
  };
})();
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import styles from 'interface/layout/Theme.scss';
import Danger from 'interface/common/Alert/Danger';
import MODULE_ERROR from 'parser/core/MODULE_ERROR';

class DegradedExperience extends React.Component {
  static propTypes = {
    disabledModules: PropTypes.object.isRequired,
  };

  constructor(...args){
    super(...args);
    this.state = {
      expanded: false,
    };
    this.toggleDetails = this.toggleDetails.bind(this);
  }

  toggleDetails() {
    this.setState({expanded: !this.state.expanded});
  }

  get firstError() {
    const { disabledModules } = this.props;
    const existingErrorTypes = Object.values(MODULE_ERROR).filter(state => disabledModules[state] && disabledModules[state].length !== 0);
    if(existingErrorTypes.length > 0){
      return disabledModules[existingErrorTypes[0]][0].name;
    }
    return "";
  }

  get disabledModuleCount(){
    const { disabledModules } = this.props;
    let amount = 0;
    if(disabledModules){
      amount = Object.values(MODULE_ERROR).reduce((total, cur) => {
        return total + (disabledModules[cur] ? disabledModules[cur].length : 0);
      }, 0);
    }
    return amount;
  }

  render() {
    const { disabledModules } = this.props;
    return this.disabledModuleCount > 0 && (

        <Danger style={{ marginBottom: 30 }}>

 Degraded Experience

          {this.firstError}
          {this.disabledModuleCount > 1 && <>and {this.disabledModuleCount - 1} other modules have encountered an error and have been disabled along with modules depending on them. </>}
          {this.disabledModuleCount === 1 && <>has encountered an error and has been disabled. </>}
          Results may be inaccurate and / or incomplete.

          Please report this issue to us on Discord or GitHub so we can fix it!

          {this.state.expanded && Object.values(MODULE_ERROR).filter(state => disabledModules[state] && disabledModules[state].length !== 0).map(state => {
            return (

The following modules have been disabled due to errors during {state}:

                  {disabledModules[state].sort((a,b) => a.name.localeCompare(b.name)).map((m, i) => <React.Fragment key={i}>{m.name}
</React.Fragment>)}

            );
          })}

          {this.state.expanded ? <>Show Less</> : <>Show More</>}
        </Danger>

    );
  }
}

export default DegradedExperience;
<commit_msg>wording<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import styles from 'interface/layout/Theme.scss';
import Danger from 'interface/common/Alert/Danger';
import MODULE_ERROR from 'parser/core/MODULE_ERROR';

class DegradedExperience extends React.Component {
  static propTypes = {
    disabledModules: PropTypes.object.isRequired,
  };

  constructor(...args){
    super(...args);
    this.state = {
      expanded: false,
    };
    this.toggleDetails = this.toggleDetails.bind(this);
  }

  toggleDetails() {
    this.setState({expanded: !this.state.expanded});
  }

  get firstError() {
    const { disabledModules } = this.props;
    const existingErrorTypes = Object.values(MODULE_ERROR).filter(state => disabledModules[state] && disabledModules[state].length !== 0);
    if(existingErrorTypes.length > 0){
      return disabledModules[existingErrorTypes[0]][0].name;
    }
    return "";
  }

  get disabledModuleCount(){
    const { disabledModules } = this.props;
    let amount = 0;
    if(disabledModules){
      amount = Object.values(MODULE_ERROR).reduce((total, cur) => {
        return total + (disabledModules[cur] ? disabledModules[cur].length : 0);
      }, 0);
    }
    return amount;
  }

  render() {
    const { disabledModules } = this.props;
    return this.disabledModuleCount > 0 && (

        <Danger style={{ marginBottom: 30 }}>

 Degraded Experience

          {this.firstError}
          {this.disabledModuleCount > 1 && <>and {this.disabledModuleCount - 1} other modules have encountered an error directly or inside a dependency and have been disabled. </>}
          {this.disabledModuleCount === 1 && <>has encountered an error and has been disabled. </>}
          Results may be inaccurate and / or incomplete.

          Please report this issue to us on Discord or GitHub so we can fix it!

          {this.state.expanded && Object.values(MODULE_ERROR).filter(state => disabledModules[state] && disabledModules[state].length !== 0).map(state => {
            return (

The following modules have been disabled due to errors during {state}:

                  {disabledModules[state].sort((a,b) => a.name.localeCompare(b.name)).map((m, i) => <React.Fragment key={i}>{m.name}
</React.Fragment>)}

            );
          })}

          {this.state.expanded ? <>Show Less</> : <>Show More</>}
        </Danger>

    );
  }
}

export default DegradedExperience;
<|endoftext|>


<commit_before>/* eslint-env jest */
/* global jasmine */

import {
    loadFixtures,
    deleteFixtures
} from '../utils/fixture-utils'
import {
  deleteUser,
  getNewAuthedUser
} from '../utils/auth-utils'
import fetchQuery from '../utils/fetch-graphql'

jasmine.DEFAULT_TIMEOUT_INTERVAL = 180e3

var cognitoUsername = null
var cognitoUserId = null
var cognitoUserIdToken = null
const fixtureUserId = 'gqltest1-12ab-12ab-12ab-123abc456def'

beforeAll(async () => {
  // Create a Cognito user.
  const userInfo = await getNewAuthedUser()
  cognitoUserId = userInfo.userId
  cognitoUserIdToken = userInfo.idToken
  cognitoUsername = userInfo.username
})

afterAll(async () => {
  // Delete the Cognito user.
  await deleteUser(cognitoUsername)
})

beforeEach(async () => {
  // Load fixtures, replacing one of the hardcoded user IDs
  // with the Cognito user's ID.
  await loadFixtures('users', [
    { before: fixtureUserId, after: cognitoUserId }
  ])
})

afterEach(async () => {
  await deleteFixtures('users', [
    { before: fixtureUserId, after: cognitoUserId }
  ])
})

describe('User table queries', () => {
  it('allows read access for the user', async () => {
    const query = `
      query UserViewQuery(
        $userId: String!) {
          user(userId: $userId) {
            userId
            username
            vcCurrent
            vcAllTime
            email
          }
      }
    `
    const response = await fetchQuery(query, {
      userId: cognitoUserId
    }, cognitoUserIdToken)
    expect(response.data.user.userId).toBe(cognitoUserId)
    expect(response.data.user.username).toBe('kevin')
    expect(response.data.user.email).toBe('foo@bar.com')
  }, 60e3)

  it('does not allow read access without a token', async () => {
    const query = `
      query UserViewQuery(
        $userId: String!) {
          user(userId: $userId) {
            userId
            username
            vcCurrent
            vcAllTime
            email
          }
      }
    `
    const response = await fetchQuery(query, {
      userId: cognitoUserId
    })
    expect(response.data).toBeUndefined()
    expect(response.message).toBe('Unauthorized')
  }, 60e3)

  // TODO: reenable when implemented.
  // it('does not allow a user to fetch another user', async () => {
  //   const query = `
  //     query UserViewQuery(
  //       $userId: String!) {
  //         user(userId: $userId) {
  //           userId
  //           username
  //           vcCurrent
  //           vcAllTime
  //           email
  //         }
  //     }
  //   `
  //   const response = await fetchQuery(query, {
  //     userId: 'gqltest1-yz89-yz80-yz80-xyz789tuv456' // another user
  //   }, cognitoUserIdToken)
  //   console.log('Wrong user fetch:')
  //   console.log(JSON.stringify(response, null, 2))
  //   expect(response.data).toBeUndefined()
  //   expect(response.message).toBe('Unauthorized')
  // }, 60e3)

  // // TODO
  // it('allows new user creation', async () => {
  //   const query = `
  //   `
  //   const response = await fetchQuery(query, {
  //     userId: cognitoUserId
  //   }, cognitoUserIdToken)
  //   //
  // }, 60e3)

  // // TODO
  // it('does not allow new user creation with a different sub than Cognito', async () => {
  //   const query = `
  //   `
  //   const response = await fetchQuery(query, {
  //     userId: cognitoUserId
  //   })
  //   //
  // }, 60e3)
})
<commit_msg>Reenable authorization test.<commit_after>/* eslint-env jest */
/* global jasmine */

import {
    loadFixtures,
    deleteFixtures
} from '../utils/fixture-utils'
import {
  deleteUser,
  getNewAuthedUser
} from '../utils/auth-utils'
import fetchQuery from '../utils/fetch-graphql'

jasmine.DEFAULT_TIMEOUT_INTERVAL = 180e3

var cognitoUsername = null
var cognitoUserId = null
var cognitoUserIdToken = null
const fixtureUserId = 'gqltest1-12ab-12ab-12ab-123abc456def'

beforeAll(async () => {
  // Create a Cognito user.
  const userInfo = await getNewAuthedUser()
  cognitoUserId = userInfo.userId
  cognitoUserIdToken = userInfo.idToken
  cognitoUsername = userInfo.username
})

afterAll(async () => {
  // Delete the Cognito user.
  await deleteUser(cognitoUsername)
})

beforeEach(async () => {
  // Load fixtures, replacing one of the hardcoded user IDs
  // with the Cognito user's ID.
  await loadFixtures('users', [
    { before: fixtureUserId, after: cognitoUserId }
  ])
})

afterEach(async () => {
  await deleteFixtures('users', [
    { before: fixtureUserId, after: cognitoUserId }
  ])
})

describe('User table queries', () => {
  it('allows read access for the user', async () => {
    const query = `
      query UserViewQuery(
        $userId: String!) {
          user(userId: $userId) {
            userId
            username
            vcCurrent
            vcAllTime
            email
          }
      }
    `
    const response = await fetchQuery(query, {
      userId: cognitoUserId
    }, cognitoUserIdToken)
    expect(response.data.user.userId).toBe(cognitoUserId)
    expect(response.data.user.username).toBe('kevin')
    expect(response.data.user.email).toBe('foo@bar.com')
  }, 60e3)

  it('does not allow read access without a token', async () => {
    const query = `
      query UserViewQuery(
        $userId: String!) {
          user(userId: $userId) {
            userId
            username
            vcCurrent
            vcAllTime
            email
          }
      }
    `
    const response = await fetchQuery(query, {
      userId: cognitoUserId
    })
    expect(response.data).toBeUndefined()
    expect(response.message).toBe('Unauthorized')
  }, 60e3)

  it('does not allow a user to fetch another user', async () => {
    const query = `
      query UserViewQuery(
        $userId: String!) {
          user(userId: $userId) {
            userId
            username
            vcCurrent
            vcAllTime
            email
          }
      }
    `
    const response = await fetchQuery(query, {
      userId: 'gqltest1-yz89-yz80-yz80-xyz789tuv456' // another user
    }, cognitoUserIdToken)
    console.log('Wrong user fetch:')
    console.log(JSON.stringify(response, null, 2))
    expect(response.data).toBeUndefined()
    expect(response.message).toBe('Query not authorized.')
  }, 60e3)

  // // TODO
  // it('allows new user creation', async () => {
  //   const query = `
  //   `
  //   const response = await fetchQuery(query, {
  //     userId: cognitoUserId
  //   }, cognitoUserIdToken)
  //   //
  // }, 60e3)

  // // TODO
  // it('does not allow new user creation with a different sub than Cognito', async () => {
  //   const query = `
  //   `
  //   const response = await fetchQuery(query, {
  //     userId: cognitoUserId
  //   })
  //   //
  // }, 60e3)
})
<|endoftext|>


<commit_before>const electron = require('./__mocks__/electron');
const childProcess = require('child_process');

let activityDetection;

describe('Tests for Activity Detection', function() {

    var originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
    jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;

    beforeAll(function (done) {
        childProcess.exec(`npm rebuild --target=${process.version} --build-from-source`, function (err) {
            activityDetection = require('../js/activityDetection/activityDetection.js');
            activityDetection.setActivityWindow(900000, electron.ipcRenderer);
            done();
        });
    });

    beforeEach(function () {
        jest.clearAllMocks()
    });

    afterAll(function (done) {
        childProcess.exec('npm run rebuild', function (err, stdout) {
            jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
            done();
        });
    });

    it('should return null', function() {

        activityDetection.setActivityWindow(0, electron.ipcRenderer);
        const noData = activityDetection.activityDetection();
        expect(noData).toBeNull();

    });

    it('should send activity event', function () {
        const spy = jest.spyOn(activityDetection, 'send');

        expect(spy).not.toBeCalled();

        activityDetection.send({systemIdleTime: 120000});
        expect(spy).toHaveBeenCalledWith({systemIdleTime: 120000});

    });

    it('should monitor user activity', function () {
        activityDetection.setActivityWindow(500000, electron.ipcRenderer);
        const spy = jest.spyOn(activityDetection, 'monitorUserActivity');

        expect(spy).not.toBeCalled();

        activityDetection.monitorUserActivity();
        expect(spy).toHaveBeenCalled();

    });

    it('should not send activity event as data is undefined', function () {
        const spy = jest.spyOn(activityDetection, 'send');

        expect(spy).not.toBeCalled();

        activityDetection.send(undefined);
        expect(spy).toHaveBeenCalledWith(undefined);

    });

});
<commit_msg>Electron-90 - throws error if rebuild fails<commit_after>const electron = require('./__mocks__/electron');
const childProcess = require('child_process');

let activityDetection;

describe('Tests for Activity Detection', function() {

    var originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
    jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;

    beforeAll(function (done) {
        childProcess.exec(`npm rebuild --target=${process.version} --build-from-source`, function (err) {
            activityDetection = require('../js/activityDetection/activityDetection.js');
            activityDetection.setActivityWindow(900000, electron.ipcRenderer);
            done();
        });
    });

    beforeEach(function () {
        jest.clearAllMocks()
    });

    afterAll(function (done) {
        childProcess.exec('npm run rebuild', function (err, stdout) {
            if (err){
                throw(err);
            }
            jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
            done();
        });
    });

    it('should return null', function() {

        activityDetection.setActivityWindow(0, electron.ipcRenderer);
        const noData = activityDetection.activityDetection();
        expect(noData).toBeNull();

    });

    it('should send activity event', function () {
        const spy = jest.spyOn(activityDetection, 'send');

        expect(spy).not.toBeCalled();

        activityDetection.send({systemIdleTime: 120000});
        expect(spy).toHaveBeenCalledWith({systemIdleTime: 120000});

    });

    it('should monitor user activity', function () {
        activityDetection.setActivityWindow(500000, electron.ipcRenderer);
        const spy = jest.spyOn(activityDetection, 'monitorUserActivity');

        expect(spy).not.toBeCalled();

        activityDetection.monitorUserActivity();
        expect(spy).toHaveBeenCalled();

    });

    it('should not send activity event as data is undefined', function () {
        const spy = jest.spyOn(activityDetection, 'send');

        expect(spy).not.toBeCalled();

        activityDetection.send(undefined);
        expect(spy).toHaveBeenCalledWith(undefined);

    });

});
<|endoftext|>


<commit_before>
myApp.rq.push(['script',0,(document.location.protocol == 'file:') ? myApp.vars.testURL+'jsonapi/config.js' : myApp.vars.baseURL+'jsonapi/config.js',function(){
//in some cases, such as the zoovy UI, zglobals may not be defined. If that's the case, certain vars, such as jqurl, must be passed in via P in initialize:
//	myApp.u.dump(" ->>>>>>>>>>>>>>>>>>>>>>>>>>>>> zGlobals is an object");
	myApp.vars.username = zGlobals.appSettings.username.toLowerCase(); //used w/ image URL's.
//need to make sure the secureURL ends in a / always. doesn't seem to always come in that way via zGlobals
	myApp.vars.secureURL = zGlobals.appSettings.https_app_url;
	myApp.vars.domain = zGlobals.appSettings.sdomain; //passed in ajax requests.
	myApp.vars.jqurl = (document.location.protocol === 'file:') ? myApp.vars.testURL+'jsonapi/' : '/jsonapi/';
	}]); //The config.js is dynamically generated.

myApp.rq.push(['extension',0,'order_create','extensions/checkout/extension.js']);
myApp.rq.push(['extension',0,'cco','extensions/cart_checkout_order.js']);

myApp.rq.push(['extension',0,'store_routing','extensions/store_routing.js']);

myApp.rq.push(['extension',0,'store_prodlist','extensions/store_prodlist.js']);
myApp.rq.push(['extension',0,'store_navcats','extensions/store_navcats.js']);
myApp.rq.push(['extension',0,'store_search','extensions/store_search.js']);
myApp.rq.push(['extension',0,'store_product','extensions/store_product.js']);
myApp.rq.push(['extension',0,'cart_message','extensions/cart_message/extension.js']);
myApp.rq.push(['extension',0,'store_crm','extensions/store_crm.js']);
myApp.rq.push(['extension',0,'quickstart','app-quickstart.js','startMyProgram']);

//myApp.rq.push(['extension',0,'entomologist','extensions/entomologist/extension.js']);
//myApp.rq.push(['extension',0,'tools_animation','extensions/tools_animation.js']);

//myApp.rq.push(['extension',1,'google_analytics','extensions/partner_google_analytics.js','startExtension']);
//myApp.rq.push(['extension',1,'tools_ab_testing','extensions/tools_ab_testing.js']);
//myApp.rq.push(['extension',0,'partner_addthis','extensions/partner_addthis.js']);
//myApp.rq.push(['extension',1,'resellerratings_survey','extensions/partner_buysafe_guarantee.js','startExtension']); /// !!! needs testing.
//myApp.rq.push(['extension',1,'buysafe_guarantee','extensions/partner_buysafe_guarantee.js','startExtension']);
//myApp.rq.push(['extension',1,'powerReviews_reviews','extensions/partner_powerreviews_reviews.js','startExtension']);
//myApp.rq.push(['extension',0,'magicToolBox_mzp','extensions/partner_magictoolbox_mzp.js','startExtension']); // (not working yet - ticket in to MTB)

myApp.rq.push(['script',0,myApp.vars.baseURL+'resources/jquery.showloading-v1.0.jt.js']); //used pretty early in process..
myApp.rq.push(['script',0,myApp.vars.baseURL+'resources/jquery.ui.anyplugins.js']); //in zero pass in case product page is first page.
myApp.rq.push(['script',0,myApp.vars.baseURL+'resources/tlc.js']); //in zero pass in case product page is first page.
myApp.rq.push(['css',1,myApp.vars.baseURL+'resources/anyplugins.css']);

myApp.rq.push(['script',0,myApp.vars.baseURL+'resources/jsonpath.0.8.0.js']); //used pretty early in process..

//once peg is loaded, need to retrieve the grammar file. Order is important there. This will validate the file too.
myApp.u.loadScript(myApp.vars.baseURL+'resources/peg-0.8.0.js',function(){
	myApp.model.getGrammar(myApp.vars.baseURL+"resources/pegjs-grammar-20140203.pegjs");
	}); // ### TODO -> callback on RQ.push wasn't getting executed. investigate.

//Cart Messaging Responses.

myApp.cmr.push(['chat.join',function(message){
//	dump(" -> message: "); dump(message);
	var $ui = myApp.ext.quickstart.a.showBuyerCMUI();
	$("[data-app-role='messageInput']",$ui).show();
	$("[data-app-role='messageHistory']",$ui).append("
"+message.FROM+" has joined the chat.<\/p>");
	$('.show4ActiveChat',$ui).show();
	$('.hide4ActiveChat',$ui).hide();
	}]);

myApp.cmr.push(['goto',function(message,$context){
	var $history = $("[data-app-role='messageHistory']",$context);
	$P = $("
")
		.addClass('chat_post')
		.append(""+message.FROM+"<\/span> has sent over a "+(message.vars.pageType || "")+" link for you within this store. Click here<\/span> to view.")
		.on('click',function(){
			showContent(myApp.ext.quickstart.u.whatAmIFor(message.vars),message.vars);
			});
	$history.append($P);
	$history.parent().scrollTop($history.height());
	}]);

//gets executed from app-admin.html as part of controller init process.
//progress is an object that will get updated as the resources load.
/*
'passZeroResourcesLength' : [INT],
'passZeroResourcesLoaded' : [INT],
'passZeroTimeout' : null //the timeout instance running within loadResources that updates this object. it will run indef unless clearTimeout run here OR all resources are loaded.

*/
myApp.u.showProgress = function(progress)	{
	function showProgress(attempt)	{
		if(progress.passZeroResourcesLength == progress.passZeroResourcesLoaded)	{
			//All pass zero resources have loaded.
			//the app will handle hiding the loading screen.
			myApp.u.appInitComplete();
			}
		else if(attempt > 150)	{
			//hhhhmmm.... something must have gone wrong.
			clearTimeout(progress.passZeroTimeout); //end the resource loading timeout.
			}
		else	{
			var percentPerInclude = (100 / progress.passZeroResourcesLength);
			var percentComplete = Math.round(progress.passZeroResourcesLength * percentPerInclude); //used to sum how many includes have successfully loaded.
//			dump(" -> percentPerInclude: "+percentPerInclude+" and percentComplete: "+percentComplete);
			$('#appPreViewProgressBar').val(percentComplete);
			$('#appPreViewProgressText').empty().append(percentComplete+"% Complete");
			attempt++;
			setTimeout(function(){showProgress(attempt);},250);
			}
		}
	showProgress(0)
	}

//Any code that needs to be executed after the app init has occured can go here.
//will pass in the page info object. (pageType, templateID, pid/navcat/show and more)
myApp.u.appInitComplete = function()	{
	myApp.u.dump("Executing myAppIsLoaded code...");

	myApp.ext.order_create.checkoutCompletes.push(function(vars,$checkout){
//append this to
		$("[data-app-role='thirdPartyContainer']",$checkout).append("
What next?

");
		$('.ocmTwitterComment',$checkout).click(function(){
			window.open('http://twitter.com/home?status='+cartContentsAsLinks,'twitter');
			_gaq.push(['_trackEvent','Checkout','User Event','Tweeted about order']);
			});
		//the fb code only works if an appID is set, so don't show banner if not present.
		if(myApp.u.thisNestedExists("zGlobals.thirdParty.facebook.appId") && typeof FB == 'object')	{
			$('.ocmFacebookComment',$checkout).click(function(){
				myApp.ext.quickstart.thirdParty.fb.postToWall(cartContentsAsLinks);
				_gaq.push(['_trackEvent','Checkout','User Event','FB message about order']);
				});
			}
		else	{$('.ocmFacebookComment').hide()}
		});
	}

//this will trigger the content to load on app init. so if you push refresh, you don't get a blank page.
//it'll also handle the old 'meta' uri params.
//this will trigger the content to load on app init. so if you push refresh, you don't get a blank page.
//it'll also handle the old 'meta' uri params.
myApp.router.appendInit({
	'type':'function',
	'route': function(v){
		return {'init':true} //returning anything but false triggers a match.
		},
	'callback':function(f,g){
		dump(" -> triggered callback for appendInit");
		g = g || {};
		if(document.location.hash)	{
			myApp.router.handleHashChange();
			}
		else	{
			//IE8 didn't like the shortcut to showContent here.
			myApp.ext.quickstart.a.showContent('homepage');
			}
		if(g.uriParams && g.uriParams.meta)	{
			myApp.ext.cco.calls.cartSet.init({'want/refer':infoObj.uriParams.meta,'cartID':_app.model.fetchCartID()},{},'passive');
			}
		if(g.uriParams && g.uriParams.meta_src)	{
			myApp.ext.cco.calls.cartSet.init({'want/refer_src':infoObj.uriParams.meta_src,'cartID':_app.model.fetchCartID()},{},'passive');
			}
		}
	});

<commit_msg>app-quickstart-init - SEO request handling<commit_after>
myApp.rq.push(['script',0,(document.location.protocol == 'file:') ? myApp.vars.testURL+'jsonapi/config.js' : myApp.vars.baseURL+'jsonapi/config.js',function(){
//in some cases, such as the zoovy UI, zglobals may not be defined. If that's the case, certain vars, such as jqurl, must be passed in via P in initialize:
//	myApp.u.dump(" ->>>>>>>>>>>>>>>>>>>>>>>>>>>>> zGlobals is an object");
	myApp.vars.username = zGlobals.appSettings.username.toLowerCase(); //used w/ image URL's.
//need to make sure the secureURL ends in a / always. doesn't seem to always come in that way via zGlobals
	myApp.vars.secureURL = zGlobals.appSettings.https_app_url;
	myApp.vars.domain = zGlobals.appSettings.sdomain; //passed in ajax requests.
	myApp.vars.jqurl = (document.location.protocol === 'file:') ? myApp.vars.testURL+'jsonapi/' : '/jsonapi/';
	}]); //The config.js is dynamically generated.

myApp.rq.push(['extension',0,'order_create','extensions/checkout/extension.js']);
myApp.rq.push(['extension',0,'cco','extensions/cart_checkout_order.js']);

myApp.rq.push(['extension',0,'store_routing','extensions/store_routing.js']);

myApp.rq.push(['extension',0,'store_prodlist','extensions/store_prodlist.js']);
myApp.rq.push(['extension',0,'store_navcats','extensions/store_navcats.js']);
myApp.rq.push(['extension',0,'store_search','extensions/store_search.js']);
myApp.rq.push(['extension',0,'store_product','extensions/store_product.js']);
myApp.rq.push(['extension',0,'cart_message','extensions/cart_message/extension.js']);
myApp.rq.push(['extension',0,'store_crm','extensions/store_crm.js']);
myApp.rq.push(['extension',0,'quickstart','app-quickstart.js','startMyProgram']);

//myApp.rq.push(['extension',0,'entomologist','extensions/entomologist/extension.js']);
//myApp.rq.push(['extension',0,'tools_animation','extensions/tools_animation.js']);

//myApp.rq.push(['extension',1,'google_analytics','extensions/partner_google_analytics.js','startExtension']);
//myApp.rq.push(['extension',1,'tools_ab_testing','extensions/tools_ab_testing.js']);
//myApp.rq.push(['extension',0,'partner_addthis','extensions/partner_addthis.js']);
//myApp.rq.push(['extension',1,'resellerratings_survey','extensions/partner_buysafe_guarantee.js','startExtension']); /// !!! needs testing.
//myApp.rq.push(['extension',1,'buysafe_guarantee','extensions/partner_buysafe_guarantee.js','startExtension']);
//myApp.rq.push(['extension',1,'powerReviews_reviews','extensions/partner_powerreviews_reviews.js','startExtension']);
//myApp.rq.push(['extension',0,'magicToolBox_mzp','extensions/partner_magictoolbox_mzp.js','startExtension']); // (not working yet - ticket in to MTB)

myApp.rq.push(['script',0,myApp.vars.baseURL+'resources/jquery.showloading-v1.0.jt.js']); //used pretty early in process..
myApp.rq.push(['script',0,myApp.vars.baseURL+'resources/jquery.ui.anyplugins.js']); //in zero pass in case product page is first page.
myApp.rq.push(['script',0,myApp.vars.baseURL+'resources/tlc.js']); //in zero pass in case product page is first page.
myApp.rq.push(['css',1,myApp.vars.baseURL+'resources/anyplugins.css']);

myApp.rq.push(['script',0,myApp.vars.baseURL+'resources/jsonpath.0.8.0.js']); //used pretty early in process..

//once peg is loaded, need to retrieve the grammar file. Order is important there. This will validate the file too.
myApp.u.loadScript(myApp.vars.baseURL+'resources/peg-0.8.0.js',function(){
	myApp.model.getGrammar(myApp.vars.baseURL+"resources/pegjs-grammar-20140203.pegjs");
	}); // ### TODO -> callback on RQ.push wasn't getting executed. investigate.

//Cart Messaging Responses.

myApp.cmr.push(['chat.join',function(message){
//	dump(" -> message: "); dump(message);
	var $ui = myApp.ext.quickstart.a.showBuyerCMUI();
	$("[data-app-role='messageInput']",$ui).show();
	$("[data-app-role='messageHistory']",$ui).append("
"+message.FROM+" has joined the chat.<\/p>");
	$('.show4ActiveChat',$ui).show();
	$('.hide4ActiveChat',$ui).hide();
	}]);

myApp.cmr.push(['goto',function(message,$context){
	var $history = $("[data-app-role='messageHistory']",$context);
	$P = $("
")
		.addClass('chat_post')
		.append(""+message.FROM+"<\/span> has sent over a "+(message.vars.pageType || "")+" link for you within this store. Click here<\/span> to view.")
		.on('click',function(){
			showContent(myApp.ext.quickstart.u.whatAmIFor(message.vars),message.vars);
			});
	$history.append($P);
	$history.parent().scrollTop($history.height());
	}]);

//gets executed from app-admin.html as part of controller init process.
//progress is an object that will get updated as the resources load.
/*
'passZeroResourcesLength' : [INT],
'passZeroResourcesLoaded' : [INT],
'passZeroTimeout' : null //the timeout instance running within loadResources that updates this object. it will run indef unless clearTimeout run here OR all resources are loaded.

*/
myApp.u.showProgress = function(progress)	{
	function showProgress(attempt)	{
		if(progress.passZeroResourcesLength == progress.passZeroResourcesLoaded)	{
			//All pass zero resources have loaded.
			//the app will handle hiding the loading screen.
			myApp.u.appInitComplete();
			}
		else if(attempt > 150)	{
			//hhhhmmm.... something must have gone wrong.
			clearTimeout(progress.passZeroTimeout); //end the resource loading timeout.
			}
		else	{
			var percentPerInclude = (100 / progress.passZeroResourcesLength);
			var percentComplete = Math.round(progress.passZeroResourcesLength * percentPerInclude); //used to sum how many includes have successfully loaded.
//			dump(" -> percentPerInclude: "+percentPerInclude+" and percentComplete: "+percentComplete);
			$('#appPreViewProgressBar').val(percentComplete);
			$('#appPreViewProgressText').empty().append(percentComplete+"% Complete");
			attempt++;
			setTimeout(function(){showProgress(attempt);},250);
			}
		}
	showProgress(0)
	}

//Any code that needs to be executed after the app init has occured can go here.
//will pass in the page info object. (pageType, templateID, pid/navcat/show and more)
myApp.u.appInitComplete = function()	{
	myApp.u.dump("Executing myAppIsLoaded code...");

	myApp.ext.order_create.checkoutCompletes.push(function(vars,$checkout){
//append this to
		$("[data-app-role='thirdPartyContainer']",$checkout).append("
What next?

");
		$('.ocmTwitterComment',$checkout).click(function(){
			window.open('http://twitter.com/home?status='+cartContentsAsLinks,'twitter');
			_gaq.push(['_trackEvent','Checkout','User Event','Tweeted about order']);
			});
		//the fb code only works if an appID is set, so don't show banner if not present.
		if(myApp.u.thisNestedExists("zGlobals.thirdParty.facebook.appId") && typeof FB == 'object')	{
			$('.ocmFacebookComment',$checkout).click(function(){
				myApp.ext.quickstart.thirdParty.fb.postToWall(cartContentsAsLinks);
				_gaq.push(['_trackEvent','Checkout','User Event','FB message about order']);
				});
			}
		else	{$('.ocmFacebookComment').hide()}
		});
	}

//this will trigger the content to load on app init. so if you push refresh, you don't get a blank page.
//it'll also handle the old 'meta' uri params.
//this will trigger the content to load on app init. so if you push refresh, you don't get a blank page.
//it'll also handle the old 'meta' uri params.
myApp.router.appendInit({
	'type':'function',
	'route': function(v){
		return {'init':true} //returning anything but false triggers a match.
		},
	'callback':function(f,g){
		dump(" -> triggered callback for appendInit");
		g = g || {};
		if(g.uriParams.seoRequest){
			showContent(g.uriParams.pageType, g.uriParams);
			}
		else if(document.location.hash)	{
			myApp.u.dump('triggering handleHash');
			myApp.router.handleHashChange();
			}
		else	{
			//IE8 didn't like the shortcut to showContent here.
			myApp.ext.quickstart.a.showContent('homepage');
			}
		if(g.uriParams && g.uriParams.meta)	{
			myApp.ext.cco.calls.cartSet.init({'want/refer':infoObj.uriParams.meta,'cartID':_app.model.fetchCartID()},{},'passive');
			}
		if(g.uriParams && g.uriParams.meta_src)	{
			myApp.ext.cco.calls.cartSet.init({'want/refer_src':infoObj.uriParams.meta_src,'cartID':_app.model.fetchCartID()},{},'passive');
			}
		}
	});

<|endoftext|>


<commit_before>Template.home.onCreated(function() {
  let intervalA = Meteor.setInterval(function() {
    $('.right-perspective-overlay').visibility('refresh');
  }, 20);
  let intervalB = Meteor.setInterval(function() {
    $('.left-perspective-overlay').visibility('refresh');
  }, 20);
  Session.set('intervalTracker', [intervalA, intervalB]);
});

Template.home.onRendered(() => {
  $('.right-perspective-overlay').transition('slide right in');
  $('.left-perspective-overlay').transition('slide left in');
});

Template.home.onDestroyed(() => {
  let intervals = Session.get('intervalTracker');
  intervals.forEach((id) => {
    Meteor.clearInterval(id);
  });
});

Template.home.events({
  'click .google-log-in': function() {
    Meteor.loginWithGoogle();
  },
  'click .create-scheme': function() {
    Router.go('insertScheme');
  },
  'click .view-schemes': function() {
    Router.go('dashboard');
  }
});
<commit_msg>Remove unused trackers.<commit_after>Template.home.onRendered(() => {
  $('.right-perspective-overlay').transition('slide right in');
  $('.left-perspective-overlay').transition('slide left in');
});

Template.home.events({
  'click .google-log-in'() {
    Meteor.loginWithGoogle();
  },
  'click .create-scheme'() {
    Router.go('insertScheme');
  },
  'click .view-schemes'() {
    Router.go('dashboard');
  },
});
<|endoftext|>


<commit_before>/*!
 * Created by mschwartz on 4/29/15.
 */
/**
 * Unit test framework
 */

/**
 * @private
 * @type {number}
 */
var testNumber = 0;

/**
 * @private
 * @type {Array}
 */
var suites = [];

/**
 * Declare a test suite
 *
 * @param {String} description/name of suite
 * @param {Function} fn body of suite tests to be run
 */
function suite(description, fn) {
    suites.push({
        description : description,
        fn          : fn
    });
}

function runSuite(suite) {
    testNumber = 1;
    console.log('--------------------');
    console.log('Unit Test: ' + suite.description);
    if (suite.fn() !== false) {
        console.log('    SUCCEEDED');
    }
}

/**
 * Declare an individual test within a suite
 *
 * @param {String} description
 * @param {Function} fn body of the test to be run
 * @returns {Boolean} true if test succeeded
 */
function test(description, fn) {
    console.log('- Test #' + testNumber + ': ' + description);
    testNumber++;
    return fn();
}

/**
 * Main program for unit tests.  Call it with a path to a directory containing unit test .js files.
 *
 * @param path
 */
function test_main(path) {
    var File = require('File'),
        dir  = new File(path);

    decaf.each(dir.list(/\.js$/), function (filename) {
        var fn = new Function(new File((path + '/' + filename).replace(/\/\//g, '/')).readAll());
        fn();
    });

    if (global.arguments.length > 1) {
        for (var i = 1; i < global.arguments.length; i++) {
            var name = global.arguments[i];
            decaf.each(suites, function (suite) {
                if (suite.description === name) {
                    runSuite(suite);
                }
            })
        }
    }
    else {
        decaf.each(suites, function (suite) {
            runSuite(suite);
        });
    }
}

decaf.extend(exports, {
    test_main : test_main,
    suite     : suite,
    test      : test,
    assert    : global.assert
});
<commit_msg>fix so suite.test on command line runs the specified test only<commit_after>/*!
 * Created by mschwartz on 4/29/15.
 */
/**
 * Unit test framework
 */

/**
 * @private
 * @type {number}
 */
var testNumber = 0;

/**
 * @private
 * @type {Array}
 */
var suites = [];

var selectedTest = undefined;

/**
 * Declare a test suite
 *
 * @param {String} description/name of suite
 * @param {Function} fn body of suite tests to be run
 */
function suite(description, fn) {
    suites.push({
        description : description,
        fn          : fn
    });
}

function runSuite(suite, test) {
    selectedTest = test;
    testNumber = 1;
    console.log('--------------------');
    console.log('Unit Test: ' + suite.description);
    if (suite.fn() !== false) {
        console.log('    SUCCEEDED');
    }
}

/**
 * Declare an individual test within a suite
 *
 * @param {String} description
 * @param {Function} fn body of the test to be run
 * @returns {Boolean} true if test succeeded
 */
function test(description, fn) {
    if (selectedTest && description !== selectedTest) {
        return true;
    }
    console.log('- Test #' + testNumber + ': ' + description);
    testNumber++;
    return fn();
}

/**
 * Main program for unit tests.  Call it with a path to a directory containing unit test .js files.
 *
 * @param path
 */
function test_main(path) {
    var File = require('File'),
        dir  = new File(path);

    decaf.each(dir.list(/\.js$/), function (filename) {
        var fn = new Function(new File((path + '/' + filename).replace(/\/\//g, '/')).readAll());
        fn();
    });

    if (global.arguments.length > 1) {
        for (var i = 1; i < global.arguments.length; i++) {
            var name = global.arguments[i],
                testToRun = undefined;
            if (~name.indexOf('.')) {
                name = name.split('.');
                testToRun = name[1];
                name = name[0];
            }
            decaf.each(suites, function (suite) {
                if (suite.description === name) {
                    runSuite(suite, testToRun);
                }
            })
        }
    }
    else {
        decaf.each(suites, function (suite) {
            runSuite(suite);
        });
    }
}

decaf.extend(exports, {
    test_main : test_main,
    suite     : suite,
    test      : test,
    assert    : global.assert
});
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var lowdb = require('lowdb');
var storage = require('lowdb/file-async');
var dao = {};
var REFRESH_RATE = 1000 * 60 * 10;
var dbPath = path.resolve(__dirname, 'db.json');
var db = getDb();

if (!isDbValid(db)) {
    createDb();
}

function getDb() {
    return lowdb(dbPath, {
        storage: storage,
    });
}

function isDbValid(db) {
    return db.object.hasOwnProperty('users') && db.object.hasOwnProperty('updates');
}

function createDb() {
    var content = JSON.stringify({
        updates: [],
        users: {}
    });

    try {
        fs.writeFileSync(dbPath, content, {
            flags: 'w'
        });
        db = getDb();
    } catch(e) {
        console.error(e);
    }
}

setInterval(function() {
    db = getDb();
}, REFRESH_RATE);

dao.getUsers = function() {
    return db('users').cloneDeep();
};

dao.saveUsers = function(users) {
    db('updates').push(Date.now());

    if (!db.object.users) {
        db.object.users = {};
    }

    users.forEach(function(user) {
        if (!db.object.users[user.userId]) {
            db.object.users[user.userId] = [];
        }
        db.object.users[user.userId].push(user.timestamp);
    });
    db.write();
};

module.exports = dao;
<commit_msg>Don't log if timestamp is 0<commit_after>var fs = require('fs');
var path = require('path');
var lowdb = require('lowdb');
var storage = require('lowdb/file-async');
var dao = {};
var REFRESH_RATE = 1000 * 60 * 10;
var dbPath = path.resolve(__dirname, 'db.json');
var db = getDb();

if (!isDbValid(db)) {
    createDb();
}

function getDb() {
    return lowdb(dbPath, {
        storage: storage,
    });
}

function isDbValid(db) {
    return db.object.hasOwnProperty('users') && db.object.hasOwnProperty('updates');
}

function createDb() {
    var content = JSON.stringify({
        updates: [],
        users: {}
    });

    try {
        fs.writeFileSync(dbPath, content, {
            flags: 'w'
        });
        db = getDb();
    } catch(e) {
        console.error(e);
    }
}

setInterval(function() {
    db = getDb();
}, REFRESH_RATE);

dao.getUsers = function() {
    return db('users').cloneDeep();
};

dao.saveUsers = function(users) {
    db('updates').push(Date.now());

    if (!db.object.users) {
        db.object.users = {};
    }

    users.forEach(function(user) {
        if (!db.object.users[user.userId]) {
            db.object.users[user.userId] = [];
        }

        if(user.timestamp) {
            db.object.users[user.userId].push(user.timestamp);
        }
    });
    db.write();
};

module.exports = dao;
<|endoftext|>


<commit_before>/*
 * Copyright 2018 Crown Copyright
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import React from 'react';

import { connect } from 'react-redux';
import { compose } from 'recompose';
import { Header, Dropdown, Grid } from 'semantic-ui-react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'

import { actionCreators } from './redux';

const { themeChanged } = actionCreators;

const themeOptions = [
  {
    text: 'Light',
    value: 'theme-light',
  },
  {
    text: 'Dark',
    value: 'theme-dark',
  },
];
const enhance = compose(connect(
  (state, props) => ({
    theme: state.userSettings.theme,
  }),
  { themeChanged },
));

const UserSettings = ({ theme, themeChanged }) => (
  <React.Fragment>
    <Grid className="content-tabs__grid">
      <Grid.Column width={12}>

          <FontAwesomeIcon icon="user" />
          Me

      </Grid.Column>
    </Grid>

User Settings

      <Grid>
        <Grid.Column width={6}>Theme:</Grid.Column>
        <Grid.Column width={10}>
          <Dropdown
            fluid
            selection
            options={themeOptions}
            value={theme}
            onChange={(_, data) => {
              themeChanged(data.value);
            }}
          />
        </Grid.Column>
      </Grid>

  </React.Fragment>
);

export default enhance(UserSettings);
<commit_msg>Swap out header<commit_after>/*
 * Copyright 2018 Crown Copyright
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import React from 'react';

import { connect } from 'react-redux';
import { compose } from 'recompose';
import { Header, Dropdown, Grid } from 'semantic-ui-react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import IconHeader from 'components/IconHeader';

import { actionCreators } from './redux';

const { themeChanged } = actionCreators;

const themeOptions = [
  {
    text: 'Light',
    value: 'theme-light',
  },
  {
    text: 'Dark',
    value: 'theme-dark',
  },
];
const enhance = compose(connect(
  (state, props) => ({
    theme: state.userSettings.theme,
  }),
  { themeChanged },
));

const UserSettings = ({ theme, themeChanged }) => (
  <React.Fragment>
    <Grid className="content-tabs__grid">
      <Grid.Column width={12}>
        <IconHeader text="Me" icon="user" />
      </Grid.Column>
    </Grid>

User Settings

      <Grid>
        <Grid.Column width={6}>Theme:</Grid.Column>
        <Grid.Column width={10}>
          <Dropdown
            fluid
            selection
            options={themeOptions}
            value={theme}
            onChange={(_, data) => {
              themeChanged(data.value);
            }}
          />
        </Grid.Column>
      </Grid>

  </React.Fragment>
);

export default enhance(UserSettings);
<|endoftext|>


<commit_before>"use strict";

const readline = require('readline');
const fs = require('fs');

/**
 * Reads the given file and returns read values. Each value is an array of decimal numbers.
 * @param filePath Path to the file that will be read.
 * @returns {Promise}
 */
function readValuesFromFile(filePath, rowToArray) {
    return new Promise(function (resolve, reject) {
        let values = [];

        const rl = readline.createInterface({
            input: fs.createReadStream(filePath)
        });

        rl.on('line', function (line) {
            const numberValues = [];

            const stringValues = line.split(/,?\s+/);
            let numberValue;
            for (let i = 0; i < stringValues.length; i++) {
                numberValue = parseFloat(stringValues[i]);
                if (!isNaN(numberValue)) {
                    numberValues.push(numberValue);
                }
            }

            if (rowToArray && numberValues.length > 1) {
                values.push(numberValues);
            } else if (!rowToArray) {
                for (let i = 0; i < numberValues.length; i++) {
                    values.push(numberValues[i]);
                }
            } else {
                reject(Error('Each line has to contain at least 2 values'));
                rl.close();
            }
        });

        rl.on('close', function () {
            resolve(values);
        });
    });
}

/**
 * Writes given text to a file on given path.
 * @returns {Promise}
 */
function writeToFile(filePath, text) {
    return new Promise(function (resolve, reject) {
        fs.writeFile(filePath, text, (err) => {
            if (err) {
                reject(err);
            } else {
                resolve();
            }
        });
    });
}

/**
 * Writes given text to a file on given path.
 * @returns {Promise}
 */
function readFromFile(filePath) {
    return new Promise(function (resolve, reject) {
        fs.readFile(filePath, 'utf8', (err, data) => {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        });
    });
}

module.exports = {
    readFromFile,
    readValuesFromFile,
    writeToFile,
};
<commit_msg>Fix file parsing (accept both decimal comma and decimal dot)<commit_after>"use strict";

const readline = require('readline');
const fs = require('fs');

/**
 * Reads the given file and returns read values. Each value is an array of decimal numbers.
 * @param filePath Path to the file that will be read.
 * @returns {Promise}
 */
function readValuesFromFile(filePath, rowToArray) {
    return new Promise(function (resolve, reject) {
        let values = [];

        const rl = readline.createInterface({
            input: fs.createReadStream(filePath)
        });

        rl.on('line', function (line) {
            const numberValues = [];

            const stringValues = line.replace(',', '.').split(/\s+/);
            let numberValue;
            for (let i = 0; i < stringValues.length; i++) {
                numberValue = parseFloat(stringValues[i]);
                if (!isNaN(numberValue)) {
                    numberValues.push(numberValue);
                }
            }

            if (rowToArray && numberValues.length > 1) {
                values.push(numberValues);
            } else if (!rowToArray) {
                for (let i = 0; i < numberValues.length; i++) {
                    values.push(numberValues[i]);
                }
            } else {
                reject(Error('Each line has to contain at least 2 values'));
                rl.close();
            }
        });

        rl.on('close', function () {
            resolve(values);
        });
    });
}

/**
 * Writes given text to a file on given path.
 * @returns {Promise}
 */
function writeToFile(filePath, text) {
    return new Promise(function (resolve, reject) {
        fs.writeFile(filePath, text, (err) => {
            if (err) {
                reject(err);
            } else {
                resolve();
            }
        });
    });
}

/**
 * Writes given text to a file on given path.
 * @returns {Promise}
 */
function readFromFile(filePath) {
    return new Promise(function (resolve, reject) {
        fs.readFile(filePath, 'utf8', (err, data) => {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        });
    });
}

module.exports = {
    readFromFile,
    readValuesFromFile,
    writeToFile,
};
<|endoftext|>