<commit_before>let city;
let filter;
let placeSuggestions = new Map();

const PLACE_CARDS_CONTAINER = document.getElementById('place-cards-container');
const DEFAULT_PLACE_IMAGE = '../assets/img/jason-dent-blue.jpg'

function init() {
  document.getElementById('plan-for-me-link').classList.add('active');
  document.getElementById('plan-for-me-link-m').classList.add('active');
  authReload();
  addCityAutocomplete();
  addFilterHandler();
}

function addCityAutocomplete() {
  const cityInputField = document.getElementById('city-input')
  const options = {
    types: ['(cities)'],
  }
  const autocomplete = new google.maps.places.Autocomplete(cityInputField, options);
  google.maps.event.addListener(autocomplete, 'place_changed', () => {
    city = autocomplete.getPlace();
    if(filter) {
      findPlacesInCity(city, filter);
    }
  });
}

function addFilterHandler() {
  const filterForm = document.getElementById('filters');
  filterForm.addEventListener('change', () => {
    filter = filterForm.value;
    if(city) {
      findPlacesInCity(city, filter);
    }
  });
}

/**
 * Fetches locations according to filter within 10000m radius of selected city
 * @param {Object} city PlaceResult object with city information returned from autocomplete that user selected
 * @param {String} filter types of locations to look for e.g. amusement park
 */
async function findPlacesInCity(city, filter) {
  if (!city.hasOwnProperty('place_id')) {
    M.Toast.dismissAll();
    M.toast({
      html: "Your city wasn't selected with autocomplete",
    });
    return;
  }

  PLACE_CARDS_CONTAINER.innerHTML = LOADING_ANIMATION_HTML;
  const { geometry } = city;
  const { location } = geometry;
  const { lat, lng } = location;
  const placesResponse = await fetch(
    `https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api/place/textsearch/json?type=${filter}&location=${lat()},${lng()}&radius=10000&key=${GOOGLE_API_KEY}&output=json`
  )
  const { results } = await placesResponse.json();
  getPlaceCardInformation(results);
}

/**
 * Gets details and photos for every place returned from Places API
 * @param {Array} places array of PlaceResult objects returned from Places API
 */
async function getPlaceCardInformation(places) {
  for(let i = 0; i < places.length; i++) {
    const { place_id } = places[i];
    const placeDetails = await getPlaceDetails(place_id);
    placeSuggestions.set(place_id, placeDetails);
  }

  renderPlaceCards(placeSuggestions);
}

/**
 * Renders information cards to DOM for each place suggestion
 * @param {Array} places array of objects containing information and photo URLs about each place
 */
function renderPlaceCards(places) {
  let placeCards = [];
  for(let i = 0; i < places.length; i++) {
    const { phoneNumber, name, photoUrl, priceLevel, rating, address, website } = places[i];

    placeCards.push(
      `

              ${name}

                add

            ` +
              (address
                ? `<p>${address}</p>`
                : '') +
              (phoneNumber
                ? `<p>${phoneNumber}</p>`
                : '') +
              (rating
                ? `<p>Rating: ${rating}</p>`
                : '') +
              (priceLevel
                ? `<p>Price Level: ${priceLevel}</p>`
                : '') +
            `

            ` +
              (website
                ? `

                    Website

`
                : '') +
            `

      `
    )
  }

  PLACE_CARDS_CONTAINER.innerHTML = placeCards.join('');
}

/**
 * Fetches more details about place such as phone number and website and puts it all into an object
 * @param {String} placeId place ID of place to get details about
 */
async function getPlaceDetails(placeId) {
  const detailsResponse = await fetch(
    `https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api/place/details/json?place_id=${placeId}&key=${GOOGLE_API_KEY}`
  )
  const { result } = await detailsResponse.json();
  const { international_phone_number, name, photos, price_level, rating, vicinity, website } = result;
  const photoUrl = await imageURLFromPhotos(photos);

  const placeDetails = {
    phoneNumber: international_phone_number,
    name: name,
    photoUrl: photoUrl,
    priceLevel: price_level,
    rating: rating,
    address: vicinity,
    website: website
  }

  return placeDetails;
}

/**
 * Gets URL for photo of place or assigns it a default one if there are no photos available
 * @param {Array} photos array of photos from PlaceResult object
 */
async function imageURLFromPhotos(photos) {
  const photoRef =
    photos && Array.isArray(photos)
      ? photos[0].photo_reference
      : undefined;

  if(photoRef) {
    const photoResponse = await fetch(
      `https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api/place/photo?maxheight=300&photoreference=${photoRef}&key=${GOOGLE_API_KEY}`
    );
    const blob = await photoResponse.blob();
    const photoUrl = await URL.createObjectURL(blob);
    return photoUrl;
  } else {
    return DEFAULT_PLACE_IMAGE;
  }
}<commit_msg>Change for loop to for-of loop to properly traverse map<commit_after>let city;
let filter;
let placesMap = new Map();

const PLACE_CARDS_CONTAINER = document.getElementById('place-cards-container');
const DEFAULT_PLACE_IMAGE = '../assets/img/jason-dent-blue.jpg'

function init() {
  document.getElementById('plan-for-me-link').classList.add('active');
  document.getElementById('plan-for-me-link-m').classList.add('active');
  authReload();
  addCityAutocomplete();
  addFilterHandler();
}

function addCityAutocomplete() {
  const cityInputField = document.getElementById('city-input')
  const options = {
    types: ['(cities)'],
  }
  const autocomplete = new google.maps.places.Autocomplete(cityInputField, options);
  google.maps.event.addListener(autocomplete, 'place_changed', () => {
    city = autocomplete.getPlace();
    if(filter) {
      findPlacesInCity(city, filter);
    }
  });
}

function addFilterHandler() {
  const filterForm = document.getElementById('filters');
  filterForm.addEventListener('change', () => {
    filter = filterForm.value;
    if(city) {
      findPlacesInCity(city, filter);
    }
  });
}

/**
 * Fetches locations according to filter within 10000m radius of selected city
 * @param {Object} city PlaceResult object with city information returned from autocomplete that user selected
 * @param {String} filter types of locations to look for e.g. amusement park
 */
async function findPlacesInCity(city, filter) {
  if (!city.hasOwnProperty('place_id')) {
    M.Toast.dismissAll();
    M.toast({
      html: "Your city wasn't selected with autocomplete",
    });
    return;
  }

  PLACE_CARDS_CONTAINER.innerHTML = LOADING_ANIMATION_HTML;
  const { geometry } = city;
  const { location } = geometry;
  const { lat, lng } = location;
  const placesResponse = await fetch(
    `https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api/place/textsearch/json?type=${filter}&location=${lat()},${lng()}&radius=10000&key=${GOOGLE_API_KEY}&output=json`
  )
  const { results } = await placesResponse.json();
  getPlaceCardInformation(results);
}

/**
 * Gets details and photos for every place returned from Places API
 * @param {Array} places array of PlaceResult objects returned from Places API
 */
async function getPlaceCardInformation(places) {
  for(let i = 0; i < places.length; i++) {
    const { place_id } = places[i];
    const placeDetails = await getPlaceDetails(place_id);
    placesMap.set(place_id, placeDetails);
  }

  renderPlaceCards(placesMap);
}

/**
 * Renders information cards to DOM for each place suggestion
 * @param {Array} places array of objects containing information and photo URLs about each place
 */
function renderPlaceCards(placesMap) {
  let placeCards = [];
  for(let [placeId, placeDetails] of placesMap.entries()) {
    const { phoneNumber, name, photoUrl, priceLevel, rating, address, website } = placeDetails;

    placeCards.push(
      `

              ${name}

                add

            ` +
              (address
                ? `<p>${address}</p>`
                : '') +
              (phoneNumber
                ? `<p>${phoneNumber}</p>`
                : '') +
              (rating
                ? `<p>Rating: ${rating}</p>`
                : '') +
              (priceLevel
                ? `<p>Price Level: ${priceLevel}</p>`
                : '') +
            `

            ` +
              (website
                ? `

                    Website

`
                : '') +
            `

      `
    )
  }

  PLACE_CARDS_CONTAINER.innerHTML = placeCards.join('');
}

/**
 * Fetches more details about place such as phone number and website and puts it all into an object
 * @param {String} placeId place ID of place to get details about
 */
async function getPlaceDetails(placeId) {
  const detailsResponse = await fetch(
    `https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api/place/details/json?place_id=${placeId}&key=${GOOGLE_API_KEY}`
  )
  const { result } = await detailsResponse.json();
  const { international_phone_number, name, photos, price_level, rating, vicinity, website } = result;
  const photoUrl = await imageURLFromPhotos(photos);

  const placeDetails = {
    phoneNumber: international_phone_number,
    name: name,
    photoUrl: photoUrl,
    priceLevel: price_level,
    rating: rating,
    address: vicinity,
    website: website
  }

  return placeDetails;
}

/**
 * Gets URL for photo of place or assigns it a default one if there are no photos available
 * @param {Array} photos array of photos from PlaceResult object
 */
async function imageURLFromPhotos(photos) {
  const photoRef =
    photos && Array.isArray(photos)
      ? photos[0].photo_reference
      : undefined;

  if(photoRef) {
    const photoResponse = await fetch(
      `https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api/place/photo?maxheight=300&photoreference=${photoRef}&key=${GOOGLE_API_KEY}`
    );
    const blob = await photoResponse.blob();
    const photoUrl = await URL.createObjectURL(blob);
    return photoUrl;
  } else {
    return DEFAULT_PLACE_IMAGE;
  }
}<|endoftext|>


<commit_before>import React from 'react'
import {IntlStub} from 'tocco-test-util'
import SearchForm from './'
import {mount} from 'enzyme'
import {Button} from 'tocco-ui'
// TODO
// import FormField from '../../../../components/FormField'

const EMPTY_FUNC = () => {}

describe('entity-browser', () => {
  describe('components', () => {
    describe('SearchForm', () => {
      it('should render needed components', () => {
        const entityModel = require('../../dev/test-data/userModel.json')
        const searchFormDefinition = require('../../dev/test-data/searchFormDefinition.json')

        const wrapper = mount(<SearchForm
          entityModel={entityModel}
          searchFormDefinition={searchFormDefinition}
          setSearchInput={EMPTY_FUNC}
          relationEntities={{}}
          searchInputs={{}}
          reset={EMPTY_FUNC}
          intl={IntlStub}
          simpleSearchFields={[]}
          disableSimpleSearch
          preselectedSearchFields={[]}
        />)

        // expect(wrapper.find(FormField)).to.have.length(searchFormDefinition.length)
        expect(wrapper.find(Button)).to.have.length(2)
      })

      it('should render only the fulltext field', () => {
        const entityModel = require('../../dev/test-data/userModel.json')
        const searchFormDefinition = require('../../dev/test-data/searchFormDefinition.json')

        const wrapper = mount(<SearchForm
          entityModel={entityModel}
          searchFormDefinition={searchFormDefinition}
          setSearchInput={EMPTY_FUNC}
          relationEntities={{}}
          searchInputs={{}}
          reset={EMPTY_FUNC}
          intl={IntlStub}
          disableSimpleSearch={false}
          simpleSearchFields={['txtFulltext']}
          preselectedSearchFields={[]}
        />)

        // expect(wrapper.find(FormField)).to.have.length(1)
        expect(wrapper.find(Button)).to.have.length(3)
      })

      it('should render two fields', () => {
        const entityModel = require('../../dev/test-data/userModel.json')
        const searchFormDefinition = require('../../dev/test-data/searchFormDefinition.json')

        const wrapper = mount(<SearchForm
          entityModel={entityModel}
          searchFormDefinition={searchFormDefinition}
          setSearchInput={EMPTY_FUNC}
          relationEntities={{}}
          searchInputs={{}}
          reset={EMPTY_FUNC}
          intl={IntlStub}
          disableSimpleSearch={false}
          simpleSearchFields={['txtFulltext', 'relUser_code1']}
          preselectedSearchFields={[]}
        />)

        // expect(wrapper.find(FormField)).to.have.length(2)
        expect(wrapper.find(Button)).to.have.length(3)
      })

      it('should not show hidden value', () => {
        // const entityModel = require('../../dev/test-data/userModel.json')
        // const searchFormDefinition = require('../../dev/test-data/searchFormDefinition.json')
        //
        // const preselectedSearchFields = [
        //   {
        //     id: 'relUser_code1',
        //     value: 'VALUE',
        //     hidden: true
        //   }
        // ]

        // const wrapper = mount(<SearchForm
        //   entityModel={entityModel}
        //   searchFormDefinition={searchFormDefinition}
        //   setSearchInput={EMPTY_FUNC}
        //   relationEntities={{}}
        //   searchInputs={{}}
        //   reset={EMPTY_FUNC}
        //   intl={IntlStub}
        //   disableSimpleSearch
        //   simpleSearchFields={[]}
        //   preselectedSearchFields={preselectedSearchFields}
        // />)

        // expect(wrapper.find(FormField)).to.have.length(searchFormDefinition.length - 1)
      })
    })
  })
})
<commit_msg>test(entity-list): re-enable searchForm tests<commit_after>import React from 'react'
import {IntlStub} from 'tocco-test-util'
import SearchForm from './'
import {mount} from 'enzyme'
import {Button, FormField} from 'tocco-ui'

const EMPTY_FUNC = () => {}

describe('entity-browser', () => {
  describe('components', () => {
    describe('SearchForm', () => {
      it('should render needed components', () => {
        const entityModel = require('../../dev/test-data/userModel.json')
        const searchFormDefinition = require('../../dev/test-data/searchFormDefinition.json')

        const wrapper = mount(<SearchForm
          initialize={EMPTY_FUNC}
          entityModel={entityModel}
          searchFormDefinition={searchFormDefinition}
          setSearchInput={EMPTY_FUNC}
          relationEntities={{}}
          searchInputs={{}}
          reset={EMPTY_FUNC}
          intl={IntlStub}
          simpleSearchFields={[]}
          disableSimpleSearch
          preselectedSearchFields={[]}
        />)

        expect(wrapper.find(FormField)).to.have.length(searchFormDefinition.length)
        expect(wrapper.find(Button)).to.have.length(2)
      })

      it('should render only the fulltext field', () => {
        const entityModel = require('../../dev/test-data/userModel.json')
        const searchFormDefinition = require('../../dev/test-data/searchFormDefinition.json')

        const wrapper = mount(<SearchForm
          initialize={EMPTY_FUNC}
          entityModel={entityModel}
          searchFormDefinition={searchFormDefinition}
          setSearchInput={EMPTY_FUNC}
          relationEntities={{}}
          searchInputs={{}}
          reset={EMPTY_FUNC}
          intl={IntlStub}
          disableSimpleSearch={false}
          simpleSearchFields={['txtFulltext']}
          preselectedSearchFields={[]}
        />)

        expect(wrapper.find(FormField)).to.have.length(1)
        expect(wrapper.find(Button)).to.have.length(3)
      })

      it('should render two fields', () => {
        const entityModel = require('../../dev/test-data/userModel.json')
        const searchFormDefinition = require('../../dev/test-data/searchFormDefinition.json')

        const wrapper = mount(<SearchForm
          initialize={EMPTY_FUNC}
          entityModel={entityModel}
          searchFormDefinition={searchFormDefinition}
          setSearchInput={EMPTY_FUNC}
          relationEntities={{}}
          searchInputs={{}}
          reset={EMPTY_FUNC}
          intl={IntlStub}
          disableSimpleSearch={false}
          simpleSearchFields={['txtFulltext', 'relUser_code1']}
          preselectedSearchFields={[]}
        />)

        expect(wrapper.find(FormField)).to.have.length(2)
        expect(wrapper.find(Button)).to.have.length(3)
      })

      it('should not show hidden value', () => {
        const entityModel = require('../../dev/test-data/userModel.json')
        const searchFormDefinition = require('../../dev/test-data/searchFormDefinition.json')

        const preselectedSearchFields = [
          {
            id: 'relUser_code1',
            value: 'VALUE',
            hidden: true
          }
        ]

        const wrapper = mount(<SearchForm
          initialize={EMPTY_FUNC}
          entityModel={entityModel}
          searchFormDefinition={searchFormDefinition}
          setSearchInput={EMPTY_FUNC}
          relationEntities={{}}
          searchInputs={{}}
          reset={EMPTY_FUNC}
          intl={IntlStub}
          disableSimpleSearch
          simpleSearchFields={[]}
          preselectedSearchFields={preselectedSearchFields}
        />)

        expect(wrapper.find(FormField)).to.have.length(searchFormDefinition.length - 1)
      })
    })
  })
})
<|endoftext|>


<commit_before>var _          = require('underscore'),
    isString   = require('is/string'),
    isFunction = require('is/function'),
    parseNum   = require('util/parseInt'),
    split      = require('util/split'),
    SUPPORTS   = require('SUPPORTS'),
    TEXT       = require('NODE_TYPE/TEXT'),
    COMMENT    = require('NODE_TYPE/COMMENT'),
    ATTRIBUTE  = require('NODE_TYPE/ATTRIBUTE'),
    REGEX      = require('REGEX');

var propFix = split('tabIndex|readOnly|className|maxLength|cellSpacing|cellPadding|rowSpan|colSpan|useMap|frameBorder|contentEditable')
    .reduce(function(obj, str) {
        obj[str.toLowerCase()] = str;
        return obj;
    }, {
        'for': 'htmlFor',
        'class': 'className'
    });

var propHooks = {
    src: SUPPORTS.hrefNormalized ? {} : {
        get: function(elem) {
            return elem.getAttribute('src', 4);
        }
    },

    href: SUPPORTS.hrefNormalized ? {} : {
        get: function(elem) {
            return elem.getAttribute('href', 4);
        }
    },

    // Support: Safari, IE9+
    // mis-reports the default selected property of an option
    // Accessing the parent's selectedIndex property fixes it
    selected: SUPPORTS.optSelected ? {} : {
        get: function(elem) {
            var parent = elem.parentNode,
                fix;

            if (parent) {
                fix = parent.selectedIndex;

                // Make sure that it also works with optgroups, see #5701
                if (parent.parentNode) {
                    fix = parent.parentNode.selectedIndex;
                }
            }
            return null;
        }
    },

    tabIndex: {
        get: function(elem) {
            // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
            // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
            // Use proper attribute retrieval(#12072)
            var tabindex = elem.getAttribute('tabindex');

            if (tabindex) { return parseNum(tabindex); }

            var nodeName = elem.nodeName;
            return (REGEX.isFocusable(nodeName) || (REGEX.isClickable(nodeName) && elem.href)) ? 0 : -1;
        }
    }
};

var getOrSetProp = function(elem, name, value) {
    var nodeType = elem.nodeType;

    // don't get/set properties on text, comment and attribute nodes
    if (!elem || nodeType === TEXT || nodeType === COMMENT || nodeType === ATTRIBUTE) {
        return;
    }

    // Fix name and attach hooks
    name = propFix[name] || name;
    var hooks = propHooks[name];

    var result;
    if (value !== undefined) {
        return hooks && ('set' in hooks) && (result = hooks.set(elem, value, name)) !== undefined ?
            result :
            (elem[name] = value);
    }

    return hooks && ('get' in hooks) && (result = hooks.get(elem, name)) !== null ?
        result :
        elem[name];
};

module.exports = {
    fn: {
        prop: function(prop, value) {
            if (arguments.length === 1 && isString(prop)) {
                var first = this[0];
                if (!first) { return; }

                return getOrSetProp(first, prop);
            }

            if (isString(prop)) {
                if (isFunction(value)) {
                    var fn = value;
                    return _.each(this, function(elem, idx) {
                        var result = fn.call(elem, idx, getOrSetProp(elem, prop));
                        getOrSetProp(elem, prop, result);
                    });
                }

                return _.each(this, (elem) => getOrSetProp(elem, prop, value));
            }

            // fallback
            return this;
        },

        removeProp: function(prop) {
            if (!isString(prop)) { return this; }

            var name = propFix[prop] || prop;
            return _.each(this, function(elem) {
                delete elem[name];
            });
        }
    }
};
<commit_msg>cleanup<commit_after>var _          = require('underscore'),
    isString   = require('is/string'),
    isFunction = require('is/function'),
    parseNum   = require('util/parseInt'),
    split      = require('util/split'),
    SUPPORTS   = require('SUPPORTS'),
    TEXT       = require('NODE_TYPE/TEXT'),
    COMMENT    = require('NODE_TYPE/COMMENT'),
    ATTRIBUTE  = require('NODE_TYPE/ATTRIBUTE'),
    REGEX      = require('REGEX');

var propFix = split('tabIndex|readOnly|className|maxLength|cellSpacing|cellPadding|rowSpan|colSpan|useMap|frameBorder|contentEditable')
    .reduce(function(obj, str) {
        obj[str.toLowerCase()] = str;
        return obj;
    }, {
        'for':   'htmlFor',
        'class': 'className'
    });

var propHooks = {
    src: SUPPORTS.hrefNormalized ? {} : {
        get: function(elem) {
            return elem.getAttribute('src', 4);
        }
    },

    href: SUPPORTS.hrefNormalized ? {} : {
        get: function(elem) {
            return elem.getAttribute('href', 4);
        }
    },

    // Support: Safari, IE9+
    // mis-reports the default selected property of an option
    // Accessing the parent's selectedIndex property fixes it
    selected: SUPPORTS.optSelected ? {} : {
        get: function(elem) {
            var parent = elem.parentNode,
                fix;

            if (parent) {
                fix = parent.selectedIndex;

                // Make sure that it also works with optgroups, see #5701
                if (parent.parentNode) {
                    fix = parent.parentNode.selectedIndex;
                }
            }
            return null;
        }
    },

    tabIndex: {
        get: function(elem) {
            // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
            // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
            // Use proper attribute retrieval(#12072)
            var tabindex = elem.getAttribute('tabindex');

            if (tabindex) { return parseNum(tabindex); }

            var nodeName = elem.nodeName;
            return (REGEX.isFocusable(nodeName) || (REGEX.isClickable(nodeName) && elem.href)) ? 0 : -1;
        }
    }
};

var getOrSetProp = function(elem, name, value) {
    var nodeType = elem.nodeType;

    // don't get/set properties on text, comment and attribute nodes
    if (!elem || nodeType === TEXT || nodeType === COMMENT || nodeType === ATTRIBUTE) {
        return;
    }

    // Fix name and attach hooks
    name = propFix[name] || name;
    var hooks = propHooks[name];

    var result;
    if (value !== undefined) {
        return hooks && ('set' in hooks) && (result = hooks.set(elem, value, name)) !== undefined ?
            result :
            (elem[name] = value);
    }

    return hooks && ('get' in hooks) && (result = hooks.get(elem, name)) !== null ?
        result :
        elem[name];
};

module.exports = {
    fn: {
        prop: function(prop, value) {
            if (arguments.length === 1 && isString(prop)) {
                var first = this[0];
                if (!first) { return; }

                return getOrSetProp(first, prop);
            }

            if (isString(prop)) {
                if (isFunction(value)) {
                    var fn = value;
                    return _.each(this, function(elem, idx) {
                        var result = fn.call(elem, idx, getOrSetProp(elem, prop));
                        getOrSetProp(elem, prop, result);
                    });
                }

                return _.each(this, (elem) => getOrSetProp(elem, prop, value));
            }

            // fallback
            return this;
        },

        removeProp: function(prop) {
            if (!isString(prop)) { return this; }

            var name = propFix[prop] || prop;
            return _.each(this, function(elem) {
                delete elem[name];
            });
        }
    }
};
<|endoftext|>


<commit_before>"use strict";

var LmdbQueue = require('../'),
    Consumer = LmdbQueue.Consumer;

var consumer = new Consumer({ path: __dirname + '/test-data', topic: 'test', name: 'test', dataType: LmdbQueue.STRING_TYPE, chunkSize: 64 * 1024 * 1024 }),
    start = Date.now();

console.log('Begin read queue.');

var cnt = 0;
while (consumer.pull()) {
    consumer.offset();
}

console.log('Read %d messages in %d ms', cnt, Date.now() - start);<commit_msg>update example.<commit_after>"use strict";

var LmdbQueue = require('../'),
    Consumer = LmdbQueue.Consumer;

var consumer = new Consumer({ path: __dirname + '/test-data', topic: 'test', name: 'test', dataType: LmdbQueue.STRING_TYPE, chunkSize: 64 * 1024 * 1024 }),
    start = Date.now();

console.log('Begin read queue.');

var cnt = 0;
while (consumer.pull()) {
    cnt++;
}

console.log('Read %d messages in %d ms', cnt, Date.now() - start);<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import {join} from 'path';
import {pathToFileURL} from 'url';

import asyncLib from 'neo-async';

import ModuleDependency from 'webpack/lib/dependencies/ModuleDependency';
import NullDependency from 'webpack/lib/dependencies/NullDependency';
import AsyncDependenciesBlock from 'webpack/lib/AsyncDependenciesBlock';
import Template from 'webpack/lib/Template';

class ClientReferenceDependency extends ModuleDependency {
  constructor(request) {
    super(request);
  }

  get type() {
    return 'client-reference';
  }
}

// This is the module that will be used to anchor all client references to.
// I.e. it will have all the client files as async deps from this point on.
// We use the Flight client implementation because you can't get to these
// without the client runtime so it's the first time in the loading sequence
// you might want them.
const clientFileName = require.resolve('../');

type ClientReferenceSearchPath = {
  directory: string,
  recursive?: boolean,
  include: RegExp,
  exclude?: RegExp,
};

type ClientReferencePath = string | ClientReferenceSearchPath;

type Options = {
  isServer: boolean,
  clientReferences?: ClientReferencePath | $ReadOnlyArray<ClientReferencePath>,
  chunkName?: string,
  manifestFilename?: string,
};

const PLUGIN_NAME = 'React Server Plugin';

export default class ReactFlightWebpackPlugin {
  clientReferences: $ReadOnlyArray<ClientReferencePath>;
  chunkName: string;
  manifestFilename: string;

  constructor(options: Options) {
    if (!options || typeof options.isServer !== 'boolean') {
      throw new Error(
        PLUGIN_NAME + ': You must specify the isServer option as a boolean.',
      );
    }
    if (options.isServer) {
      throw new Error('TODO: Implement the server compiler.');
    }
    if (!options.clientReferences) {
      this.clientReferences = [
        {
          directory: '.',
          recursive: true,
          include: /\.client\.(js|ts|jsx|tsx)$/,
        },
      ];
    } else if (
      typeof options.clientReferences === 'string' ||
      !Array.isArray(options.clientReferences)
    ) {
      this.clientReferences = [(options.clientReferences: $FlowFixMe)];
    } else {
      this.clientReferences = options.clientReferences;
    }
    if (typeof options.chunkName === 'string') {
      this.chunkName = options.chunkName;
      if (!/\[(index|request)\]/.test(this.chunkName)) {
        this.chunkName += '[index]';
      }
    } else {
      this.chunkName = 'client[index]';
    }
    this.manifestFilename =
      options.manifestFilename || 'react-client-manifest.json';
  }

  apply(compiler: any) {
    const run = (params, callback) => {
      // First we need to find all client files on the file system. We do this early so
      // that we have them synchronously available later when we need them. This might
      // not be needed anymore since we no longer need to compile the module itself in
      // a special way. So it's probably better to do this lazily and in parallel with
      // other compilation.
      const contextResolver = compiler.resolverFactory.get('context', {});
      this.resolveAllClientFiles(
        compiler.context,
        contextResolver,
        compiler.inputFileSystem,
        compiler.createContextModuleFactory(),
        (err, resolvedClientReferences) => {
          if (err) {
            callback(err);
            return;
          }
          compiler.hooks.compilation.tap(
            PLUGIN_NAME,
            (compilation, {normalModuleFactory}) => {
              compilation.dependencyFactories.set(
                ClientReferenceDependency,
                normalModuleFactory,
              );
              compilation.dependencyTemplates.set(
                ClientReferenceDependency,
                new NullDependency.Template(),
              );

              compilation.hooks.buildModule.tap(PLUGIN_NAME, module => {
                // We need to add all client references as dependency of something in the graph so
                // Webpack knows which entries need to know about the relevant chunks and include the
                // map in their runtime. The things that actually resolves the dependency is the Flight
                // client runtime. So we add them as a dependency of the Flight client runtime.
                // Anything that imports the runtime will be made aware of these chunks.
                // TODO: Warn if we don't find this file anywhere in the compilation.
                if (module.resource !== clientFileName) {
                  return;
                }
                if (resolvedClientReferences) {
                  for (let i = 0; i < resolvedClientReferences.length; i++) {
                    const dep = resolvedClientReferences[i];
                    const chunkName = this.chunkName
                      .replace(/\[index\]/g, '' + i)
                      .replace(
                        /\[request\]/g,
                        Template.toPath(dep.userRequest),
                      );

                    const block = new AsyncDependenciesBlock(
                      {
                        name: chunkName,
                      },
                      module,
                      null,
                      dep.require,
                    );
                    block.addDependency(dep);
                    module.addBlock(block);
                  }
                }
              });
            },
          );

          callback();
        },
      );
    };

    compiler.hooks.run.tapAsync(PLUGIN_NAME, run);
    compiler.hooks.watchRun.tapAsync(PLUGIN_NAME, run);

    compiler.hooks.emit.tap(PLUGIN_NAME, compilation => {
      const json = {};
      compilation.chunkGroups.forEach(chunkGroup => {
        const chunkIds = chunkGroup.chunks.map(c => c.id);

        function recordModule(id, mod) {
          // TODO: Hook into deps instead of the target module.
          // That way we know by the type of dep whether to include.
          // It also resolves conflicts when the same module is in multiple chunks.
          if (!/\.client\.js$/.test(mod.resource)) {
            return;
          }
          const moduleExports = {};
          ['', '*'].concat(mod.buildMeta.providedExports).forEach(name => {
            moduleExports[name] = {
              id: id,
              chunks: chunkIds,
              name: name,
            };
          });
          const href = pathToFileURL(mod.resource).href;
          if (href !== undefined) {
            json[href] = moduleExports;
          }
        }

        chunkGroup.chunks.forEach(chunk => {
          chunk.getModules().forEach(mod => {
            recordModule(mod.id, mod);
            // If this is a concatenation, register each child to the parent ID.
            if (mod.modules) {
              mod.modules.forEach(concatenatedMod => {
                recordModule(mod.id, concatenatedMod);
              });
            }
          });
        });
      });
      const output = JSON.stringify(json, null, 2);
      compilation.assets[this.manifestFilename] = {
        source() {
          return output;
        },
        size() {
          return output.length;
        },
      };
    });
  }

  // This attempts to replicate the dynamic file path resolution used for other wildcard
  // resolution in Webpack is using.
  resolveAllClientFiles(
    context: string,
    contextResolver: any,
    fs: any,
    contextModuleFactory: any,
    callback: (
      err: null | Error,
      result?: $ReadOnlyArray<ClientReferenceDependency>,
    ) => void,
  ) {
    asyncLib.map(
      this.clientReferences,
      (
        clientReferencePath: string | ClientReferenceSearchPath,
        cb: (
          err: null | Error,
          result?: $ReadOnlyArray<ClientReferenceDependency>,
        ) => void,
      ): void => {
        if (typeof clientReferencePath === 'string') {
          cb(null, [new ClientReferenceDependency(clientReferencePath)]);
          return;
        }
        const clientReferenceSearch: ClientReferenceSearchPath = clientReferencePath;
        contextResolver.resolve(
          {},
          context,
          clientReferencePath.directory,
          {},
          (err, resolvedDirectory) => {
            if (err) return cb(err);
            const options = {
              resource: resolvedDirectory,
              resourceQuery: '',
              recursive:
                clientReferenceSearch.recursive === undefined
                  ? true
                  : clientReferenceSearch.recursive,
              regExp: clientReferenceSearch.include,
              include: undefined,
              exclude: clientReferenceSearch.exclude,
            };
            contextModuleFactory.resolveDependencies(
              fs,
              options,
              (err2: null | Error, deps: Array<ModuleDependency>) => {
                if (err2) return cb(err2);
                const clientRefDeps = deps.map(dep => {
                  const request = join(resolvedDirectory, dep.request);
                  const clientRefDep = new ClientReferenceDependency(request);
                  clientRefDep.userRequest = dep.userRequest;
                  return clientRefDep;
                });
                cb(null, clientRefDeps);
              },
            );
          },
        );
      },
      (
        err: null | Error,
        result: $ReadOnlyArray<$ReadOnlyArray<ClientReferenceDependency>>,
      ): void => {
        if (err) return callback(err);
        const flat = [];
        for (let i = 0; i < result.length; i++) {
          flat.push.apply(flat, result[i]);
        }
        callback(null, flat);
      },
    );
  }
}
<commit_msg>[Flight] Fix webpack watch mode issue (#20457)<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import {join} from 'path';
import {pathToFileURL} from 'url';

import asyncLib from 'neo-async';

import ModuleDependency from 'webpack/lib/dependencies/ModuleDependency';
import NullDependency from 'webpack/lib/dependencies/NullDependency';
import AsyncDependenciesBlock from 'webpack/lib/AsyncDependenciesBlock';
import Template from 'webpack/lib/Template';

class ClientReferenceDependency extends ModuleDependency {
  constructor(request) {
    super(request);
  }

  get type() {
    return 'client-reference';
  }
}

// This is the module that will be used to anchor all client references to.
// I.e. it will have all the client files as async deps from this point on.
// We use the Flight client implementation because you can't get to these
// without the client runtime so it's the first time in the loading sequence
// you might want them.
const clientFileName = require.resolve('../');

type ClientReferenceSearchPath = {
  directory: string,
  recursive?: boolean,
  include: RegExp,
  exclude?: RegExp,
};

type ClientReferencePath = string | ClientReferenceSearchPath;

type Options = {
  isServer: boolean,
  clientReferences?: ClientReferencePath | $ReadOnlyArray<ClientReferencePath>,
  chunkName?: string,
  manifestFilename?: string,
};

const PLUGIN_NAME = 'React Server Plugin';

export default class ReactFlightWebpackPlugin {
  clientReferences: $ReadOnlyArray<ClientReferencePath>;
  chunkName: string;
  manifestFilename: string;

  constructor(options: Options) {
    if (!options || typeof options.isServer !== 'boolean') {
      throw new Error(
        PLUGIN_NAME + ': You must specify the isServer option as a boolean.',
      );
    }
    if (options.isServer) {
      throw new Error('TODO: Implement the server compiler.');
    }
    if (!options.clientReferences) {
      this.clientReferences = [
        {
          directory: '.',
          recursive: true,
          include: /\.client\.(js|ts|jsx|tsx)$/,
        },
      ];
    } else if (
      typeof options.clientReferences === 'string' ||
      !Array.isArray(options.clientReferences)
    ) {
      this.clientReferences = [(options.clientReferences: $FlowFixMe)];
    } else {
      this.clientReferences = options.clientReferences;
    }
    if (typeof options.chunkName === 'string') {
      this.chunkName = options.chunkName;
      if (!/\[(index|request)\]/.test(this.chunkName)) {
        this.chunkName += '[index]';
      }
    } else {
      this.chunkName = 'client[index]';
    }
    this.manifestFilename =
      options.manifestFilename || 'react-client-manifest.json';
  }

  apply(compiler: any) {
    let resolvedClientReferences;
    const run = (params, callback) => {
      // First we need to find all client files on the file system. We do this early so
      // that we have them synchronously available later when we need them. This might
      // not be needed anymore since we no longer need to compile the module itself in
      // a special way. So it's probably better to do this lazily and in parallel with
      // other compilation.
      const contextResolver = compiler.resolverFactory.get('context', {});
      this.resolveAllClientFiles(
        compiler.context,
        contextResolver,
        compiler.inputFileSystem,
        compiler.createContextModuleFactory(),
        (err, resolvedClientRefs) => {
          if (err) {
            callback(err);
            return;
          }
          resolvedClientReferences = resolvedClientRefs;
          callback();
        },
      );
    };

    compiler.hooks.run.tapAsync(PLUGIN_NAME, run);
    compiler.hooks.watchRun.tapAsync(PLUGIN_NAME, run);
    compiler.hooks.compilation.tap(
      PLUGIN_NAME,
      (compilation, {normalModuleFactory}) => {
        compilation.dependencyFactories.set(
          ClientReferenceDependency,
          normalModuleFactory,
        );
        compilation.dependencyTemplates.set(
          ClientReferenceDependency,
          new NullDependency.Template(),
        );

        compilation.hooks.buildModule.tap(PLUGIN_NAME, module => {
          // We need to add all client references as dependency of something in the graph so
          // Webpack knows which entries need to know about the relevant chunks and include the
          // map in their runtime. The things that actually resolves the dependency is the Flight
          // client runtime. So we add them as a dependency of the Flight client runtime.
          // Anything that imports the runtime will be made aware of these chunks.
          // TODO: Warn if we don't find this file anywhere in the compilation.
          if (module.resource !== clientFileName) {
            return;
          }
          if (resolvedClientReferences) {
            for (let i = 0; i < resolvedClientReferences.length; i++) {
              const dep = resolvedClientReferences[i];
              const chunkName = this.chunkName
                .replace(/\[index\]/g, '' + i)
                .replace(/\[request\]/g, Template.toPath(dep.userRequest));

              const block = new AsyncDependenciesBlock(
                {
                  name: chunkName,
                },
                module,
                null,
                dep.require,
              );
              block.addDependency(dep);
              module.addBlock(block);
            }
          }
        });
      },
    );

    compiler.hooks.emit.tap(PLUGIN_NAME, compilation => {
      const json = {};
      compilation.chunkGroups.forEach(chunkGroup => {
        const chunkIds = chunkGroup.chunks.map(c => c.id);

        function recordModule(id, mod) {
          // TODO: Hook into deps instead of the target module.
          // That way we know by the type of dep whether to include.
          // It also resolves conflicts when the same module is in multiple chunks.
          if (!/\.client\.js$/.test(mod.resource)) {
            return;
          }
          const moduleExports = {};
          ['', '*'].concat(mod.buildMeta.providedExports).forEach(name => {
            moduleExports[name] = {
              id: id,
              chunks: chunkIds,
              name: name,
            };
          });
          const href = pathToFileURL(mod.resource).href;
          if (href !== undefined) {
            json[href] = moduleExports;
          }
        }

        chunkGroup.chunks.forEach(chunk => {
          chunk.getModules().forEach(mod => {
            recordModule(mod.id, mod);
            // If this is a concatenation, register each child to the parent ID.
            if (mod.modules) {
              mod.modules.forEach(concatenatedMod => {
                recordModule(mod.id, concatenatedMod);
              });
            }
          });
        });
      });
      const output = JSON.stringify(json, null, 2);
      compilation.assets[this.manifestFilename] = {
        source() {
          return output;
        },
        size() {
          return output.length;
        },
      };
    });
  }

  // This attempts to replicate the dynamic file path resolution used for other wildcard
  // resolution in Webpack is using.
  resolveAllClientFiles(
    context: string,
    contextResolver: any,
    fs: any,
    contextModuleFactory: any,
    callback: (
      err: null | Error,
      result?: $ReadOnlyArray<ClientReferenceDependency>,
    ) => void,
  ) {
    asyncLib.map(
      this.clientReferences,
      (
        clientReferencePath: string | ClientReferenceSearchPath,
        cb: (
          err: null | Error,
          result?: $ReadOnlyArray<ClientReferenceDependency>,
        ) => void,
      ): void => {
        if (typeof clientReferencePath === 'string') {
          cb(null, [new ClientReferenceDependency(clientReferencePath)]);
          return;
        }
        const clientReferenceSearch: ClientReferenceSearchPath = clientReferencePath;
        contextResolver.resolve(
          {},
          context,
          clientReferencePath.directory,
          {},
          (err, resolvedDirectory) => {
            if (err) return cb(err);
            const options = {
              resource: resolvedDirectory,
              resourceQuery: '',
              recursive:
                clientReferenceSearch.recursive === undefined
                  ? true
                  : clientReferenceSearch.recursive,
              regExp: clientReferenceSearch.include,
              include: undefined,
              exclude: clientReferenceSearch.exclude,
            };
            contextModuleFactory.resolveDependencies(
              fs,
              options,
              (err2: null | Error, deps: Array<ModuleDependency>) => {
                if (err2) return cb(err2);
                const clientRefDeps = deps.map(dep => {
                  const request = join(resolvedDirectory, dep.request);
                  const clientRefDep = new ClientReferenceDependency(request);
                  clientRefDep.userRequest = dep.userRequest;
                  return clientRefDep;
                });
                cb(null, clientRefDeps);
              },
            );
          },
        );
      },
      (
        err: null | Error,
        result: $ReadOnlyArray<$ReadOnlyArray<ClientReferenceDependency>>,
      ): void => {
        if (err) return callback(err);
        const flat = [];
        for (let i = 0; i < result.length; i++) {
          flat.push.apply(flat, result[i]);
        }
        callback(null, flat);
      },
    );
  }
}
<|endoftext|>


<commit_before>import { resolve, join } from 'path'
import webpack from 'webpack'
import glob from 'glob-promise'
import WriteFilePlugin from 'write-file-webpack-plugin'
import UnlinkFilePlugin from './plugins/unlink-file-plugin'
import WatchPagesPlugin from './plugins/watch-pages-plugin'
import WatchRemoveEventPlugin from './plugins/watch-remove-event-plugin'
import DynamicEntryPlugin from './plugins/dynamic-entry-plugin'
import DetachPlugin from './plugins/detach-plugin'
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin'

export default async function createCompiler (dir, { hotReload = false } = {}) {
  dir = resolve(dir)

  const pages = await glob('pages/**/*.js', { cwd: dir })

  const entry = {}
  const defaultEntries = hotReload ? ['webpack/hot/dev-server'] : []
  for (const p of pages) {
    entry[join('bundles', p)] = defaultEntries.concat(['./' + p])
  }

  const nextPagesDir = join(__dirname, '..', '..', 'pages')

  const errorEntry = join('bundles', 'pages', '_error.js')
  const defaultErrorPath = join(nextPagesDir, '_error.js')
  if (!entry[errorEntry]) {
    entry[errorEntry] = defaultEntries.concat([defaultErrorPath])
  }

  const errorDebugEntry = join('bundles', 'pages', '_error-debug.js')
  const errorDebugPath = join(nextPagesDir, '_error-debug.js')
  entry[errorDebugEntry] = errorDebugPath

  const nodeModulesDir = join(__dirname, '..', '..', '..', 'node_modules')

  const plugins = [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    }),
    new WriteFilePlugin({
      exitOnErrors: false,
      log: false,
      // required not to cache removed files
      useHashIndex: false
    })
  ].concat(hotReload ? [
    new webpack.HotModuleReplacementPlugin(),
    new DetachPlugin(),
    new DynamicEntryPlugin(),
    new UnlinkFilePlugin(),
    new WatchRemoveEventPlugin(),
    new WatchPagesPlugin(dir),
    new FriendlyErrorsWebpackPlugin({
      messages: ['Your application is running here http://localhost:3000']
    })
  ] : [
    new webpack.optimize.UglifyJsPlugin({
      compress: { warnings: false },
      sourceMap: false
    })
  ])

  const babelRuntimePath = require.resolve('babel-runtime/package')
  .replace(/[\\\/]package\.json$/, '')

  const loaders = [{
    test: /\.js$/,
    loader: 'emit-file-loader',
    include: [dir, nextPagesDir],
    exclude (str) {
      return /node_modules/.test(str) && str.indexOf(nextPagesDir) !== 0
    },
    query: {
      name: 'dist/[path][name].[ext]'
    }
  }]
  .concat(hotReload ? [{
    test: /\.js$/,
    loader: 'hot-self-accept-loader',
    include: [
      join(dir, 'pages'),
      nextPagesDir
    ]
  }] : [])
  .concat([{
    loader: 'babel',
    include: nextPagesDir,
    query: {
      plugins: [
        [
          require.resolve('babel-plugin-module-resolver'),
          {
            alias: {
              'ansi-html': require.resolve('ansi-html')
            }
          }
        ]
      ]
    }
  }, {
    test: /\.js$/,
    loader: 'babel',
    include: [dir, nextPagesDir],
    exclude (str) {
      return /node_modules/.test(str) && str.indexOf(nextPagesDir) !== 0
    },
    query: {
      presets: ['es2015', 'react'],
      plugins: [
        require.resolve('babel-plugin-transform-async-to-generator'),
        require.resolve('babel-plugin-transform-object-rest-spread'),
        require.resolve('babel-plugin-transform-class-properties'),
        require.resolve('babel-plugin-transform-runtime'),
        [
          require.resolve('babel-plugin-module-resolver'),
          {
            alias: {
              'babel-runtime': babelRuntimePath,
              react: require.resolve('react'),
              'next/link': require.resolve('../../lib/link'),
              'next/css': require.resolve('../../lib/css'),
              'next/head': require.resolve('../../lib/head')
            }
          }
        ]
      ]
    }
  }])

  const interpolateNames = new Map([
    [defaultErrorPath, 'dist/pages/_error.js'],
    [errorDebugPath, 'dist/pages/_error-debug.js']
  ])

  return webpack({
    context: dir,
    entry,
    output: {
      path: join(dir, '.next'),
      filename: '[name]',
      libraryTarget: 'commonjs2',
      publicPath: hotReload ? 'http://localhost:3030/' : null
    },
    externals: [
      'react',
      'react-dom',
      {
        [require.resolve('react')]: 'react',
        [require.resolve('../../lib/link')]: 'next/link',
        [require.resolve('../../lib/css')]: 'next/css',
        [require.resolve('../../lib/head')]: 'next/head'
      }
    ],
    resolve: {
      root: [
        nodeModulesDir,
        join(dir, 'node_modules')
      ]
    },
    resolveLoader: {
      root: [
        nodeModulesDir,
        join(__dirname, 'loaders')
      ]
    },
    plugins,
    module: {
      preLoaders: [
        { test: /\.json$/, loader: 'json-loader' }
      ],
      loaders
    },
    customInterpolateName: function (url, name, opts) {
      return interpolateNames.get(this.resourcePath) || url
    }
  })
}
<commit_msg>Removes unecessary and undisplayed default message<commit_after>import { resolve, join } from 'path'
import webpack from 'webpack'
import glob from 'glob-promise'
import WriteFilePlugin from 'write-file-webpack-plugin'
import UnlinkFilePlugin from './plugins/unlink-file-plugin'
import WatchPagesPlugin from './plugins/watch-pages-plugin'
import WatchRemoveEventPlugin from './plugins/watch-remove-event-plugin'
import DynamicEntryPlugin from './plugins/dynamic-entry-plugin'
import DetachPlugin from './plugins/detach-plugin'
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin'

export default async function createCompiler (dir, { hotReload = false } = {}) {
  dir = resolve(dir)

  const pages = await glob('pages/**/*.js', { cwd: dir })

  const entry = {}
  const defaultEntries = hotReload ? ['webpack/hot/dev-server'] : []
  for (const p of pages) {
    entry[join('bundles', p)] = defaultEntries.concat(['./' + p])
  }

  const nextPagesDir = join(__dirname, '..', '..', 'pages')

  const errorEntry = join('bundles', 'pages', '_error.js')
  const defaultErrorPath = join(nextPagesDir, '_error.js')
  if (!entry[errorEntry]) {
    entry[errorEntry] = defaultEntries.concat([defaultErrorPath])
  }

  const errorDebugEntry = join('bundles', 'pages', '_error-debug.js')
  const errorDebugPath = join(nextPagesDir, '_error-debug.js')
  entry[errorDebugEntry] = errorDebugPath

  const nodeModulesDir = join(__dirname, '..', '..', '..', 'node_modules')

  const plugins = [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    }),
    new WriteFilePlugin({
      exitOnErrors: false,
      log: false,
      // required not to cache removed files
      useHashIndex: false
    })
  ].concat(hotReload ? [
    new webpack.HotModuleReplacementPlugin(),
    new DetachPlugin(),
    new DynamicEntryPlugin(),
    new UnlinkFilePlugin(),
    new WatchRemoveEventPlugin(),
    new WatchPagesPlugin(dir),
    new FriendlyErrorsWebpackPlugin()
  ] : [
    new webpack.optimize.UglifyJsPlugin({
      compress: { warnings: false },
      sourceMap: false
    })
  ])

  const babelRuntimePath = require.resolve('babel-runtime/package')
  .replace(/[\\\/]package\.json$/, '')

  const loaders = [{
    test: /\.js$/,
    loader: 'emit-file-loader',
    include: [dir, nextPagesDir],
    exclude (str) {
      return /node_modules/.test(str) && str.indexOf(nextPagesDir) !== 0
    },
    query: {
      name: 'dist/[path][name].[ext]'
    }
  }]
  .concat(hotReload ? [{
    test: /\.js$/,
    loader: 'hot-self-accept-loader',
    include: [
      join(dir, 'pages'),
      nextPagesDir
    ]
  }] : [])
  .concat([{
    loader: 'babel',
    include: nextPagesDir,
    query: {
      plugins: [
        [
          require.resolve('babel-plugin-module-resolver'),
          {
            alias: {
              'ansi-html': require.resolve('ansi-html')
            }
          }
        ]
      ]
    }
  }, {
    test: /\.js$/,
    loader: 'babel',
    include: [dir, nextPagesDir],
    exclude (str) {
      return /node_modules/.test(str) && str.indexOf(nextPagesDir) !== 0
    },
    query: {
      presets: ['es2015', 'react'],
      plugins: [
        require.resolve('babel-plugin-transform-async-to-generator'),
        require.resolve('babel-plugin-transform-object-rest-spread'),
        require.resolve('babel-plugin-transform-class-properties'),
        require.resolve('babel-plugin-transform-runtime'),
        [
          require.resolve('babel-plugin-module-resolver'),
          {
            alias: {
              'babel-runtime': babelRuntimePath,
              react: require.resolve('react'),
              'next/link': require.resolve('../../lib/link'),
              'next/css': require.resolve('../../lib/css'),
              'next/head': require.resolve('../../lib/head')
            }
          }
        ]
      ]
    }
  }])

  const interpolateNames = new Map([
    [defaultErrorPath, 'dist/pages/_error.js'],
    [errorDebugPath, 'dist/pages/_error-debug.js']
  ])

  return webpack({
    context: dir,
    entry,
    output: {
      path: join(dir, '.next'),
      filename: '[name]',
      libraryTarget: 'commonjs2',
      publicPath: hotReload ? 'http://localhost:3030/' : null
    },
    externals: [
      'react',
      'react-dom',
      {
        [require.resolve('react')]: 'react',
        [require.resolve('../../lib/link')]: 'next/link',
        [require.resolve('../../lib/css')]: 'next/css',
        [require.resolve('../../lib/head')]: 'next/head'
      }
    ],
    resolve: {
      root: [
        nodeModulesDir,
        join(dir, 'node_modules')
      ]
    },
    resolveLoader: {
      root: [
        nodeModulesDir,
        join(__dirname, 'loaders')
      ]
    },
    plugins,
    module: {
      preLoaders: [
        { test: /\.json$/, loader: 'json-loader' }
      ],
      loaders
    },
    customInterpolateName: function (url, name, opts) {
      return interpolateNames.get(this.resourcePath) || url
    }
  })
}
<|endoftext|>


<commit_before>var path 		= require('path');
var rootPath 	= path.normalize(__dirname + '/../../');

module.exports 	= {
    local: {
        baseUrl: 'http://localhost:3030',
        db: 'mongodb://localhost/rp_local',
        rootPath: rootPath,
        port: process.env.PORT || 30030
    staging : {
        baseUrl: 'http://dev.resourceprojects.org',
        //db: '@aws-us-east-1-portal.14.dblayer.com:10669/rp_dev?ssl=true',
        db: '@aws-us-east-1-portal.14.dblayer.com:10669,aws-us-east-1-portal.13.dblayer.com:10499/rp_dev?ssl=true',
        rootPath: rootPath,
        port: process.env.PORT || 80
    }
};
<commit_msg>fixed brokend config file<commit_after>var path 		= require('path');
var rootPath 	= path.normalize(__dirname + '/../../');

module.exports 	= {
    local: {
        baseUrl: 'http://localhost:3030',
        db: 'mongodb://localhost/rp_local',
        rootPath: rootPath,
        port: process.env.PORT || 30030
    },
    staging : {
        baseUrl: 'http://dev.resourceprojects.org',
        //db: '@aws-us-east-1-portal.14.dblayer.com:10669/rp_dev?ssl=true',
        db: '@aws-us-east-1-portal.14.dblayer.com:10669,aws-us-east-1-portal.13.dblayer.com:10499/rp_dev?ssl=true',
        rootPath: rootPath,
        port: process.env.PORT || 80
    }
};
<|endoftext|>


<commit_before>
/**
 * Middleware
 */
var requires = require('../app/Middleware/auth').requires;

/**
 * Controllers
 */
var navigation = require('../app/controllers/navigation')
  , users = require('../app/controllers/users');

module.exports = function (app) {

  // temporary test route
  app.get('/test-api/test.json', function *() {
    this.body = {
      "name": "brewGet",
      "description": "a node/express app that facilitates the trading of beer"
    }
  })

  // navigation
  app.get('/api/nav', navigation.items)

  // authentication
  app.post('/api/users/sign-in', users.authenticate);
  app.delete('/api/users/sign-out', users.signOut);

  // users
  app.get('/api/users', users.index);
  app.post('/api/users', users.create);
  app.get('/api/users/:username', users.show);
  app.put('/api/users/:username', requires.self, users.update);
  app.delete('/api/users/:username', requires.self, users.destroy);

  // redirect all remaining GET method routes to angular router
  app.get('*', function* () {
    this.redirect('/#!' + this.url);
  });
}
<commit_msg>correct capitalization error in middleware reference<commit_after>
/**
 * Middleware
 */
var requires = require('../app/middleware/auth').requires;

/**
 * Controllers
 */
var navigation = require('../app/controllers/navigation')
  , users = require('../app/controllers/users');

module.exports = function (app) {

  // temporary test route
  app.get('/test-api/test.json', function *() {
    this.body = {
      "name": "brewGet",
      "description": "a node/express app that facilitates the trading of beer"
    }
  })

  // navigation
  app.get('/api/nav', navigation.items)

  // authentication
  app.post('/api/users/sign-in', users.authenticate);
  app.delete('/api/users/sign-out', users.signOut);

  // users
  app.get('/api/users', users.index);
  app.post('/api/users', users.create);
  app.get('/api/users/:username', users.show);
  app.put('/api/users/:username', requires.self, users.update);
  app.delete('/api/users/:username', requires.self, users.destroy);

  // redirect all remaining GET method routes to angular router
  app.get('*', function* () {
    this.redirect('/#!' + this.url);
  });
}
<|endoftext|>


<commit_before>var reviewController = require('../reviews/reviewController.js');
var userController = require('../users/userController.js');
var commentController = require('../comments/commentController.js');
var jwt = require('express-jwt');

//Checks the token for authentication when attatched to route
var authCheck = jwt({
  secret: new Buffer('2e4hy18SeEf1D1TyFZ1H375OovOhyhxFu0GYZb8j9zhXygsiNlhdYWCjDaqIGl1c', 'base64'),
  audience: 'GaWAS7TybB6Fqwa9uBw2SDVMPRGSAVDK'
});

module.exports = function (app, express) {

  //Review Routes
  app.get('/review/:type/:typeId', reviewController.getReviews);

  app.post('/review/:type/:typeId', authCheck, reviewController.postReview);

  app.get('/review/:reviewId', reviewController.getReviewById);

  app.put('/review/:reviewId', authCheck, reviewController.editReview);

  app.put('/review/count/:reviewId', authCheck, reviewController.editCount);

  app.delete('/review/:reviewId', authCheck, reviewController.deleteReview);

  //Comment Routes
  app.get('/comment/:reviewId', commentController.getCommentByReviewId);

  app.post('/comment', authCheck, commentController.postComment);

  app.delete('/comment/:commentId', authCheck, commentController.deleteComment);

  //User Routes
  app.get('/user/:username', userController.getUserByUsername);

  app.get('/user/reviews/:userId', reviewController.getUserReviews);

  app.post('/user', authCheck, userController.postUser);

  app.put('/user/edit', authCheck, userController.editUser);

  //MIKE - I changed this route slightly, as I think auth0 passes the correct id in the request, so we don't need to provide an id parameter. Does that sound right?
  app.delete('/user/delete', authCheck, userController.deleteUser);         //Luke's version
  // app.delete('/user/delete/:id', authCheck, userController.deleteUser);   //Mike's version

  //User favorites/watched/currently watching routes
  app.get('/favorites', authCheck, userController.getUserLists);

  app.delete('/delete/:type', authCheck, userController.removeFromUserLists);

  app.post('/add/:type', authCheck, userController.addToUserLists);

};<commit_msg>removed route comment from luke to mike<commit_after>var reviewController = require('../reviews/reviewController.js');
var userController = require('../users/userController.js');
var commentController = require('../comments/commentController.js');
var jwt = require('express-jwt');

//Checks the token for authentication when attatched to route
var authCheck = jwt({
  secret: new Buffer('2e4hy18SeEf1D1TyFZ1H375OovOhyhxFu0GYZb8j9zhXygsiNlhdYWCjDaqIGl1c', 'base64'),
  audience: 'GaWAS7TybB6Fqwa9uBw2SDVMPRGSAVDK'
});

module.exports = function (app, express) {

  //Review Routes
  app.get('/review/:type/:typeId', reviewController.getReviews);

  app.post('/review/:type/:typeId', authCheck, reviewController.postReview);

  app.get('/review/:reviewId', reviewController.getReviewById);

  app.put('/review/:reviewId', authCheck, reviewController.editReview);

  app.put('/review/count/:reviewId', authCheck, reviewController.editCount);

  app.delete('/review/:reviewId', authCheck, reviewController.deleteReview);

  //Comment Routes
  app.get('/comment/:reviewId', commentController.getCommentByReviewId);

  app.post('/comment', authCheck, commentController.postComment);

  app.delete('/comment/:commentId', authCheck, commentController.deleteComment);

  //User Routes
  app.get('/user/:username', userController.getUserByUsername);

  app.get('/user/reviews/:userId', reviewController.getUserReviews);

  app.post('/user', authCheck, userController.postUser);

  app.put('/user/edit', authCheck, userController.editUser);

  app.delete('/user/delete', authCheck, userController.deleteUser);

  //User favorites/watched/currently watching routes
  app.get('/favorites', authCheck, userController.getUserLists);

  app.delete('/delete/:type', authCheck, userController.removeFromUserLists);

  app.post('/add/:type', authCheck, userController.addToUserLists);

};<|endoftext|>


<commit_before>
/**
 * Module dependencies
 */
var mongoose = require('mongoose')
  , net = require('net')
  , Promise = require('bluebird');

var Session = mongoose.model('SessionStore')
  , User = mongoose.model('User');

/**
 * Helper functions
 */
var user_compact = function (user) {};

/**
 * Web socket client
 */
var client = net.connect({ port: 4001 }, function () {
  client.write(JSON.stringify({
    event: 'console.log',
    message: 'TCP client connected on port ' + ( process.env.PORT || 3000 )
  }));
});

/**
 * Events
 */
module.exports = function (socketEmitter) {
  socketEmitter.on('session.find', function (sid, cid) {
    Promise.promisify(Session.findOne, Session)({ sid: 'koa:sess:' + sid }).then(function (session) {
      if (!session || !session.blob) return;
      session = JSON.parse(session.blob);
      return Promise.promisify(User.findById, User)(session.user, { images: 1, slug: 1, username: 1, location: 1 });
    }).then(function (user) {
      if (!user) return client.write(JSON.stringify({
        cid: cid,
        event: 'session.populate',
        sid: sid
      }));
      var images = []
        , location = '';
      user = user._doc;
      if (user.images && user.images.length > 0) {
        var i = user.images.length;
        while (i--) if (user.images[i].geometry.width === 50 || user.images[i].geometry.width === 100) images.push({
          geometry: user.images[i].geometry,
          src: user.images[i].src
        });
      }
      if (user.location && user.location.country && user.location.country.name === 'United States') {
        if (user.location.state && user.location.state.abbreviation) {
          if (user.location.city && user.location.city.name) location = user.location.city.name + ', ' + user.location.state.abbreviation;
          else if (user.location.state.name) location = user.location.state.name;
          else location = user.location.state.abbreviation;
        } else if (user.location.city && user.location.city.name) location = user.location.city.name;
        else if (user.location.name) location = user.location.name;
      }
      else if (user.location && user.location.name) location = user.location.name;
      user.images = images;
      user.location = location;
      client.write(JSON.stringify({
        cid: cid,
        event: 'session.populate',
        sid: sid,
        user: user
      }));
    }).fail(function (err) {
      console.error(err);
    });
  });
  socketEmitter.on('session.update', function (sid, session) {
    if (!sid) return;
    console.log(sid);
    // client.write(JSON.stringify({
    //
    // }));
  });

  client.on('data', function (data) {
    try {
      var dataObj = JSON.parse(data);
      if (dataObj.event === 'console.log') console.log(dataObj.message);
      else if (dataObj.event === 'session.find') socketEmitter.emit('session.find', dataObj.sid, dataObj.cid);
    } catch (err) {}
  });
  client.on('end', function () {
    console.log('client disconnected from TCP server');
  });
};
<commit_msg>add event listener for connection id<commit_after>
/**
 * Module dependencies
 */
var mongoose = require('mongoose')
  , net = require('net')
  , Promise = require('bluebird');

var Session = mongoose.model('SessionStore')
  , User = mongoose.model('User');

/**
 * Helper functions
 */
var user_compact = function (user) {};

/**
 * Web socket client
 */
var client = net.connect({ port: 4001 }, function () {
  client.write(JSON.stringify({
    event: 'console.log',
    message: 'TCP client connected on port ' + ( process.env.PORT || 3000 )
  }));
});

/**
 * Events
 */
module.exports = function (socketEmitter) {
  socketEmitter.on('connection.id', function (sid, cid) {});
  socketEmitter.on('session.find', function (sid, cid) {
    Promise.promisify(Session.findOne, Session)({ sid: 'koa:sess:' + sid }).then(function (session) {
      if (!session || !session.blob) return;
      session = JSON.parse(session.blob);
      return Promise.promisify(User.findById, User)(session.user, { images: 1, slug: 1, username: 1, location: 1 });
    }).then(function (user) {
      if (!user) return client.write(JSON.stringify({
        cid: cid,
        event: 'session.populate',
        sid: sid
      }));
      var images = []
        , location = '';
      user = user._doc;
      if (user.images && user.images.length > 0) {
        var i = user.images.length;
        while (i--) if (user.images[i].geometry.width === 50 || user.images[i].geometry.width === 100) images.push({
          geometry: user.images[i].geometry,
          src: user.images[i].src
        });
      }
      if (user.location && user.location.country && user.location.country.name === 'United States') {
        if (user.location.state && user.location.state.abbreviation) {
          if (user.location.city && user.location.city.name) location = user.location.city.name + ', ' + user.location.state.abbreviation;
          else if (user.location.state.name) location = user.location.state.name;
          else location = user.location.state.abbreviation;
        } else if (user.location.city && user.location.city.name) location = user.location.city.name;
        else if (user.location.name) location = user.location.name;
      }
      else if (user.location && user.location.name) location = user.location.name;
      user.images = images;
      user.location = location;
      client.write(JSON.stringify({
        cid: cid,
        event: 'session.populate',
        sid: sid,
        user: user
      }));
    }).fail(function (err) {
      console.error(err);
    });
  });
  socketEmitter.on('session.update', function (sid, session) {
    if (!sid) return;
    console.log(sid);
    // client.write(JSON.stringify({
    //
    // }));
  });

  client.on('data', function (data) {
    try {
      var dataObj = JSON.parse(data);
      if (dataObj.event === 'console.log') console.log(dataObj.message);
      else if (dataObj.event === 'session.find') socketEmitter.emit('session.find', dataObj.sid, dataObj.cid);
    } catch (err) {}
  });
  client.on('end', function () {
    console.log('client disconnected from TCP server');
  });
};
<|endoftext|>


<commit_before>// Get the required shit together
const Discord = require('eris');
const config = require('config');

const client = new Discord.Client(config.get('api').discord.token, { maxShards: config.get('shards') });
const prefixes = config.get('prefix');
let regex = null;

// Setup commands and util objects.
const commands = require('./cogs.js');
client.utils = require('./utils.js');

// Just plop all valid commands in for other cogs to look at it.
client.commands = commands;

client.on('ready', () => {
	// Set up regex for the bot.
	regex = new RegExp(`(${prefixes.join('|')}).?(${Object.keys(commands).join('|')})\\s?(.*)`);

	// Add mentions to the prefix list
	prefixes.push(`<@${client.user.id}>`);
	console.log('Connected to Discord!');
});

client.on('messageCreate', (message) => {
	// Disallow if the author is a bot
	if (message.author.bot) return;

	// Test the message content on the regular expression
	const result = regex.exec(message.content);

	// Return if it fails the regex commands check test
	if (!result) return;

	// Bake some cool extra crap into the message
	message.prefix = result[1];
	message.command = result[2];
	message.input = result[3] || null;
	message.words = result[3].split(/\n+|\s+/g);

	// Run the actual command
	commands[message.command].command(message, client);
});

// Connect to Discord
console.log('Discord loaded');
client.connect();

module.exports = client;
<commit_msg>re-add server listings<commit_after>// Get the required shit together
const Discord = require('eris');
const config = require('config');
const utils = require('./utils.js');

const client = new Discord.Client(config.get('api').discord.token, { maxShards: config.get('shards') });
const prefixes = config.get('prefix');
let regex = null;

// Setup commands and util objects.
const commands = require('./cogs.js');

// Just plop all valid commands in for other cogs to look at it.
client.commands = commands;

client.on('ready', () => {
	// Set up regex for the bot.
	regex = new RegExp(`(${prefixes.join('|')}).?(${Object.keys(commands).join('|')})\\s?(.*)`);

	// Add mentions to the prefix list
	prefixes.push(`<@${client.user.id}>`);
	console.log('Connected to Discord!');

	// Send DBOTS info if it was provided.
	if (config.get('api').botsdiscordpw) {
		utils.botsdiscordpw(client);
		setInterval(() => {
			utils.botsdiscordpw(client);
		}, 1800000);
	}

	// Send FAKEDBOTS info if it was provided.
	if (config.get('api').discordbotsorg) {
		utils.discordbotsorg(client);
		setInterval(() => {
			utils.discordbotsorg(client);
		}, 1800000);
	}
});

client.on('messageCreate', (message) => {
	// Disallow if the author is a bot
	if (message.author.bot) return;

	// Test the message content on the regular expression
	const result = regex.exec(message.content);

	// Return if it fails the regex commands check test
	if (!result) return;

	// Bake some cool extra crap into the message
	message.prefix = result[1];
	message.command = result[2];
	message.input = result[3] || null;
	message.words = result[3].split(/\n+|\s+/g);

	// Run the actual command
	commands[message.command].command(message, client);
});

// Connect to Discord
console.log('Discord loaded');
client.connect();

module.exports = client;
<|endoftext|>


<commit_before>/* eslint-disable max-lines */
const _ = require('lodash');
const { google } = require('googleapis');
const { nanoid } = require('nanoid');
const token = require('./token.js');
const config = require('nconf')
	.argv()
	.env({ lowerCase: true })	// Load environment variables
	.file('environment', { file: `config/${process.env.NODE_ENV}.json` })
	.file('defaults', { file: 'config/default.json' });

//let oAuth2Client;

GoogleActions = {

	authCheck : (account, res)=>{
		if(!account || !account.googleId){ // If not signed into Google
			const err = new Error('Not Signed In');
			err.status = 401;
			throw err;
		}

		const oAuth2Client = new google.auth.OAuth2(
			config.get('google_client_id'),
			config.get('google_client_secret'),
			'/auth/google/redirect'
		);

		oAuth2Client.setCredentials({
			access_token  : account.googleAccessToken, //Comment out to refresh token
			refresh_token : account.googleRefreshToken
		});

		oAuth2Client.on('tokens', (tokens)=>{
			if(tokens.refresh_token) {
				account.googleRefreshToken = tokens.refresh_token;
			}
			account.googleAccessToken = tokens.access_token;
			const JWTToken = token.generateAccessToken(account);

			//Save updated token to cookie
			//res.cookie('nc_session', JWTToken, { maxAge: 1000*60*60*24*365, path: '/', sameSite: 'lax' });
			res.cookie('nc_session', JWTToken, { maxAge: 1000*60*60*24*365, path: '/', sameSite: 'lax', domain: '.naturalcrit.com' });
		});

		return oAuth2Client;
	},

	getGoogleFolder : async (auth)=>{
		const drive = google.drive({ version: 'v3', auth: auth });

		fileMetadata = {
			'name'     : 'Homebrewery',
			'mimeType' : 'application/vnd.google-apps.folder'
		};

		const obj = await drive.files.list({
			q : 'mimeType = \'application/vnd.google-apps.folder\''
		})
		.catch((err)=>{
			console.log('Error searching Google Drive Folders');
			console.error(err);
		});

		let folderId;

		if(obj.data.files.length == 0){
			const obj = await drive.files.create({
				resource : fileMetadata
			})
			.catch((err)=>{
				console.log('Error creating google app folder');
				console.error(err);
			});

			folderId = obj.data.id;
		} else {
			folderId = obj.data.files[0].id;
		}

		return folderId;
	},

	listGoogleBrews : async (req, res)=>{

		oAuth2Client = GoogleActions.authCheck(req.account, res);

		//TODO: Change to service account to allow non-owners to view published files.
		// Requires a driveId parameter in the drive.files.list command
		// const keys = JSON.parse(config.get('service_account'));
		// const auth = google.auth.fromJSON(keys);
		// auth.scopes = ['https://www.googleapis.com/auth/drive'];

		const drive = google.drive({ version: 'v3', auth: oAuth2Client });

		const obj = await drive.files.list({
			pageSize : 100,
			fields   : 'nextPageToken, files(id, name, description, createdTime, modifiedTime, properties)',
			q        : 'mimeType != \'application/vnd.google-apps.folder\' and trashed = false'
		})
		.catch((err)=>{
	    return console.error(`Error Listing Google Brews: ${err}`);
			//TODO: Should break out here, but continues on for some reason.
	  });

		if(!obj.data.files.length) {
	    console.log('No files found.');
	  }

		const brews = obj.data.files.map((file)=>{
	    return {
	      text      : '',
	      shareId   : file.properties.shareId,
	      editId    : file.properties.editId,
	      createdAt : file.createdTime,
	      updatedAt : file.modifiedTime,
	      gDrive    : true,
	      googleId  : file.id,
		  pageCount : file.properties.pageCount,

	      title       : file.properties.title,
	      description : file.description,
		  views       : file.properties.views,
	      tags        : '',
	      published   : file.properties.published ? file.properties.published == 'true' : false,
	      authors     : [req.account.username],	//TODO: properly save and load authors to google drive
	      systems     : []
	    };
	  });

	  return brews;
	},

	existsGoogleBrew : async (auth, id)=>{
		const drive = google.drive({ version: 'v3', auth: auth });

		const result = await drive.files.get({ fileId: id })
		.catch((err)=>{
			console.log('error checking file exists...');
			console.log(err);
			return false;
		});

		if(result){return true;}

		return false;
	},

	updateGoogleBrew : async (auth, brew)=>{
		const drive = google.drive({ version: 'v3', auth: auth });

		if(await GoogleActions.existsGoogleBrew(auth, brew.googleId) == true) {
			await drive.files.update({
				fileId   : brew.googleId,
				resource : { name        : `${brew.title}.txt`,
										 description : `${brew.description}`,
										 properties  : { title      : brew.title,
										 							    published  : brew.published,
																	    lastViewed : brew.lastViewed,
																	    views      : brew.views,
																	    version    : brew.version,
																	    renderer   : brew.renderer,
																	    tags       : brew.tags,
																	    systems    : brew.systems.join(),
																	    pageCount  : (brew.text.match(/\\page/g) || []).length + 1
																 }
									 },
				media : { mimeType : 'text/plain',
								  body     : brew.text }
			})
			.catch((err)=>{
				console.log('Error saving to google');
				console.error(err);
				throw (err);
				//return res.status(500).send('Error while saving');
			});
		}

		return (brew);
	},

	newGoogleBrew : async (auth, brew)=>{
		const drive = google.drive({ version: 'v3', auth: auth });

		const media = {
			mimeType : 'text/plain',
			body     : brew.text
		};

		const folderId = await GoogleActions.getGoogleFolder(auth);

		const fileMetadata = {
			'name'        : `${brew.title}.txt`,
			'description' : `${brew.description}`,
			'parents'     : [folderId],
			'properties'  : {								//AppProperties is not accessible
				'shareId'   : nanoid(12),
				'editId'    : nanoid(12),
				'title'     : brew.title,
				'views'     : '0',
				'pageCount' : (brew.text.match(/\\page/g) || []).length + 1,
				'renderer'  : brew.renderer || 'legacy'
			}
		};

		const obj = await drive.files.create({
			resource : fileMetadata,
			media    : media
		})
		.catch((err)=>{
			console.log('Error while creating new Google brew');
			console.error(err);
			throw (err);
		});

		if(!obj) return;

		await drive.permissions.create({
			resource : { type : 'anyone',
									 role : 'writer' },
			fileId : obj.data.id,
			fields : 'id',
		})
		.catch((err)=>{
			console.log('Error updating permissions');
			console.error(err);
		});

		const newHomebrew = {
			text      : brew.text,
			shareId   : fileMetadata.properties.shareId,
			editId    : fileMetadata.properties.editId,
			createdAt : new Date(),
			updatedAt : new Date(),
			gDrive    : true,
			googleId  : obj.data.id,
			pageCount : fileMetadata.properties.pageCount || 1,

			title       : brew.title,
			description : brew.description,
			tags        : '',
			published   : brew.published,
			renderer    : brew.renderer,
			authors     : [],
			systems     : []
		};

		return newHomebrew;
	},

	readFileMetadata : async (auth, id, accessId, accessType)=>{

		const drive = google.drive({ version: 'v3', auth: auth });

		const obj = await drive.files.get({
			fileId : id,
			fields : 'properties, createdTime, modifiedTime, description, trashed'
		})
		.catch((err)=>{
			console.log('Error loading from Google');
			throw (err);
			return;
		});

		if(obj) {
			if(accessType == 'edit' && obj.data.properties.editId != accessId){
				throw ('Edit ID does not match');
			} else if(accessType == 'share' && obj.data.properties.shareId != accessId){
				throw ('Share ID does not match');
			}

			//Access file using service account. Using API key only causes "automated query" lockouts after a while.

			const keys = typeof(config.get('service_account')) == 'string' ?
				JSON.parse(config.get('service_account')) :
				config.get('service_account');

			const serviceAuth = google.auth.fromJSON(keys);
			serviceAuth.scopes = ['https://www.googleapis.com/auth/drive'];

			const serviceDrive = google.drive({ version: 'v3', auth: serviceAuth });

			const file = await serviceDrive.files.get({
				fileId : id,
				fields : 'description, properties',
				alt    : 'media'
			})
			.catch((err)=>{
				console.log('Error getting file contents from Google');
				console.error(err);
			});

			const brew = {
				shareId : obj.data.properties.shareId,
				editId  : obj.data.properties.editId,
				title   : obj.data.properties.title,
				text    : file.data,

				description : obj.data.description,
				tags        : obj.data.properties.tags    ? obj.data.properties.tags               : '',
				systems     : obj.data.properties.systems ? obj.data.properties.systems.split(',') : [],
				authors     : [],
				published   : obj.data.properties.published ? obj.data.properties.published == 'true' : false,
				trashed     : obj.data.trashed,

				createdAt  : obj.data.createdTime,
				updatedAt  : obj.data.modifiedTime,
				lastViewed : obj.data.properties.lastViewed,
				pageCount : obj.data.properties.pageCount,
				views      : parseInt(obj.data.properties.views) || 0, //brews with no view parameter will return undefined
				version    : parseInt(obj.data.properties.version) || 0,
				renderer   : obj.data.properties.renderer ? obj.data.properties.renderer : 'legacy',

				gDrive   : true,
				googleId : id
			};

			return (brew);
		}
	},

	deleteGoogleBrew : async (req, res, id)=>{

		oAuth2Client = GoogleActions.authCheck(req.account, res);
		const drive = google.drive({ version: 'v3', auth: oAuth2Client });

		const googleId = id.slice(0, -12);
		const accessId = id.slice(-12);

		const obj = await drive.files.get({
			fileId : googleId,
			fields : 'properties'
		})
		.catch((err)=>{
			console.log('Error loading from Google');
			console.error(err);
			return;
		});

		if(obj && obj.data.properties.editId != accessId) {
			throw ('Not authorized to delete this Google brew');
		}

		await drive.files.update({
			fileId   : googleId,
			resource : { trashed: true }
		})
		.catch((err)=>{
			console.log('Can\'t delete Google file');
			console.error(err);
		});

		return res.status(200).send();
	},

	increaseView : async (id, accessId, accessType, brew)=>{
		//service account because this is modifying another user's file properties
		//so we need extended scope
		const keys = typeof(config.get('service_account')) == 'string' ?
			JSON.parse(config.get('service_account')) :
			config.get('service_account');

		const auth = google.auth.fromJSON(keys);
		auth.scopes = ['https://www.googleapis.com/auth/drive'];

		const drive = google.drive({ version: 'v3', auth: auth });

		await drive.files.update({
			fileId   : brew.googleId,
			resource : { properties : { views      : brew.views + 1,
		 															lastViewed : new Date() } }
		})
		.catch((err)=>{
			console.log('Error updating Google views');
			console.error(err);
			//return res.status(500).send('Error while saving');
		});

		return;
	}
};

module.exports = GoogleActions;
<commit_msg>Lint fix.<commit_after>/* eslint-disable max-lines */
const _ = require('lodash');
const { google } = require('googleapis');
const { nanoid } = require('nanoid');
const token = require('./token.js');
const config = require('nconf')
	.argv()
	.env({ lowerCase: true })	// Load environment variables
	.file('environment', { file: `config/${process.env.NODE_ENV}.json` })
	.file('defaults', { file: 'config/default.json' });

//let oAuth2Client;

GoogleActions = {

	authCheck : (account, res)=>{
		if(!account || !account.googleId){ // If not signed into Google
			const err = new Error('Not Signed In');
			err.status = 401;
			throw err;
		}

		const oAuth2Client = new google.auth.OAuth2(
			config.get('google_client_id'),
			config.get('google_client_secret'),
			'/auth/google/redirect'
		);

		oAuth2Client.setCredentials({
			access_token  : account.googleAccessToken, //Comment out to refresh token
			refresh_token : account.googleRefreshToken
		});

		oAuth2Client.on('tokens', (tokens)=>{
			if(tokens.refresh_token) {
				account.googleRefreshToken = tokens.refresh_token;
			}
			account.googleAccessToken = tokens.access_token;
			const JWTToken = token.generateAccessToken(account);

			//Save updated token to cookie
			//res.cookie('nc_session', JWTToken, { maxAge: 1000*60*60*24*365, path: '/', sameSite: 'lax' });
			res.cookie('nc_session', JWTToken, { maxAge: 1000*60*60*24*365, path: '/', sameSite: 'lax', domain: '.naturalcrit.com' });
		});

		return oAuth2Client;
	},

	getGoogleFolder : async (auth)=>{
		const drive = google.drive({ version: 'v3', auth: auth });

		fileMetadata = {
			'name'     : 'Homebrewery',
			'mimeType' : 'application/vnd.google-apps.folder'
		};

		const obj = await drive.files.list({
			q : 'mimeType = \'application/vnd.google-apps.folder\''
		})
		.catch((err)=>{
			console.log('Error searching Google Drive Folders');
			console.error(err);
		});

		let folderId;

		if(obj.data.files.length == 0){
			const obj = await drive.files.create({
				resource : fileMetadata
			})
			.catch((err)=>{
				console.log('Error creating google app folder');
				console.error(err);
			});

			folderId = obj.data.id;
		} else {
			folderId = obj.data.files[0].id;
		}

		return folderId;
	},

	listGoogleBrews : async (req, res)=>{

		oAuth2Client = GoogleActions.authCheck(req.account, res);

		//TODO: Change to service account to allow non-owners to view published files.
		// Requires a driveId parameter in the drive.files.list command
		// const keys = JSON.parse(config.get('service_account'));
		// const auth = google.auth.fromJSON(keys);
		// auth.scopes = ['https://www.googleapis.com/auth/drive'];

		const drive = google.drive({ version: 'v3', auth: oAuth2Client });

		const obj = await drive.files.list({
			pageSize : 100,
			fields   : 'nextPageToken, files(id, name, description, createdTime, modifiedTime, properties)',
			q        : 'mimeType != \'application/vnd.google-apps.folder\' and trashed = false'
		})
		.catch((err)=>{
	    return console.error(`Error Listing Google Brews: ${err}`);
			//TODO: Should break out here, but continues on for some reason.
	  });

		if(!obj.data.files.length) {
	    console.log('No files found.');
	  }

		const brews = obj.data.files.map((file)=>{
	    return {
	      text      : '',
	      shareId   : file.properties.shareId,
	      editId    : file.properties.editId,
	      createdAt : file.createdTime,
	      updatedAt : file.modifiedTime,
	      gDrive    : true,
	      googleId  : file.id,
		  pageCount : file.properties.pageCount,

	      title       : file.properties.title,
	      description : file.description,
		  views       : file.properties.views,
	      tags        : '',
	      published   : file.properties.published ? file.properties.published == 'true' : false,
	      authors     : [req.account.username],	//TODO: properly save and load authors to google drive
	      systems     : []
	    };
	  });

	  return brews;
	},

	existsGoogleBrew : async (auth, id)=>{
		const drive = google.drive({ version: 'v3', auth: auth });

		const result = await drive.files.get({ fileId: id })
		.catch((err)=>{
			console.log('error checking file exists...');
			console.log(err);
			return false;
		});

		if(result){return true;}

		return false;
	},

	updateGoogleBrew : async (auth, brew)=>{
		const drive = google.drive({ version: 'v3', auth: auth });

		if(await GoogleActions.existsGoogleBrew(auth, brew.googleId) == true) {
			await drive.files.update({
				fileId   : brew.googleId,
				resource : { name        : `${brew.title}.txt`,
										 description : `${brew.description}`,
										 properties  : { title      : brew.title,
										 							    published  : brew.published,
																	    lastViewed : brew.lastViewed,
																	    views      : brew.views,
																	    version    : brew.version,
																	    renderer   : brew.renderer,
																	    tags       : brew.tags,
																	    systems    : brew.systems.join(),
																	    pageCount  : (brew.text.match(/\\page/g) || []).length + 1
																 }
									 },
				media : { mimeType : 'text/plain',
								  body     : brew.text }
			})
			.catch((err)=>{
				console.log('Error saving to google');
				console.error(err);
				throw (err);
				//return res.status(500).send('Error while saving');
			});
		}

		return (brew);
	},

	newGoogleBrew : async (auth, brew)=>{
		const drive = google.drive({ version: 'v3', auth: auth });

		const media = {
			mimeType : 'text/plain',
			body     : brew.text
		};

		const folderId = await GoogleActions.getGoogleFolder(auth);

		const fileMetadata = {
			'name'        : `${brew.title}.txt`,
			'description' : `${brew.description}`,
			'parents'     : [folderId],
			'properties'  : {								//AppProperties is not accessible
				'shareId'   : nanoid(12),
				'editId'    : nanoid(12),
				'title'     : brew.title,
				'views'     : '0',
				'pageCount' : (brew.text.match(/\\page/g) || []).length + 1,
				'renderer'  : brew.renderer || 'legacy'
			}
		};

		const obj = await drive.files.create({
			resource : fileMetadata,
			media    : media
		})
		.catch((err)=>{
			console.log('Error while creating new Google brew');
			console.error(err);
			throw (err);
		});

		if(!obj) return;

		await drive.permissions.create({
			resource : { type : 'anyone',
									 role : 'writer' },
			fileId : obj.data.id,
			fields : 'id',
		})
		.catch((err)=>{
			console.log('Error updating permissions');
			console.error(err);
		});

		const newHomebrew = {
			text      : brew.text,
			shareId   : fileMetadata.properties.shareId,
			editId    : fileMetadata.properties.editId,
			createdAt : new Date(),
			updatedAt : new Date(),
			gDrive    : true,
			googleId  : obj.data.id,
			pageCount : fileMetadata.properties.pageCount || 1,

			title       : brew.title,
			description : brew.description,
			tags        : '',
			published   : brew.published,
			renderer    : brew.renderer,
			authors     : [],
			systems     : []
		};

		return newHomebrew;
	},

	readFileMetadata : async (auth, id, accessId, accessType)=>{

		const drive = google.drive({ version: 'v3', auth: auth });

		const obj = await drive.files.get({
			fileId : id,
			fields : 'properties, createdTime, modifiedTime, description, trashed'
		})
		.catch((err)=>{
			console.log('Error loading from Google');
			throw (err);
			return;
		});

		if(obj) {
			if(accessType == 'edit' && obj.data.properties.editId != accessId){
				throw ('Edit ID does not match');
			} else if(accessType == 'share' && obj.data.properties.shareId != accessId){
				throw ('Share ID does not match');
			}

			//Access file using service account. Using API key only causes "automated query" lockouts after a while.

			const keys = typeof(config.get('service_account')) == 'string' ?
				JSON.parse(config.get('service_account')) :
				config.get('service_account');

			const serviceAuth = google.auth.fromJSON(keys);
			serviceAuth.scopes = ['https://www.googleapis.com/auth/drive'];

			const serviceDrive = google.drive({ version: 'v3', auth: serviceAuth });

			const file = await serviceDrive.files.get({
				fileId : id,
				fields : 'description, properties',
				alt    : 'media'
			})
			.catch((err)=>{
				console.log('Error getting file contents from Google');
				console.error(err);
			});

			const brew = {
				shareId : obj.data.properties.shareId,
				editId  : obj.data.properties.editId,
				title   : obj.data.properties.title,
				text    : file.data,

				description : obj.data.description,
				tags        : obj.data.properties.tags    ? obj.data.properties.tags               : '',
				systems     : obj.data.properties.systems ? obj.data.properties.systems.split(',') : [],
				authors     : [],
				published   : obj.data.properties.published ? obj.data.properties.published == 'true' : false,
				trashed     : obj.data.trashed,

				createdAt  : obj.data.createdTime,
				updatedAt  : obj.data.modifiedTime,
				lastViewed : obj.data.properties.lastViewed,
				pageCount  : obj.data.properties.pageCount,
				views      : parseInt(obj.data.properties.views) || 0, //brews with no view parameter will return undefined
				version    : parseInt(obj.data.properties.version) || 0,
				renderer   : obj.data.properties.renderer ? obj.data.properties.renderer : 'legacy',

				gDrive   : true,
				googleId : id
			};

			return (brew);
		}
	},

	deleteGoogleBrew : async (req, res, id)=>{

		oAuth2Client = GoogleActions.authCheck(req.account, res);
		const drive = google.drive({ version: 'v3', auth: oAuth2Client });

		const googleId = id.slice(0, -12);
		const accessId = id.slice(-12);

		const obj = await drive.files.get({
			fileId : googleId,
			fields : 'properties'
		})
		.catch((err)=>{
			console.log('Error loading from Google');
			console.error(err);
			return;
		});

		if(obj && obj.data.properties.editId != accessId) {
			throw ('Not authorized to delete this Google brew');
		}

		await drive.files.update({
			fileId   : googleId,
			resource : { trashed: true }
		})
		.catch((err)=>{
			console.log('Can\'t delete Google file');
			console.error(err);
		});

		return res.status(200).send();
	},

	increaseView : async (id, accessId, accessType, brew)=>{
		//service account because this is modifying another user's file properties
		//so we need extended scope
		const keys = typeof(config.get('service_account')) == 'string' ?
			JSON.parse(config.get('service_account')) :
			config.get('service_account');

		const auth = google.auth.fromJSON(keys);
		auth.scopes = ['https://www.googleapis.com/auth/drive'];

		const drive = google.drive({ version: 'v3', auth: auth });

		await drive.files.update({
			fileId   : brew.googleId,
			resource : { properties : { views      : brew.views + 1,
		 															lastViewed : new Date() } }
		})
		.catch((err)=>{
			console.log('Error updating Google views');
			console.error(err);
			//return res.status(500).send('Error while saving');
		});

		return;
	}
};

module.exports = GoogleActions;
<|endoftext|>


<commit_before>import {unauthorized} from 'boom'
import Logger from '@modulus/logger'

import Config from '../../config'

let logger = Logger('handlers/auth')

function validate(token, callback) {
  if (token === Config.authToken) {
    logger.info(`Request validated with token ${token}`)
    callback(null, true, { token: token })
  } else {
    logger.error(`Request not validated with token ${token}`)
    callback(unauthorized('Invalid token'), false, { token: token })
  }
}

export default {
  validate: validate
}
<commit_msg>Add request path to logging<commit_after>import {unauthorized} from 'boom'
import Logger from '@modulus/logger'

import Config from '../../config'

let logger = Logger('handlers/auth')

function validate(token, callback) {
  let request = this

  if (token === Config.authToken) {
    logger.info(`Request to ${request.path} validated with token ${token}`)
    callback(null, true, { token: token })
  } else {
    logger.error(`Request to ${request.path} not validated with token ${token}`)
    callback(unauthorized('Invalid token'), false, { token: token })
  }
}

export default {
  validate: validate
}
<|endoftext|>


<commit_before>const handleHttpError = (res, error, status) => {
    return res.status(status).json({
      success: false, message: 'Server error: ' + error
    })
}

module.exports = handleHttpError
<commit_msg>Changed server error handler message<commit_after>const handleHttpError = (res, error, status) => {
    return res.status(status).json({
      success: false, message: 'Error: ' + error
    })
}

module.exports = handleHttpError
<|endoftext|>