<commit_before>var participantService = require('../../modules/activity/services/ParticipantService');
var activityService = require('../../modules/activity/services/ActivityService');
var util = require('../../app/util');
var _ = require('underscore');

module.exports = function (router) {
    router.post('/add', function *() {
        var id = this.request.body.id;
        var activity = yield activityService.loadById(id);
        if (activity) {
            var json = {
                activity: id
                , user: this.session.user.id
                , phone: this.request.body.phone
                , total_money: activity.base_lucky_money
                , help_friends: []
            }
            var data = yield participantService.create(json);
            this.body = data;
        } else {
            this.body = {error: 'no such activity'};
        }
    });

    router.post('/help', function *() {
        var id = this.request.body.id;
        var user = this.session.user || {};
        if(!user.wx_openid){
            var today = new Date();
            var participant = yield participantService.loadById(id);
            if (participant) {
                var active = today >= new Date(participant.activity.startTime) && today <= new Date(participant.activity.endTime);
                if(active) {
                    var helpArr = participant.help_friends;
                    if (_.indexOf(helpArr, user.wx_openid) === -1) {
                        if (helpArr.length < participant.activity.friend_help_count_limit) {
                            helpArr.push(user.wx_openid);
                            var min = participant.activity.friend_help_min_money || 0;
                            var max = participant.activity.friend_help_max_money || 0;
                            var helpMoney = util.random(min, max);
                            var total_money = participant.total_money + helpMoney;
                            var update = {
                                total_money: total_money,
                                help_friends: helpArr
                            }
                            var data = yield participantService.updateById(participant._id, update);
                            this.body = data;
                        } else {
                            this.body = {limited: true};
                        }
                    } else {
                        this.body = {helped: true};
                    }
                }else{
                    this.body = {invalid: true};
                }
            } else {
                this.body = {error: 'no such participant'};
            }
        }else {
            this.body = {error: 'please open in wechat browser'};
        }
    });
}<commit_msg>update<commit_after>var participantService = require('../../modules/activity/services/ParticipantService');
var activityService = require('../../modules/activity/services/ActivityService');
var util = require('../../app/util');
var _ = require('underscore');

module.exports = function (router) {
    router.post('/add', function *() {
        var id = this.request.body.id;
        var activity = yield activityService.loadById(id);
        if (activity) {
            var json = {
                activity: id
                , user: this.session.user.id
                , phone: this.request.body.phone
                , total_money: activity.base_lucky_money
                , help_friends: []
            }
            var data = yield participantService.create(json);
            this.body = data;
        } else {
            this.body = {error: 'no such activity'};
        }
    });

    router.post('/help', function *() {
        var id = this.request.body.id;
        var user = this.session.user || {};
        console.log('!!!!!!!!!!!!!!!!!!!!');
        console.error(id);
        console.error(user);
        if(!user.wx_openid){
            var today = new Date();
            var participant = yield participantService.loadById(id);
            if (participant) {
                var active = today >= new Date(participant.activity.startTime) && today <= new Date(participant.activity.endTime);
                if(active) {
                    var helpArr = participant.help_friends;
                    if (_.indexOf(helpArr, user.wx_openid) === -1) {
                        if (helpArr.length < participant.activity.friend_help_count_limit) {
                            helpArr.push(user.wx_openid);
                            var min = participant.activity.friend_help_min_money || 0;
                            var max = participant.activity.friend_help_max_money || 0;
                            var helpMoney = util.random(min, max);
                            var total_money = participant.total_money + helpMoney;
                            var update = {
                                total_money: total_money,
                                help_friends: helpArr
                            }
                            var data = yield participantService.updateById(participant._id, update);
                            this.body = data;
                        } else {
                            this.body = {limited: true};
                        }
                    } else {
                        this.body = {helped: true};
                    }
                }else{
                    this.body = {invalid: true};
                }
            } else {
                this.body = {error: 'no such participant'};
            }
        }else {
            this.body = {error: 'please open in wechat browser'};
        }
    });
}<|endoftext|>


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

import { connect } from 'react-redux';
import { compose, lifecycle } from 'recompose';
import { withRouter } from 'react-router-dom';
import { Button, Menu, Icon, Header, Divider, Grid, Popup } from 'semantic-ui-react';
import Mousetrap from 'mousetrap';

import { actionCreators as recentItemsActionCreators } from 'prototypes/RecentItems/redux';
import { actionCreators as appSearchActionCreators } from 'prototypes/AppSearch/redux';
import RecentItems from 'prototypes/RecentItems';
import AppSearch from 'prototypes/AppSearch';
import withLocalStorage from 'lib/withLocalStorage';

const { recentItemsOpened } = recentItemsActionCreators;
const { appSearchOpened } = appSearchActionCreators;
const withIsExpanded = withLocalStorage('isExpanded', 'setIsExpanded', true);

const SIDE_BAR_COLOUR = 'blue';

const enhance = compose(
  connect((state, props) => ({}), {
    recentItemsOpened,
    appSearchOpened,
  }),
  withRouter,
  withIsExpanded,
  lifecycle({
    componentDidMount() {
      Mousetrap.bind('ctrl+e', () => this.props.recentItemsOpened());
      Mousetrap.bind('ctrl+f', () => this.props.appSearchOpened());
    },
  }),
);

const pathPrefix = '/s';

const sidebarMenuItems = [
  {
    title: 'Welcome',
    path: `${pathPrefix}/welcome/`,
    icon: 'home',
  },
  {
    title: 'Explorer',
    path: `${pathPrefix}/docExplorer`,
    icon: 'eye',
  },
  {
    title: 'Pipelines',
    path: `${pathPrefix}/pipelines`,
    icon: 'tasks',
  },
  {
    title: 'Processing',
    path: `${pathPrefix}/trackers`, // TODO change this to processing -- needs changing in the stroom iFrame too.
    icon: 'play',
  },
  {
    title: 'Me',
    path: `${pathPrefix}/me`,
    icon: 'user',
  },
  {
    title: 'Users',
    path: `${pathPrefix}/users`,
    icon: 'users',
  },
  {
    title: 'API Keys',
    path: `${pathPrefix}/apikeys`,
    icon: 'key',
  },
];

const AppChrome = ({
  title,
  icon,
  recentItemsOpened,
  appSearchOpened,
  isExpanded,
  setIsExpanded,
  history,
  children,
}) => {
  const menuItems = [
    {
      title: 'Stroom',
      icon: 'bars',
      onClick: () => setIsExpanded(!isExpanded),
    },
  ].concat(sidebarMenuItems.map(sidebarMenuItem => ({
    title: sidebarMenuItem.title,
    icon: sidebarMenuItem.icon,
    onClick: () => history.push(sidebarMenuItem.path),
  })));

  const menu = isExpanded ? (
    <Menu vertical fluid color={SIDE_BAR_COLOUR} inverted>
      {menuItems.map(menuItem => (
        <Menu.Item
          key={menuItem.title}
          active={menuItem.selected}
          name={menuItem.title}
          onClick={menuItem.onClick}
        >
          <Icon name={menuItem.icon} />
          {menuItem.title}
        </Menu.Item>
      ))}
    </Menu>
  ) : (
    <Button.Group vertical color={SIDE_BAR_COLOUR} size="large">
      {menuItems.map(menuItem => (
        <Button
          key={menuItem.title}
          active={menuItem.selected}
          icon={menuItem.icon}
          onClick={menuItem.onClick}
        />
      ))}
    </Button.Group>
  );

  return (

      <AppSearch />

{menu}

            <Grid>
              <Grid.Column width={12}>

                  <Icon name={icon} color="grey" />
                  {title}

              </Grid.Column>
              <Grid.Column width={4}>
                <Popup
                  trigger={
                    <Button
                      floated="right"
                      circular
                      icon="file outline"
                      onClick={() => recentItemsOpened()}
                    />
                  }
                  content="Recently opened items"
                />
                <Popup
                  trigger={
                    <Button
                      floated="right"
                      circular
                      icon="search"
                      onClick={() => appSearchOpened()}
                    />
                  }
                  content="Search for things"
                />
              </Grid.Column>
            </Grid>
            <Divider />
            {children}

  );
};

AppChrome.contextTypes = {
  store: PropTypes.object,
  router: PropTypes.shape({
    history: object.isRequired,
  }),
};

AppChrome.propTypes = {};

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

import { connect } from 'react-redux';
import { compose, lifecycle } from 'recompose';
import { withRouter } from 'react-router-dom';
import { Button, Menu, Icon, Header, Divider, Grid, Popup } from 'semantic-ui-react';
import Mousetrap from 'mousetrap';

import { actionCreators as recentItemsActionCreators } from 'prototypes/RecentItems/redux';
import { actionCreators as appSearchActionCreators } from 'prototypes/AppSearch/redux';
import RecentItems from 'prototypes/RecentItems';
import AppSearch from 'prototypes/AppSearch';
import withLocalStorage from 'lib/withLocalStorage';

const { recentItemsOpened } = recentItemsActionCreators;
const { appSearchOpened } = appSearchActionCreators;
const withIsExpanded = withLocalStorage('isExpanded', 'setIsExpanded', true);

const SIDE_BAR_COLOUR = 'blue';

const enhance = compose(
  connect((state, props) => ({}), {
    recentItemsOpened,
    appSearchOpened,
  }),
  withRouter,
  withIsExpanded,
  lifecycle({
    componentDidMount() {
      Mousetrap.bind('ctrl+e', () => this.props.recentItemsOpened());
      Mousetrap.bind('ctrl+f', () => this.props.appSearchOpened());
    },
  }),
);

const pathPrefix = '/s';

const sidebarMenuItems = [
  {
    title: 'Welcome',
    path: `${pathPrefix}/welcome/`,
    icon: 'home',
  },
  {
    title: 'Explorer',
    path: `${pathPrefix}/docExplorer`,
    icon: 'eye',
  },
  {
    title: 'Pipelines',
    path: `${pathPrefix}/pipelines`,
    icon: 'tasks',
  },
  {
    title: 'Processing',
    path: `${pathPrefix}/trackers`, // TODO change this to processing -- needs changing in the stroom iFrame too.
    icon: 'play',
  },
  {
    title: 'Me',
    path: `${pathPrefix}/me`,
    icon: 'user',
  },
  {
    title: 'Users',
    path: `${pathPrefix}/users`,
    icon: 'users',
  },
  {
    title: 'API Keys',
    path: `${pathPrefix}/apikeys`,
    icon: 'key',
  },
];

const AppChrome = ({
  title,
  icon,
  recentItemsOpened,
  appSearchOpened,
  isExpanded,
  setIsExpanded,
  history,
  children,
}) => {
  const menuItems = [
    {
      title: 'Stroom',
      icon: 'bars',
      onClick: () => setIsExpanded(!isExpanded),
    },
  ].concat(sidebarMenuItems.map(sidebarMenuItem => ({
    title: sidebarMenuItem.title,
    icon: sidebarMenuItem.icon,
    onClick: () => history.push(sidebarMenuItem.path),
  })));

  const menu = isExpanded ? (
    <Menu vertical fluid color={SIDE_BAR_COLOUR} inverted>
      {menuItems.map(menuItem => (
        <Menu.Item
          key={menuItem.title}
          active={menuItem.title === title}
          name={menuItem.title}
          onClick={menuItem.onClick}
        >
          <Icon name={menuItem.icon} />
          {menuItem.title}
        </Menu.Item>
      ))}
    </Menu>
  ) : (
    <Button.Group vertical color={SIDE_BAR_COLOUR} size="large">
      {menuItems.map(menuItem => (
        <Button
          key={menuItem.title}
          active={menuItem.title === title}
          icon={menuItem.icon}
          onClick={menuItem.onClick}
        />
      ))}
    </Button.Group>
  );

  return (

      <AppSearch />

{menu}

            <Grid>
              <Grid.Column width={12}>

                  <Icon name={icon} color="grey" />
                  {title}

              </Grid.Column>
              <Grid.Column width={4}>
                <Popup
                  trigger={
                    <Button
                      floated="right"
                      circular
                      icon="file outline"
                      onClick={() => recentItemsOpened()}
                    />
                  }
                  content="Recently opened items"
                />
                <Popup
                  trigger={
                    <Button
                      floated="right"
                      circular
                      icon="search"
                      onClick={() => appSearchOpened()}
                    />
                  }
                  content="Search for things"
                />
              </Grid.Column>
            </Grid>
            <Divider />
            {children}

  );
};

AppChrome.contextTypes = {
  store: PropTypes.object,
  router: PropTypes.shape({
    history: object.isRequired,
  }),
};

AppChrome.propTypes = {};

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


<commit_before>/***
|''Name''|TiddlySpaceToolbar|
|''Description''|Updates the toolbar macro to use svg buttons and a popup for the more menu|
***/
//{{{
(function($){
	config.macros.toolbar._TSoldHandler = config.macros.toolbar.handler;
	config.macros.toolbar.handler = function(place,macroName,params,wikifier,paramString,tiddler)
	{

		this._TSoldHandler(place,macroName,params,wikifier,paramString,tiddler);

		if(config.macros.image){ //only do this for people who have this macro available!
			var cancelTiddlerButton =jQuery(".command_cancelTiddler",place);
			cancelTiddlerButton.empty();
			wikify("<<image cancelTiddler.svg>>",cancelTiddlerButton[0]);

			var closeTiddlerButton =jQuery(".command_closeTiddler",place);
			closeTiddlerButton.empty();
			wikify("<<image closeTiddler.svg>>",closeTiddlerButton[0]);

			var editTiddlerButton = jQuery(".command_editTiddler",place);
			editTiddlerButton.empty();
			wikify("<<image editTiddler.svg>>",editTiddlerButton[0]);

			var deleteTiddlerButton =jQuery(".command_deleteTiddler",place);
			deleteTiddlerButton.empty();
			wikify("<<image deleteTiddler.svg>>",deleteTiddlerButton[0]);

			var saveTiddlerButton =jQuery(".command_saveTiddler",place);
			saveTiddlerButton.empty();
			wikify("<<image saveTiddler.svg>>",saveTiddlerButton[0]);

			var moreTiddlerButton = jQuery("a.moreCommand",place);
			moreTiddlerButton.empty();
			wikify("<<image moreCommand.svg>>",moreTiddlerButton[0]);
		}
	}

	config.macros.toolbar.onClickMore = function(ev)
	{
		var sibling = this.nextSibling;
		var commands = sibling.childNodes;
		var popup = Popup.create(this);
		addClass(popup,"taggedTiddlerList");

		for(var i=0; i < commands.length; i++){
			var li =createTiddlyElement(popup,"li",null);
			var oldCommand =commands[i];
			var command = oldCommand.cloneNode(true);
			command.onclick = oldCommand.onclick;
			li.appendChild(command);
		}
		Popup.show();

		var e = ev || window.event;
		e.cancelBubble = true;
		if(e.stopPropagation) e.stopPropagation();
	}

	var shadows = config.shadowTiddlers;
	shadows.ToolbarCommands = "|~ViewToolbar|+editTiddler closeTiddler > cloneTiddler pubRev closeOthers fields publishTiddlerRevision revisions syncing permalink references jump|"+
	"\n|~EditToolbar|+saveTiddler -cancelTiddler deleteTiddler|";

})(jQuery);
//}}}
<commit_msg>Don't provide images for toolbar if ie not available A fall back for the time being to ensure toolbar buttons are not disabled for ie users.<commit_after>/***
|''Name''|TiddlySpaceToolbar|
|''Description''|Updates the toolbar macro to use svg buttons and a popup for the more menu|
***/
//{{{
(function($){
	config.macros.toolbar._TSoldHandler = config.macros.toolbar.handler;
	config.macros.toolbar.handler = function(place,macroName,params,wikifier,paramString,tiddler)
	{

		this._TSoldHandler(place,macroName,params,wikifier,paramString,tiddler);

		if(config.macros.image && config.macros.image.svgAvailable){ //only do this for people who have this macro available!
			var cancelTiddlerButton =jQuery(".command_cancelTiddler",place);
			cancelTiddlerButton.empty();
			wikify("<<image cancelTiddler.svg>>",cancelTiddlerButton[0]);

			var closeTiddlerButton =jQuery(".command_closeTiddler",place);
			closeTiddlerButton.empty();
			wikify("<<image closeTiddler.svg>>",closeTiddlerButton[0]);

			var editTiddlerButton = jQuery(".command_editTiddler",place);
			editTiddlerButton.empty();
			wikify("<<image editTiddler.svg>>",editTiddlerButton[0]);

			var deleteTiddlerButton =jQuery(".command_deleteTiddler",place);
			deleteTiddlerButton.empty();
			wikify("<<image deleteTiddler.svg>>",deleteTiddlerButton[0]);

			var saveTiddlerButton =jQuery(".command_saveTiddler",place);
			saveTiddlerButton.empty();
			wikify("<<image saveTiddler.svg>>",saveTiddlerButton[0]);

			var moreTiddlerButton = jQuery("a.moreCommand",place);
			moreTiddlerButton.empty();
			wikify("<<image moreCommand.svg>>",moreTiddlerButton[0]);
		}
	}

	config.macros.toolbar.onClickMore = function(ev)
	{
		var sibling = this.nextSibling;
		var commands = sibling.childNodes;
		var popup = Popup.create(this);
		addClass(popup,"taggedTiddlerList");

		for(var i=0; i < commands.length; i++){
			var li =createTiddlyElement(popup,"li",null);
			var oldCommand =commands[i];
			var command = oldCommand.cloneNode(true);
			command.onclick = oldCommand.onclick;
			li.appendChild(command);
		}
		Popup.show();

		var e = ev || window.event;
		e.cancelBubble = true;
		if(e.stopPropagation) e.stopPropagation();
	}

	var shadows = config.shadowTiddlers;
	shadows.ToolbarCommands = "|~ViewToolbar|+editTiddler closeTiddler > cloneTiddler pubRev closeOthers fields publishTiddlerRevision revisions syncing permalink references jump|"+
	"\n|~EditToolbar|+saveTiddler -cancelTiddler deleteTiddler|";

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


<commit_before>function Croaker(env) {
  var deps = env || {},
    $ = deps.jQuery || jQuery,
    mywindow = deps.window || window;

  function FatalException(message) {
    return {
      name: 'FatalException',
      message: message
    };
  }

  function NodeEntry(name, attributes, children) {
    return  {
      name: name,
      attributes: attributes,
      children: children
    };
  }

  function Parser() {
    var that = {};

    function parseAttributes(node) {
      var attributes = {}, x;

      if (node.hasAttributes()) {
        for (x = 0; x < node.attributes.length; x++) {
          attributes[node.attributes.item(x).name] = node.attributes.item(x).value;
        }
      }
      return attributes;
    }

    function parseChildNodes(processor, node) {
      var children = [], x;

      if (node.hasChildNodes()) {
        for (x = 0; x < node.childNodes.length; x++) {
          children.push(processor(node.childNodes.item(x)));
        }
      }
      return children;
    }

    function processNode(node) {
      return new NodeEntry(node.nodeName, parseAttributes(node), parseChildNodes(processNode, node));
    }

    function validateDoc(doc) {
      if(doc.documentElement.innerHTML) {
        throw new FatalException('unable to parse xml');
      }

      if (doc.documentElement.nodeName === 'parsererror') {
        throw new FatalException('unable to parse xml');
      }

    }

    function parse(string) {
      var domparser = new DOMParser(),
        xmlDoc = domparser.parseFromString(string, "text/xml");
      validateDoc(xmlDoc);
      return processNode(xmlDoc.documentElement);
    }

    that.parse = parse;
    return that;
  }

  function Metric(name, value) {
    return {
      name:name,
      value:value
    };
  }

  function Member(name, file, line, metrics) {
    return {
      name:name,
      file:file,
      line:line,
      metrics:metrics
    };
  }

  function Type (name,members,metrics) {
    return {
       name:name,
       members:members,
       metrics:metrics
    };
  }

  function Namespace(name, types, metrics) {
    return {
      name:name,
      types:types,
      metrics:metrics
    };
  }

  function Module(name, version, metrics, namespaces) {
    return {
      name:name,
      version: version,
      metrics: metrics,
      namespaces: namespaces
    };
  }

  function Mapper() {
    var that = {};

    function formMetrics(startingNode, index) {
      var x, metrics = [], metricsNode = startingNode.children[index];

      for (x=0; x < metricsNode.children.length; x++) {
        metrics.push(
          new Metric(metricsNode.children[x].attributes.Name,
          parseInt(metricsNode.children[x].attributes.Value, 10))
        );
      }

      return metrics;
    }

    function formMembers(startingNode) {
      var members = [], x;

      for (x=0; x < startingNode.children.length; x++) {
        members.push(
          new Member (startingNode.children[x].attributes.Name,
          startingNode.children[x].attributes.File,
          startingNode.children[x].attributes.Line,
          formMetrics(startingNode.children[0],0))
        );
      }

      return members;
    }

    function formTypes(startingNode) {
      if(startingNode.children.length < 1) {
        return;
      }

      var types = [], x, membersNode;

      for (x=0; x < startingNode.children.length; x++) {
        membersNode = startingNode.children[x].children[1];

        types.push(
          new Type (startingNode.children[x].attributes.Name,
          formMembers(membersNode),
          formMetrics(startingNode.children[0],0))
        );
      }

      return types;
    }

    function formNamespaces(startingNode) {
      if(startingNode.children.length < 1) {
        return;
      }

      var typesNode, namespaces = [], x;

      for (x=0; x < startingNode.children.length; x++) {
        typesNode = startingNode.children[x].children[1];

        namespaces.push(
          new Namespace(startingNode.children[x].attributes.Name,
          formTypes(typesNode),
          formMetrics(startingNode.children[0], 0))
        );
      }

      return namespaces;
    }

    function map(entryNode) {
      var x,
        moduleNode = entryNode.children[0].children[0].children[0].children[0],
        namespacesNode = moduleNode.children[1],
        typesNode = namespacesNode.children[0].children[1],
        membersNode = typesNode.children[0].children[1];

      return new Module(moduleNode.attributes.Name,
                 moduleNode.attributes.AssemblyVersion,
                 formMetrics(moduleNode, 0),
                 formNamespaces(namespacesNode));
    }

    that.map = map;
    return that;
  }

  function DataLoader(url, callback) {
    function execute() {
      return $.get(url, callback);
    }

    return {
      execute: execute
    };
  }

  function LocationUrlParser() {
    function validateUrl(url) {
      if (!url || url.length <= 1) {
        throw new FatalException('no path argument provided');
      }
    }

    function parse() {
      var url = mywindow.location.search;
      validateUrl(url);
      return url.substring(1).split('=')[1];
    }

    return {
      parse: parse
    };
  }

  return {
    NodeEntry: NodeEntry,
    Parser: Parser,
    Metric: Metric,
    Member: Member,
    Type: Type,
    Namespace: Namespace,
    Module: Module,
    Mapper: Mapper,
    DataLoader: DataLoader,
    LocationUrlParser: LocationUrlParser
  };
}

var croaker = new Croaker();
<commit_msg>removed extra var defs<commit_after>function Croaker(env) {
  var deps = env || {},
    $ = deps.jQuery || jQuery,
    mywindow = deps.window || window;

  function FatalException(message) {
    return {
      name: 'FatalException',
      message: message
    };
  }

  function NodeEntry(name, attributes, children) {
    return  {
      name: name,
      attributes: attributes,
      children: children
    };
  }

  function Parser() {
    var that = {};

    function parseAttributes(node) {
      var attributes = {}, x;

      if (node.hasAttributes()) {
        for (x = 0; x < node.attributes.length; x++) {
          attributes[node.attributes.item(x).name] = node.attributes.item(x).value;
        }
      }
      return attributes;
    }

    function parseChildNodes(processor, node) {
      var children = [], x;

      if (node.hasChildNodes()) {
        for (x = 0; x < node.childNodes.length; x++) {
          children.push(processor(node.childNodes.item(x)));
        }
      }
      return children;
    }

    function processNode(node) {
      return new NodeEntry(node.nodeName, parseAttributes(node), parseChildNodes(processNode, node));
    }

    function validateDoc(doc) {
      if(doc.documentElement.innerHTML) {
        throw new FatalException('unable to parse xml');
      }

      if (doc.documentElement.nodeName === 'parsererror') {
        throw new FatalException('unable to parse xml');
      }

    }

    function parse(string) {
      var domparser = new DOMParser(),
        xmlDoc = domparser.parseFromString(string, "text/xml");
      validateDoc(xmlDoc);
      return processNode(xmlDoc.documentElement);
    }

    that.parse = parse;
    return that;
  }

  function Metric(name, value) {
    return {
      name:name,
      value:value
    };
  }

  function Member(name, file, line, metrics) {
    return {
      name:name,
      file:file,
      line:line,
      metrics:metrics
    };
  }

  function Type (name,members,metrics) {
    return {
       name:name,
       members:members,
       metrics:metrics
    };
  }

  function Namespace(name, types, metrics) {
    return {
      name:name,
      types:types,
      metrics:metrics
    };
  }

  function Module(name, version, metrics, namespaces) {
    return {
      name:name,
      version: version,
      metrics: metrics,
      namespaces: namespaces
    };
  }

  function Mapper() {
    var that = {};

    function formMetrics(startingNode, index) {
      var x, metrics = [], metricsNode = startingNode.children[index];

      for (x=0; x < metricsNode.children.length; x++) {
        metrics.push(
          new Metric(metricsNode.children[x].attributes.Name,
          parseInt(metricsNode.children[x].attributes.Value, 10))
        );
      }

      return metrics;
    }

    function formMembers(startingNode) {
      var members = [], x;

      for (x=0; x < startingNode.children.length; x++) {
        members.push(
          new Member (startingNode.children[x].attributes.Name,
          startingNode.children[x].attributes.File,
          startingNode.children[x].attributes.Line,
          formMetrics(startingNode.children[0],0))
        );
      }

      return members;
    }

    function formTypes(startingNode) {
      if(startingNode.children.length < 1) {
        return;
      }

      var types = [], x, membersNode;

      for (x=0; x < startingNode.children.length; x++) {
        membersNode = startingNode.children[x].children[1];

        types.push(
          new Type (startingNode.children[x].attributes.Name,
          formMembers(membersNode),
          formMetrics(startingNode.children[0],0))
        );
      }

      return types;
    }

    function formNamespaces(startingNode) {
      if(startingNode.children.length < 1) {
        return;
      }

      var typesNode, namespaces = [], x;

      for (x=0; x < startingNode.children.length; x++) {
        typesNode = startingNode.children[x].children[1];

        namespaces.push(
          new Namespace(startingNode.children[x].attributes.Name,
          formTypes(typesNode),
          formMetrics(startingNode.children[0], 0))
        );
      }

      return namespaces;
    }

    function map(entryNode) {
      var moduleNode = entryNode.children[0].children[0].children[0].children[0],
        namespacesNode = moduleNode.children[1];

      return new Module(moduleNode.attributes.Name,
                 moduleNode.attributes.AssemblyVersion,
                 formMetrics(moduleNode, 0),
                 formNamespaces(namespacesNode));
    }

    that.map = map;
    return that;
  }

  function DataLoader(url, callback) {
    function execute() {
      return $.get(url, callback);
    }

    return {
      execute: execute
    };
  }

  function LocationUrlParser() {
    function validateUrl(url) {
      if (!url || url.length <= 1) {
        throw new FatalException('no path argument provided');
      }
    }

    function parse() {
      var url = mywindow.location.search;
      validateUrl(url);
      return url.substring(1).split('=')[1];
    }

    return {
      parse: parse
    };
  }

  return {
    NodeEntry: NodeEntry,
    Parser: Parser,
    Metric: Metric,
    Member: Member,
    Type: Type,
    Namespace: Namespace,
    Module: Module,
    Mapper: Mapper,
    DataLoader: DataLoader,
    LocationUrlParser: LocationUrlParser
  };
}

var croaker = new Croaker();
<|endoftext|>


<commit_before>export const alphanumerics = ['a', 'b', 'c', 'g', 'f', '1', '2', '3', '0']
  .map(s => s.toUpperCase());
export const puncs = [
  '.', ',', '/', '\'', ';', '[', ']', '\\', '-', '=', '`',
];
export const modifiers = [
  'Alt', 'Shift', 'Ctrl', 'Meta',
];
export const arrowKeys = [
  'ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown',
];
export const ENTER = 'Enter';
export const BACKSPACE = 'Backspace';
<commit_msg>Fixtures for unshifted value test<commit_after>export const alphanumerics = ['a', 'b', 'c', 'g', 'f', '1', '2', '3', '0']
  .map(s => s.toUpperCase());
export const puncs = [
  '.', ',', '/', '\'', ';', '[', ']', '\\', '-', '=', '`',
];
export const modifiers = [
  'Alt', 'Shift', 'Ctrl', 'Meta',
];
export const arrowKeys = [
  'ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown',
];
export const ENTER = 'Enter';
export const BACKSPACE = 'Backspace';
/* eslint-disable quotes */
/* eslint-disable quote-props */
export const shiftedValues = {
  '!': {
    code: "Digit1",
    string: "1",
  },
  '@': {
    code: "Digit2",
    string: "2",
  },
  '#': {
    code: "Digit3",
    string: "3",
  },
  '$': {
    code: "Digit4",
    string: "4",
  },
  '%': {
    code: "Digit5",
    string: "5",
  },
  '^': {
    code: "Digit6",
    string: "6",
  },
  '&': {
    code: "Digit7",
    string: "7",
  },
  '*': {
    code: "Digit8",
    string: "8",
  },
  '(': {
    code: "Digit9",
    string: "9",
  },
  ')': {
    code: "Digit0",
    string: "0",
  },
  '_': {
    code: "Minus",
    string: "-",
  },
  '+': {
    code: "Equal",
    string: "=",
  },
  '{': {
    code: "BracketLeft",
    string: "[",
  },
  '}': {
    code: "BracketRight",
    string: "]",
  },
  '|': {
    code: "Backslash",
    string: "\\",
  },
  ':': {
    code: "Semicolon",
    string: ";",
  },
  '"': {
    code: "Quote",
    string: "'",
  },
  '<': {
    code: "Comma",
    string: ",",
  },
  '>': {
    code: "Period",
    string: ".",
  },
  '?': {
    code: "Slash",
    string: "/",
  },
};
<|endoftext|>


<commit_before>module.exports = {
  plugins: {
   'postcss-import': {},
   'postcss-cssnext': {
	     browsers: ['last 2 versions', '> 5%'],
	     }
	}
};
<commit_msg>clean up<commit_after>module.exports = {
  plugins: {
   'postcss-import': {},
   'postcss-cssnext': {
	   browsers: ['last 2 versions', '> 5%'],
	  }
	}
};
<|endoftext|>


<commit_before>import { identity } from "../utility/kit";

export function sortFactory(model) {
    const { index } = model.rowList();
    if (!index.size) {
        return identity;
    }

    const { id } = model.data();
    return rows => {
        let cursor = 0;
        const positions = new Map();
        return rows
            .filter((row, i) => {
                const key = id.row(i, row);
                const position = index.get(key)
                if (position || position === 0) {
                    positions.set(position, row);
                    return false;
                }

                return true;
            })
            .reduce((memo, row) => {
                let indexRow;
                while (indexRow = positions.get(cursor)) {
                    memo.push(indexRow)
                    cursor++;
                }

                memo.push(row);
                cursor++;

                return memo;
            }, []);
    };
}<commit_msg>append remain positions to the end<commit_after>import { identity } from "../utility/kit";

export function sortFactory(model) {
    const { index } = model.rowList();
    if (!index.size) {
        return identity;
    }

    const { id } = model.data();
    return rows => {
        let cursor = 0;
        const positions = new Map();
        const result =
            rows
                .filter((row, i) => {
                    const key = id.row(i, row);
                    const position = index.get(key)
                    if (position || position === 0) {
                        positions.set(position, row);
                        return false;
                    }

                    return true;
                })
                .reduce((memo, row) => {
                    let indexRow;
                    while (indexRow = positions.get(cursor)) {
                        positions.delete(cursor);
                        memo.push(indexRow)
                        cursor++;
                    }

                    memo.push(row);
                    cursor++;

                    return memo;
                }, []);

        if (positions.size) {
            const remain = Array.from(positions.entries());
            remain.sort((x, y) => x[0] - y[0]);

            return result.concat(remain.map(pos => pos[1]));
        }

        return result;
    };
}``<|endoftext|>


<commit_before>var darkColor;
var lightColor;

self.port.on("colors", function (colors) {
    darkColor = colors[0];
    lightColor = colors[1];
    allColors = colors[2];
    //     console.log("Contrast: got colors, checking elements");

    if (allColors == true) {
        // Now replace document colors
        checkElementContrast(document.all[0]);

        // Other checks required when browser is in quirks mode
        if (document.compatMode == "BackCompat") {
            // tables don't inherit color
            var tables = document.getElementsByTagName("table");
            for (var i = 0; i < tables.length; i++) {
                if (getComputedStyle(tables[i]).color ==
                    getDefaultComputedStyle(tables[i]).color) {
                    //if color has not been set explicitely, then force inherit
                    tables[i].style.color = "inherit";
                }
            }
        }
    }

    // Seperately check input-like elements
    var inputs = document.getElementsByTagName("input");
    for (var i=0; i < inputs.length; i++) {
        checkElementContrast(inputs[i]);
    }

    var texts = document.getElementsByTagName("textarea");
    for (var i=0; i < texts.length; i++) {
        checkElementContrast(texts[i]);
    }

    var selects = document.getElementsByTagName("select");
    for (var i=0; i < selects.length; i++) {
        checkElementContrast(selects[i]);
    }

    var buttons = document.getElementsByTagName("button");
    for (var i=0; i < buttons.length; i++) {
        checkElementContrast(buttons[i]);
    }
});

function checkElementContrast(element) {
    try {
        var isFgUndefined = (getComputedStyle(element).color ==
            getDefaultComputedStyle(element).color);
        var isBgUndefined = (getComputedStyle(element).backgroundColor ==
            getDefaultComputedStyle(element).backgroundColor)

        var hasBgImg = (getComputedStyle(element).backgroundImage != 'none');
    } catch (e) {
        console.log("Got exception " + e.message + " when parsing element " +
            element.tagName + "." + element.className + "#" + element.id);
        return;
    }

    isBgUndefined = isBgUndefined && !hasBgImg;

    var fg_color_defined = getComputedStyle(element).color !=
        getDefaultComputedStyle(element).color;
    var bg_color_defined = getComputedStyle(element).backgroundColor !=
        getDefaultComputedStyle(element).backgroundColor;
    var bg_img_defined = getComputedStyle(element).backgroundImage != 'none';

    if (fg_color_defined && bg_color_defined) {
        //Both colors explicitely defined, nothing to do
        return;
    }

    if (!fg_color_defined && bg_color_defined) {
        // always set fg if only bg color defined
        element.style.color = darkColor;
        return;
    }

    if (fg_color_defined && !bg_color_defined) {
        //since bg images might be transparent, set the bg color no
        //matter what
        element.style.backgroundColor = lightColor;
        return;
    }

    if (bg_img_defined) {
        //No FG or BG color, but possibly transparent image, so need
        //to set both
        element.style.color = darkColor;
        element.style.backgroundColor = lightColor;
        return;
    }

    //Nothing defined, recurse through children
    var children = element.children
    for (var i = 0; i < children.length; i++) {
        // Don't look at non-renderable elements
        switch (element.children[i].nodeName) {
        case "HEAD":
        case "TITLE":
        case "META":
        case "SCRIPT":
        case "IMG":
        case "STYLE":
            break;
        default:
            //console.log("Contrast: recursing");
            checkElementContrast(element.children[i]);
        }
    }
    return;
}
<commit_msg>Simplify logic of scanning specific input elements<commit_after>var darkColor;
var lightColor;

self.port.on("colors", function (colors) {
    darkColor = colors[0];
    lightColor = colors[1];
    allColors = colors[2];
    //     console.log("Contrast: got colors, checking elements");

    if (allColors == true) {
        // Now replace document colors
        checkElementContrast(document.all[0]);

        // Other checks required when browser is in quirks mode
        if (document.compatMode == "BackCompat") {
            // tables don't inherit color
            var tables = document.getElementsByTagName("table");
            for (var i = 0; i < tables.length; i++) {
                if (getComputedStyle(tables[i]).color ==
                    getDefaultComputedStyle(tables[i]).color) {
                    //if color has not been set explicitely, then force inherit
                    tables[i].style.color = "inherit";
                }
            }
        }
    }

    // Seperately check input-like elements
    ["input", "textarea", "select", "button", "toolbarbutton"].forEach(
        function (val) {
            var elements = document.getElementsByTagName(val),
                i;
            for (i = 0; i < elements.length; i += 1) {
                checkElementContrast(elements[i]);
            }
        });
});

function checkElementContrast(element) {
    try {
        var isFgUndefined = (getComputedStyle(element).color ==
            getDefaultComputedStyle(element).color);
        var isBgUndefined = (getComputedStyle(element).backgroundColor ==
            getDefaultComputedStyle(element).backgroundColor)

        var hasBgImg = (getComputedStyle(element).backgroundImage != 'none');
    } catch (e) {
        console.log("Got exception " + e.message + " when parsing element " +
            element.tagName + "." + element.className + "#" + element.id);
        return;
    }

    isBgUndefined = isBgUndefined && !hasBgImg;

    var fg_color_defined = getComputedStyle(element).color !=
        getDefaultComputedStyle(element).color;
    var bg_color_defined = getComputedStyle(element).backgroundColor !=
        getDefaultComputedStyle(element).backgroundColor;
    var bg_img_defined = getComputedStyle(element).backgroundImage != 'none';

    if (fg_color_defined && bg_color_defined) {
        //Both colors explicitely defined, nothing to do
        return;
    }

    if (!fg_color_defined && bg_color_defined) {
        // always set fg if only bg color defined
        element.style.color = darkColor;
        return;
    }

    if (fg_color_defined && !bg_color_defined) {
        //since bg images might be transparent, set the bg color no
        //matter what
        element.style.backgroundColor = lightColor;
        return;
    }

    if (bg_img_defined) {
        //No FG or BG color, but possibly transparent image, so need
        //to set both
        element.style.color = darkColor;
        element.style.backgroundColor = lightColor;
        return;
    }

    //Nothing defined, recurse through children
    var children = element.children
    for (var i = 0; i < children.length; i++) {
        // Don't look at non-renderable elements
        switch (element.children[i].nodeName) {
        case "HEAD":
        case "TITLE":
        case "META":
        case "SCRIPT":
        case "IMG":
        case "STYLE":
            break;
        default:
            //console.log("Contrast: recursing");
            checkElementContrast(element.children[i]);
        }
    }
    return;
}
<|endoftext|>


<commit_before>import fs from 'fs';
import path from 'path';
import geoTz from 'geo-tz';
import { getLog, graphLog } from '../../core/log';
const log = getLog('data/queries/links');

import { uploadVideo } from '../../services/youtubeDataApi';

import {
  localityRepository,
  linkRepository,
  checkInRepository,
  terminalRepository,
  userRepository
} from '../source';

import {
  MediaItemType, LinkSearchResultType,
} from '../types/TransitLinkType';

import {
  GraphQLString,
  GraphQLList,
} from 'graphql';

import { STORAGE_PATH, MEDIA_PATH } from '../../config';
import tagRepository from '../source/tagRepository';
import { getLocalDateTime } from '../../core/utils';

export const TransitLinkMutationFields = {

  instanceFiles: {

    type: MediaItemType,
    description: 'Upload media files for link instance',
    args: {
      linkInstanceUuid: { type: GraphQLString }
    },
    resolve: async ({ request }, { linkInstanceUuid }) => {

      log.info(`graphql-request=upload-instance-file user=${request.user ? request.user.uuid : null}`);

      const { file } = request;

      const nameParts = file.originalname.split('.');
      const extension = nameParts[nameParts.length - 1];
      const savePath = STORAGE_PATH || path.join(__dirname, 'public');
      const filePath = path.join(savePath, file.filename);

      const mediaPath = path.join((MEDIA_PATH || path.join(__dirname, 'public')), 'instance-media');
      const instancePath = path.join(mediaPath, linkInstanceUuid);

      if (fs.existsSync(filePath)) {

        if (!fs.existsSync(mediaPath)) {
          fs.mkdirSync(mediaPath);
        }
        if (!fs.existsSync(instancePath)) {
          fs.mkdirSync(instancePath);
        }

        const now = (new Date()).getTime();
        const instanceFileName = `${now}.${extension}`;
        const instanceFilePath = path.join(instancePath, instanceFileName);
        fs.renameSync(filePath, instanceFilePath);

        const linkInstanceId = await linkRepository.getInstanceIdByUuid(linkInstanceUuid);
        let mediaItem = null;

        if (file.mimetype.indexOf('image') !== -1) {

          log.info(`graphql-request=upload-instance-file user=${request.user ? request.user.uuid : null} image-file-name=${instanceFileName}`);

          mediaItem = await linkRepository.saveInstanceMedia(linkInstanceId, {
            type: 'image',
            flag: false,
            url: `/instance-media/${linkInstanceUuid}/${instanceFileName}`
          });

        } else {

          const upload = await uploadVideo(linkInstanceUuid, instanceFilePath);
          const thumbnail = upload.snippet.thumbnails.medium.url;
          log.info(`graphql-request=upload-instance-file user=${request.user ? request.user.uuid : null} video-id=${upload.id}`);

          mediaItem = await linkRepository.saveInstanceMedia(linkInstanceId, {
            type: 'video',
            flag: false,
            url: upload.id,
            thumbnail
          });

        }

        return mediaItem;

      } else {
        throw new Error(`Did not find media file ${filePath})`);
      }

    }

  }

};

const findRoutePoints = async (terminals) => {
  for (let i = 0; i < terminals.length; i++) {
    const terminal = terminals[i];
    const { linkedTerminal } = terminal;
    if (linkedTerminal) {
      const routeCheckIns = await checkInRepository.getCheckIns({
        createdAt: {
          $gt: terminal.type === 'departure' ? terminal.createdAt : linkedTerminal.createdAt,
          $lt: terminal.type === 'departure' ? linkedTerminal.createdAt : terminal.createdAt
        },
        userId: terminal.userId
      }, {
        order: [['createdAt', terminal.type === 'departure' ? 'ASC' : 'DESC']]
      });
      terminal.route = (routeCheckIns || {}).map(checkIn => ({ lat: checkIn.latitude, lng: checkIn.longitude }));
    }
  }
};

const findTags = async (terminals) => {
  const allTags = [];
  for (let i = 0; i < terminals.length; i++) {
    const terminal = terminals[i];
    const tags = await tagRepository.getTagsByCheckInIds([terminal.checkInId]);
    const { linkedTerminal } = terminal;
    if (linkedTerminal) {
      const linkedTags = await tagRepository.getTagsByCheckInIds([linkedTerminal.checkInId]);
      tags.push(
        ...linkedTags.filter(
          linkedTag => !tags.find(
            tag => tag.tag === linkedTag.tag && tag.userUuid === linkedTag.userUuid
          )
        )
      );
    }

    allTags.push(...tags);
    terminal.tags = tags;
  }
  return allTags;
};

export const TransitLinkQueryFields = {

  transitLinks: {

    type: LinkSearchResultType,
    description: 'Search terminals',
    args: {
      locality: { type: GraphQLString },
      linkedLocality: { type: GraphQLString },
      from: { type: GraphQLString },
      to: { type: GraphQLString },
      tag: { type: GraphQLString },
      search: { type: GraphQLString },
      user: { type: GraphQLString },
      type: { type: GraphQLString },
      transportTypes: { type: new GraphQLList(GraphQLString) }
    },
    resolve: async ({ request }, params) => {

      const { locality, linkedLocality, from, to, tag, user, type, search, transportTypes } = params;

      log.info(graphLog(request, 'search-links',`search=${search} locality=${locality} tag=${tag} type=${type}`));

      const linkStats = [];

      if (!tag) {

        if (from && to) {

          const routes = await terminalRepository.getRoute(from, to);
          const routeKeys = Object.keys(routes);

          if (routeKeys.length > 0) {

            let terminals = [];

            for (let i = 0; i < routeKeys.length; i++) {

              const departures = routes[routeKeys[i]]
                .filter(dep => dep.linkedTerminalId)
                .map(dep => ({
                  ...dep,
                  routeId: parseInt(routeKeys[i]),
                  localDateTime: getLocalDateTime(dep.createdAt, geoTz(dep.latitude, dep.longitude)[0]),
                  linkedTerminal: {
                    ...dep.linkedTerminal.json(),
                    localDateTime: getLocalDateTime(dep.linkedTerminal.createdAt, geoTz(dep.linkedTerminal.latitude, dep.linkedTerminal.longitude)[0]),
                  }
                }));

              await findRoutePoints(departures);

              terminals = terminals.concat(departures);

            }

            let terminal = null;
            if (terminals.length > 0) terminal = terminals[0];

            if (terminal) {
              linkStats.push({
                locality: terminal.locality,
                latitude: terminal.latitude,
                longitude: terminal.longitude,
                from,
                to,
                departures: terminals,
                arrivals: [],
                internal: []
              });

            }
          }

          return {
            searchResultType: 'route',
            from,
            to,
            links: linkStats
          };

        } else {

          const localityQuery = { limit: 16 };
          const transportQuery = {};

          if (locality) localityQuery.locality = locality;
          if (search) localityQuery.search = search;
          if (transportTypes && transportTypes.length > 0) {
            localityQuery.transportTypes = transportTypes;
            transportQuery.transport = transportTypes;
          }
          const localities = await localityRepository.getMostTravelledLocalities(localityQuery);
          if (!linkedLocality) {

            const localities = await localityRepository.getMostTravelledLocalities(localityQuery);
            const baseQuery = {
              ...((transportTypes && transportTypes.length > 0) && { transport: transportTypes })
            };

            const getLinkedLocalityInfo = async (locality, linkedLocality, type) => {

              const terminal = await terminalRepository.getTerminal({
                locality,
                linkedLocality,
                type,
                linkedTerminalId: { $ne: null }
              });

              const counts = await terminalRepository.countInterTerminals({
                locality, linkedLocality
              });

              const timeZone = geoTz(terminal.latitude, terminal.longitude)[0];
              const formattedTerminal = {
                ...terminal.json(),
                localDateTime: getLocalDateTime(terminal.createdAt, timeZone)
              };
              delete formattedTerminal.formattedAddress;
              delete formattedTerminal.linkedFormattedAddress;
              formattedTerminal.linkCount = counts[type];
              formattedTerminal.reverseLinkCount = counts[type === 'arrival' ? 'departure' : 'arrival'];

              return {
                terminal: formattedTerminal,
                linkedLocality,
                linkCount: counts[type]
              };

            };

            for (let i = 0; i < localities.length; i++) {

              const locality = localities[i];
              const interTerminalCounts = await terminalRepository.countInterTerminals({
                ...baseQuery, locality
              });

              const departureLinks = [];
              const linkedDepartureLocalities = await terminalRepository.getLinkedLocalitiesByLocality({
                ...baseQuery, locality,
                type: 'departure'
              });
              for (let i = 0; i < linkedDepartureLocalities.length; i++) {
                departureLinks.push(await getLinkedLocalityInfo(locality, linkedDepartureLocalities[i], 'departure'));
              }

              const arrivalLinks = [];
              const linkedArrivalLocalities = await terminalRepository.getLinkedLocalitiesByLocality({
                ...baseQuery, locality,
                type: 'arrival'
              });
              for (let i = 0; i < linkedArrivalLocalities.length; i++) {
                arrivalLinks.push(await getLinkedLocalityInfo(locality, linkedArrivalLocalities[i], 'arrival'));
              }

              const terminal = await terminalRepository.getTerminal({ locality });

              const departures = departureLinks.map(dep => dep.terminal);
              const arrivals = arrivalLinks.map(arr => arr.terminal);

              const internal = await terminalRepository.getInternalDeparturesByLocality(locality, baseQuery);

              const tags = await tagRepository.getLatestTagsByLocality(locality, 14);

              linkStats.push({
                locality,
                latitude: terminal.latitude,
                longitude: terminal.longitude,
                departureCount: interTerminalCounts.arrival || 0,
                arrivalCount: interTerminalCounts.departure || 0,
                departures,
                arrivals,
                internal,
                linkedDepartures: departures.map(dep => ({ linkedLocality: dep.linkedTerminal.locality })),
                linkedArrivals: arrivals.map(arr => ({ linkedLocality: arr.linkedTerminal.locality })),
                tags
              });

            }

            return {
              searchResultType: 'connections',
              links: linkStats
            };

          } else {

            const baseQuery = {
              ...((transportTypes && transportTypes.length > 0) && { transport: transportTypes }),
              linkedLocality
            };

            const locality = localities[0];
            const interTerminals = await terminalRepository.getInterTerminalsByLocality(locality, baseQuery);
            const departures = interTerminals.filter(terminal => terminal.type === 'departure');
            const arrivals = interTerminals.filter(terminal => terminal.type === 'arrival');
            await findRoutePoints(departures);
            await findRoutePoints(arrivals);
            const departureTags = await findTags(departures);
            const arrivalTags = await findTags(arrivals);
            const allTags = departureTags;
            allTags.push(
              ...arrivalTags.filter(
                arrTag => !departureTags.find(
                  depTag => depTag.tag === arrTag.tag && depTag.userUuid === arrTag.userUuid
                )
              )
            );

            let terminal = null;
            if (departures.length > 0) terminal = departures[0];
            if (arrivals.length > 0) terminal = arrivals[0];
            if (terminal) {
              linkStats.push({
                locality,
                latitude: terminal.latitude,
                longitude: terminal.longitude,
                departures: departures.map(dep => ({
                  ...dep.json(),
                  localDateTime: getLocalDateTime(dep.createdAt, geoTz(dep.latitude, dep.longitude)[0]),
                  linkedTerminal: {
                    ...dep.linkedTerminal.json(),
                    localDateTime: getLocalDateTime(dep.linkedTerminal.createdAt, geoTz(dep.linkedTerminal.latitude, dep.linkedTerminal.longitude)[0]),
                  }
                })),
                arrivals: arrivals.map(arr => ({
                  ...arr.json(),
                  localDateTime: getLocalDateTime(arr.createdAt, geoTz(arr.latitude, arr.longitude)[0]),
                  linkedTerminal: {
                    ...arr.linkedTerminal.json(),
                    localDateTime: getLocalDateTime(arr.linkedTerminal.createdAt, geoTz(arr.linkedTerminal.latitude, arr.linkedTerminal.longitude)[0]),
                  }
                })),
                tags: allTags
              });
            }
          }

          return {
            searchResultType: 'links',
            locality,
            linkedLocality,
            links: linkStats
          };

        }

      } else {

        const taggedCheckIns = await checkInRepository.getTaggedCheckIns(tag);

        if (taggedCheckIns.length > 0) {

          const query = {
            checkInId: taggedCheckIns.map(checkIn => checkIn.id),
            type: 'departure'
          };

          if (user) {
            const userId = await userRepository.getUserIdByUuid(user);
            query.userId = userId;
          }

          const departures = (await terminalRepository.getTerminals(query))
            .filter(dep => dep.linkedTerminal)
            .map(dep => ({
              ...dep.json(),
              localDateTime: getLocalDateTime(dep.createdAt, geoTz(dep.latitude, dep.longitude)[0]),
              linkedTerminal: {
                ...dep.linkedTerminal.json(),
                localDateTime: getLocalDateTime(dep.linkedTerminal.createdAt, geoTz(dep.linkedTerminal.latitude, dep.linkedTerminal.longitude)[0]),
              }
            }));

          await findRoutePoints(departures);
          let terminal = null;
          if (departures.length > 0) terminal = departures[0];
          if (terminal) {
            linkStats.push({
              locality: terminal.locality,
              latitude: terminal.latitude,
              longitude: terminal.longitude,
              departures,
              arrivals: [],
              internal: []
            });
          }
        }

        return {
          searchResultType: 'tagged',
          links: linkStats
        };

      }

    }

  },

  linkInstanceMedia: {

    type: new GraphQLList(MediaItemType),
    description: 'Get media associated to a link instance',
    args: {
      linkInstanceUuid: { type: GraphQLString }
    },
    resolve: async ({ request }, { linkInstanceUuid }) => {
      const linkInstanceId = await linkRepository.getInstanceIdByUuid(linkInstanceUuid);
      const mediaItems = await linkRepository.getMediaItems({ linkInstanceId });
      return mediaItems;

    }

  }

};
<commit_msg>Fixed bug with routepoints finding<commit_after>import fs from 'fs';
import path from 'path';
import geoTz from 'geo-tz';
import { getLog, graphLog } from '../../core/log';
const log = getLog('data/queries/links');

import { uploadVideo } from '../../services/youtubeDataApi';

import {
  localityRepository,
  linkRepository,
  checkInRepository,
  terminalRepository,
  userRepository
} from '../source';

import {
  MediaItemType, LinkSearchResultType,
} from '../types/TransitLinkType';

import {
  GraphQLString,
  GraphQLList,
} from 'graphql';

import { STORAGE_PATH, MEDIA_PATH } from '../../config';
import tagRepository from '../source/tagRepository';
import { getLocalDateTime } from '../../core/utils';

export const TransitLinkMutationFields = {

  instanceFiles: {

    type: MediaItemType,
    description: 'Upload media files for link instance',
    args: {
      linkInstanceUuid: { type: GraphQLString }
    },
    resolve: async ({ request }, { linkInstanceUuid }) => {

      log.info(`graphql-request=upload-instance-file user=${request.user ? request.user.uuid : null}`);

      const { file } = request;

      const nameParts = file.originalname.split('.');
      const extension = nameParts[nameParts.length - 1];
      const savePath = STORAGE_PATH || path.join(__dirname, 'public');
      const filePath = path.join(savePath, file.filename);

      const mediaPath = path.join((MEDIA_PATH || path.join(__dirname, 'public')), 'instance-media');
      const instancePath = path.join(mediaPath, linkInstanceUuid);

      if (fs.existsSync(filePath)) {

        if (!fs.existsSync(mediaPath)) {
          fs.mkdirSync(mediaPath);
        }
        if (!fs.existsSync(instancePath)) {
          fs.mkdirSync(instancePath);
        }

        const now = (new Date()).getTime();
        const instanceFileName = `${now}.${extension}`;
        const instanceFilePath = path.join(instancePath, instanceFileName);
        fs.renameSync(filePath, instanceFilePath);

        const linkInstanceId = await linkRepository.getInstanceIdByUuid(linkInstanceUuid);
        let mediaItem = null;

        if (file.mimetype.indexOf('image') !== -1) {

          log.info(`graphql-request=upload-instance-file user=${request.user ? request.user.uuid : null} image-file-name=${instanceFileName}`);

          mediaItem = await linkRepository.saveInstanceMedia(linkInstanceId, {
            type: 'image',
            flag: false,
            url: `/instance-media/${linkInstanceUuid}/${instanceFileName}`
          });

        } else {

          const upload = await uploadVideo(linkInstanceUuid, instanceFilePath);
          const thumbnail = upload.snippet.thumbnails.medium.url;
          log.info(`graphql-request=upload-instance-file user=${request.user ? request.user.uuid : null} video-id=${upload.id}`);

          mediaItem = await linkRepository.saveInstanceMedia(linkInstanceId, {
            type: 'video',
            flag: false,
            url: upload.id,
            thumbnail
          });

        }

        return mediaItem;

      } else {
        throw new Error(`Did not find media file ${filePath})`);
      }

    }

  }

};

const findRoutePoints = async (terminals) => {
  for (let i = 0; i < terminals.length; i++) {
    const terminal = terminals[i];
    const { linkedTerminal } = terminal;
    if (linkedTerminal) {
      const routeCheckIns = await checkInRepository.getCheckIns({
        createdAt: {
          $gt: terminal.type === 'departure' ? terminal.createdAt : linkedTerminal.createdAt,
          $lt: terminal.type === 'departure' ? linkedTerminal.createdAt : terminal.createdAt
        },
        id: { $notIn: [terminal.checkInId, linkedTerminal.checkInId] },
        userId: terminal.userId
      }, {
        order: [['createdAt', terminal.type === 'departure' ? 'ASC' : 'DESC']]
      });
      terminal.route = (routeCheckIns || {}).map(checkIn => ({ lat: checkIn.latitude, lng: checkIn.longitude }));
    }
  }
};

const findTags = async (terminals) => {
  const allTags = [];
  for (let i = 0; i < terminals.length; i++) {
    const terminal = terminals[i];
    const tags = await tagRepository.getTagsByCheckInIds([terminal.checkInId]);
    const { linkedTerminal } = terminal;
    if (linkedTerminal) {
      const linkedTags = await tagRepository.getTagsByCheckInIds([linkedTerminal.checkInId]);
      tags.push(
        ...linkedTags.filter(
          linkedTag => !tags.find(
            tag => tag.tag === linkedTag.tag && tag.userUuid === linkedTag.userUuid
          )
        )
      );
    }

    allTags.push(...tags);
    terminal.tags = tags;
  }
  return allTags;
};

export const TransitLinkQueryFields = {

  transitLinks: {

    type: LinkSearchResultType,
    description: 'Search terminals',
    args: {
      locality: { type: GraphQLString },
      linkedLocality: { type: GraphQLString },
      from: { type: GraphQLString },
      to: { type: GraphQLString },
      tag: { type: GraphQLString },
      search: { type: GraphQLString },
      user: { type: GraphQLString },
      type: { type: GraphQLString },
      transportTypes: { type: new GraphQLList(GraphQLString) }
    },
    resolve: async ({ request }, params) => {

      const { locality, linkedLocality, from, to, tag, user, type, search, transportTypes } = params;

      log.info(graphLog(request, 'search-links',`search=${search} locality=${locality} tag=${tag} type=${type}`));

      const linkStats = [];

      if (!tag) {

        if (from && to) {

          const routes = await terminalRepository.getRoute(from, to);
          const routeKeys = Object.keys(routes);

          if (routeKeys.length > 0) {

            let terminals = [];

            for (let i = 0; i < routeKeys.length; i++) {

              const departures = routes[routeKeys[i]]
                .filter(dep => dep.linkedTerminalId)
                .map(dep => ({
                  ...dep,
                  routeId: parseInt(routeKeys[i]),
                  localDateTime: getLocalDateTime(dep.createdAt, geoTz(dep.latitude, dep.longitude)[0]),
                  linkedTerminal: {
                    ...dep.linkedTerminal.json(),
                    localDateTime: getLocalDateTime(dep.linkedTerminal.createdAt, geoTz(dep.linkedTerminal.latitude, dep.linkedTerminal.longitude)[0]),
                  }
                }));

              await findRoutePoints(departures);

              terminals = terminals.concat(departures);

            }

            let terminal = null;
            if (terminals.length > 0) terminal = terminals[0];

            if (terminal) {
              linkStats.push({
                locality: terminal.locality,
                latitude: terminal.latitude,
                longitude: terminal.longitude,
                from,
                to,
                departures: terminals,
                arrivals: [],
                internal: []
              });

            }
          }

          return {
            searchResultType: 'route',
            from,
            to,
            links: linkStats
          };

        } else {

          const localityQuery = { limit: 16 };
          const transportQuery = {};

          if (locality) localityQuery.locality = locality;
          if (search) localityQuery.search = search;
          if (transportTypes && transportTypes.length > 0) {
            localityQuery.transportTypes = transportTypes;
            transportQuery.transport = transportTypes;
          }
          const localities = await localityRepository.getMostTravelledLocalities(localityQuery);
          if (!linkedLocality) {

            const localities = await localityRepository.getMostTravelledLocalities(localityQuery);
            const baseQuery = {
              ...((transportTypes && transportTypes.length > 0) && { transport: transportTypes })
            };

            const getLinkedLocalityInfo = async (locality, linkedLocality, type) => {

              const terminal = await terminalRepository.getTerminal({
                locality,
                linkedLocality,
                type,
                linkedTerminalId: { $ne: null }
              });

              const counts = await terminalRepository.countInterTerminals({
                locality, linkedLocality
              });

              const timeZone = geoTz(terminal.latitude, terminal.longitude)[0];
              const formattedTerminal = {
                ...terminal.json(),
                localDateTime: getLocalDateTime(terminal.createdAt, timeZone)
              };
              delete formattedTerminal.formattedAddress;
              delete formattedTerminal.linkedFormattedAddress;
              formattedTerminal.linkCount = counts[type];
              formattedTerminal.reverseLinkCount = counts[type === 'arrival' ? 'departure' : 'arrival'];

              return {
                terminal: formattedTerminal,
                linkedLocality,
                linkCount: counts[type]
              };

            };

            for (let i = 0; i < localities.length; i++) {

              const locality = localities[i];
              const interTerminalCounts = await terminalRepository.countInterTerminals({
                ...baseQuery, locality
              });

              const departureLinks = [];
              const linkedDepartureLocalities = await terminalRepository.getLinkedLocalitiesByLocality({
                ...baseQuery, locality,
                type: 'departure'
              });
              for (let i = 0; i < linkedDepartureLocalities.length; i++) {
                departureLinks.push(await getLinkedLocalityInfo(locality, linkedDepartureLocalities[i], 'departure'));
              }

              const arrivalLinks = [];
              const linkedArrivalLocalities = await terminalRepository.getLinkedLocalitiesByLocality({
                ...baseQuery, locality,
                type: 'arrival'
              });
              for (let i = 0; i < linkedArrivalLocalities.length; i++) {
                arrivalLinks.push(await getLinkedLocalityInfo(locality, linkedArrivalLocalities[i], 'arrival'));
              }

              const terminal = await terminalRepository.getTerminal({ locality });

              const departures = departureLinks.map(dep => dep.terminal);
              const arrivals = arrivalLinks.map(arr => arr.terminal);

              const internal = await terminalRepository.getInternalDeparturesByLocality(locality, baseQuery);

              const tags = await tagRepository.getLatestTagsByLocality(locality, 14);

              linkStats.push({
                locality,
                latitude: terminal.latitude,
                longitude: terminal.longitude,
                departureCount: interTerminalCounts.arrival || 0,
                arrivalCount: interTerminalCounts.departure || 0,
                departures,
                arrivals,
                internal,
                linkedDepartures: departures.map(dep => ({ linkedLocality: dep.linkedTerminal.locality })),
                linkedArrivals: arrivals.map(arr => ({ linkedLocality: arr.linkedTerminal.locality })),
                tags
              });

            }

            return {
              searchResultType: 'connections',
              links: linkStats
            };

          } else {

            const baseQuery = {
              ...((transportTypes && transportTypes.length > 0) && { transport: transportTypes }),
              linkedLocality
            };

            const locality = localities[0];
            const interTerminals = await terminalRepository.getInterTerminalsByLocality(locality, baseQuery);
            const departures = interTerminals.filter(terminal => terminal.type === 'departure');
            const arrivals = interTerminals.filter(terminal => terminal.type === 'arrival');
            await findRoutePoints(departures);
            await findRoutePoints(arrivals);
            const departureTags = await findTags(departures);
            const arrivalTags = await findTags(arrivals);
            const allTags = departureTags;
            allTags.push(
              ...arrivalTags.filter(
                arrTag => !departureTags.find(
                  depTag => depTag.tag === arrTag.tag && depTag.userUuid === arrTag.userUuid
                )
              )
            );

            let terminal = null;
            if (departures.length > 0) terminal = departures[0];
            if (arrivals.length > 0) terminal = arrivals[0];
            if (terminal) {
              linkStats.push({
                locality,
                latitude: terminal.latitude,
                longitude: terminal.longitude,
                departures: departures.map(dep => ({
                  ...dep.json(),
                  localDateTime: getLocalDateTime(dep.createdAt, geoTz(dep.latitude, dep.longitude)[0]),
                  linkedTerminal: {
                    ...dep.linkedTerminal.json(),
                    localDateTime: getLocalDateTime(dep.linkedTerminal.createdAt, geoTz(dep.linkedTerminal.latitude, dep.linkedTerminal.longitude)[0]),
                  }
                })),
                arrivals: arrivals.map(arr => ({
                  ...arr.json(),
                  localDateTime: getLocalDateTime(arr.createdAt, geoTz(arr.latitude, arr.longitude)[0]),
                  linkedTerminal: {
                    ...arr.linkedTerminal.json(),
                    localDateTime: getLocalDateTime(arr.linkedTerminal.createdAt, geoTz(arr.linkedTerminal.latitude, arr.linkedTerminal.longitude)[0]),
                  }
                })),
                tags: allTags
              });
            }
          }

          return {
            searchResultType: 'links',
            locality,
            linkedLocality,
            links: linkStats
          };

        }

      } else {

        const taggedCheckIns = await checkInRepository.getTaggedCheckIns(tag);

        if (taggedCheckIns.length > 0) {

          const query = {
            checkInId: taggedCheckIns.map(checkIn => checkIn.id),
            type: 'departure'
          };

          if (user) {
            const userId = await userRepository.getUserIdByUuid(user);
            query.userId = userId;
          }

          const departures = (await terminalRepository.getTerminals(query))
            .filter(dep => dep.linkedTerminal)
            .map(dep => ({
              ...dep.json(),
              localDateTime: getLocalDateTime(dep.createdAt, geoTz(dep.latitude, dep.longitude)[0]),
              linkedTerminal: {
                ...dep.linkedTerminal.json(),
                localDateTime: getLocalDateTime(dep.linkedTerminal.createdAt, geoTz(dep.linkedTerminal.latitude, dep.linkedTerminal.longitude)[0]),
              }
            }));

          await findRoutePoints(departures);
          let terminal = null;
          if (departures.length > 0) terminal = departures[0];
          if (terminal) {
            linkStats.push({
              locality: terminal.locality,
              latitude: terminal.latitude,
              longitude: terminal.longitude,
              departures,
              arrivals: [],
              internal: []
            });
          }
        }

        return {
          searchResultType: 'tagged',
          links: linkStats
        };

      }

    }

  },

  linkInstanceMedia: {

    type: new GraphQLList(MediaItemType),
    description: 'Get media associated to a link instance',
    args: {
      linkInstanceUuid: { type: GraphQLString }
    },
    resolve: async ({ request }, { linkInstanceUuid }) => {
      const linkInstanceId = await linkRepository.getInstanceIdByUuid(linkInstanceUuid);
      const mediaItems = await linkRepository.getMediaItems({ linkInstanceId });
      return mediaItems;

    }

  }

};
<|endoftext|>


<commit_before>import UserSettings from './models/userSettings';
import UserArticleLink from './models/userArticleLink';
import { parseToJson } from '@cofacts/line-bot-log-parser';

/**
 *
 * @param {string} path a path of rumors-line-bot-logs folder
 *
 * ```
 * rumors-line-bot-logs $ tree
 * .
 * ├── 201705
 * │   ├── 23
 * │   │   ├── 00
 * │   │   │   ├── 0009.70036095121560.log
 * │   │   │   ├── 0021.70036095121560.log
 * │   │   │   ├── 0035.70036095121560.log
 * │   │   │   ├── 0058.70036095121560.log
 * │   │   │   ├── 0114.70036095121560.log
 * │   │   │   ├── 0125.70036095121560.log
 * │   │   │   ├── 0200.70036095121560.log
 * │   │   │   [...]
 * │   │   ├── 01
 * │   │   │   [...]
 * │   │   ├── 02
 * │   │   │   [...]
 * │   │   ├── 03
 * ```
 */

async function main(logFilePath) {
  const parse = async path => {
    const status = {
      processedLog: 0,
      writtenUserSettings: 0,
      writtenUserArticleLink: 0,
    };

    await parseToJson(path, async (data, next) => {
      const timestamp = new Date(data['timestamp']);
      const userId = data['userId'];
      const selectedArticleId = data['context.data.selectedArticleId'];
      const selectedReplyId = data['context.data.selectedReplyId'];

      // console.log(timestamp, userId, selectedArticleId, selectedReplyId);s
      status.processedLog++;
      if (userId) {
        await UserSettings.findOrInsertByUserId(userId);
        status.writtenUserSettings++;

        if (selectedArticleId) {
          if (selectedReplyId) {
            await UserArticleLink.createOrUpdateByUserIdAndArticleId(
              userId,
              selectedArticleId,
              {
                lastViewedAt: timestamp,
              }
            );
            status.writtenUserArticleLink++;
          } else {
            await UserArticleLink.createOrUpdateByUserIdAndArticleId(
              userId,
              selectedArticleId,
              {
                lastViewedAt: timestamp,
              }
            );
            status.writtenUserArticleLink++;
          }
        }
      }

      if (status.processedLog % 1000 === 0) {
        console.log(status);
      }

      next();
    });

    console.log(status);
  };

  for (let y = 2017; y <= 2020; y++) {
    for (let m = 1; m <= 12; m++) {
      const path = `${logFilePath}/${y}${Math.floor(m / 10)}${m % 10}/**/*.log`;
      console.log(path);
      await parse(path);
    }
  }
}

if (require.main === module) {
  const path = '../rumors-line-bot-logs';
  main(path)
    .then(console.log)
    .catch(console.error);
}
<commit_msg>Remove useless branch<commit_after>import UserSettings from './models/userSettings';
import UserArticleLink from './models/userArticleLink';
import { parseToJson } from '@cofacts/line-bot-log-parser';

/**
 *
 * @param {string} path a path of rumors-line-bot-logs folder
 *
 * ```
 * rumors-line-bot-logs $ tree
 * .
 * ├── 201705
 * │   ├── 23
 * │   │   ├── 00
 * │   │   │   ├── 0009.70036095121560.log
 * │   │   │   ├── 0021.70036095121560.log
 * │   │   │   ├── 0035.70036095121560.log
 * │   │   │   ├── 0058.70036095121560.log
 * │   │   │   ├── 0114.70036095121560.log
 * │   │   │   ├── 0125.70036095121560.log
 * │   │   │   ├── 0200.70036095121560.log
 * │   │   │   [...]
 * │   │   ├── 01
 * │   │   │   [...]
 * │   │   ├── 02
 * │   │   │   [...]
 * │   │   ├── 03
 * ```
 */

async function main(logFilePath) {
  const parse = async path => {
    const status = {
      processedLog: 0,
      writtenUserSettings: 0,
      writtenUserArticleLink: 0,
    };

    await parseToJson(path, async (data, next) => {
      const timestamp = new Date(data['timestamp']);
      const userId = data['userId'];
      const selectedArticleId = data['context.data.selectedArticleId'];
      const selectedReplyId = data['context.data.selectedReplyId'];

      // console.log(timestamp, userId, selectedArticleId, selectedReplyId);s
      status.processedLog++;
      if (userId) {
        await UserSettings.findOrInsertByUserId(userId);
        status.writtenUserSettings++;

        if (selectedArticleId) {
          await UserArticleLink.createOrUpdateByUserIdAndArticleId(
            userId,
            selectedArticleId,
            {
              lastViewedAt: timestamp,
            }
          );
          status.writtenUserArticleLink++;
        }
      }

      if (status.processedLog % 1000 === 0) {
        console.log(status);
      }

      next();
    });

    console.log(status);
  };

  for (let y = 2017; y <= 2020; y++) {
    for (let m = 1; m <= 12; m++) {
      const path = `${logFilePath}/${y}${Math.floor(m / 10)}${m % 10}/**/*.log`;
      console.log(path);
      await parse(path);
    }
  }
}

if (require.main === module) {
  const path = '../rumors-line-bot-logs';
  main(path)
    .then(console.log)
    .catch(console.error);
}
<|endoftext|>