<commit_before>import React, { Component, Children, PropTypes } from 'react'
import { Textfield, Menu, Icon } from 'react-mdl'
import classnames from 'classnames'

import './SelectField.scss'

import Option from '../Option/Option'

export default class SelectField extends Component {

  static propTypes = {
    className: PropTypes.string,
    floatingLabel: PropTypes.bool,
    label: PropTypes.string.isRequired,
    value: PropTypes.any,
    error: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
    multiple: PropTypes.bool,
    editable: PropTypes.bool,
    skipValues: PropTypes.array,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    onChange: PropTypes.func,
    children: PropTypes.arrayOf(PropTypes.element).isRequired,
  }

  static defaultProps = {
    editable: false,
    multiple: false,
    skipValues: [],
  }

  constructor(props) {
    super(props)

    if (props.readOnly && props.editable) {
      throw new Error('MultiSelectField cannot be both "editable" and "readOnly"!')
    }

    this.state = {
      value: null,
      inputValue: '',
      focused: false,
    }

    // generate selectfield id
    this.id = `mdl-selectfield-${selectFieldIndex}`
    selectFieldIndex++

    // override material menu if needed
    // this needs to be done in the constructor
    // otherwise menu does not work properly
    if (!overrideApplied) applyOverride()

    this.showMenu = this.showMenu.bind(this)
    this.hideMenu = this.hideMenu.bind(this)
    this.onMenuItemClick = this.onMenuItemClick.bind(this)
    this.onTextfieldFocus = this.onTextfieldFocus.bind(this)
    this.onTextfieldBlur = this.onTextfieldBlur.bind(this)
    this.onTextfieldChange = this.onTextfieldChange.bind(this)
    this.onTextfieldKeyDown = this.onTextfieldKeyDown.bind(this)
  }

  componentWillMount() {
    const { value, multiple, children } = this.props
    if (value && !multiple) {
      Children.forEach(children, child => {
        if (child.props.value === value) {
          this.setState({
            value: child.props.value,
            inputValue: child.props.children || '',
          })
        }
      })
    }
  }

  getInputNode() {
    return this.input.refs.input
  }

  getMenu() {
    return this.getMenuNode().MaterialMenu
  }

  getMenuNode() {
    if (!this.menuNode) {
      this.menuNode = document.querySelectorAll(`[data-mdl-for="${this.id}"]`)[0]
    }
    return this.menuNode
  }

  menuVisible() {
    return hasClass(this.getMenuNode().parentNode, 'is-visible')
  }

  showMenu() {
    const menu = this.getMenu()
    if (menuOpenCurrent && menu !== menuOpenCurrent) {
      menuOpenCurrent.hide()
      menuOpenCurrent = null
    }
    if (!this.menuVisible()) {
      menu.show()
      menuOpenCurrent = menu
    }
  }

  hideMenu() {
    this.getMenu().hide()
    menuOpenCurrent = false
  }

  focusMenu() {
    this.getMenu().element_.children[0].focus()
  }

  fixMenuHeight() {
    // TODO: find a better solution or implement boundaries
    const node = this.getMenuNode()
    const box = node.getBoundingClientRect()
    const width = box.width
    const height = box.height > 250 ? 250 : box.height
    node.style.clip = `rect(0 ${width}px ${height}px 0)`
    node.parentNode.style.height = `${height}px`
    node.previousSibling.style.height = `${height}px`
  }

  onMenuItemClick(child) {
    const { multiple } = this.props
    const { value, children } = child.props
    const inputValue = value ? children || '' : ''
    if (multiple || value !== this.state.value) {
      this.setState({ value, inputValue })
      if (this.props.onChange) this.props.onChange(value, inputValue)
    }
    this.hideMenu()
  }

  onTextfieldFocus(e) {
    this.showMenu()
    this.setState({ focused: true })
    if (this.props.onFocus) this.props.onFocus(e)
  }

  onTextfieldBlur(e) {
    this.setState({ focused: false })
    if (this.props.onBlur) this.props.onBlur(e)
  }

  onTextfieldChange(e) {
    const newValue = e.target.value
    this.setState({ value: null, inputValue: newValue }, this.fixMenuHeight)
  }

  onTextfieldKeyDown(e) {
    const TAB = 9
    //const ENTER = 13
    const ESCAPE = 27
    //const DOWN_ARROW = 40

    switch (e.which) {
      case TAB:
        this.hideMenu()
        break
      case ESCAPE:
        this.getInputNode().blur()
        this.hideMenu()
        break
    }
  }

  getChildren() {
    const { editable, skipValues } = this.props
    const { value, inputValue } = this.state
    let children = Children.toArray(this.props.children)
    // needed for multiselect
    if (skipValues.length) {
      children = children.filter(child => skipValues.indexOf(child.props.value) === -1)
      // no more children
      if (!children.length) {
        return [<Option value={''} disabled>No values</Option>]
      }
    }
    // return all
    if (value || !editable || !inputValue) {
      return children
    }
    // filter children
    const re = new RegExp(inputValue, 'gi');
    return children.filter(child => child.props.children.match(re))
  }

  render() {
    const {
      floatingLabel, className, label,
      error, multiple, readOnly, editable,
    } = this.props

    const {
      value, inputValue, focused,
    } = this.state

    const children = this.getChildren()

    const mainClass = classnames({
      'mdl-selectfield': true,
      'mdl-selectfield--editable': editable,
      'mdl-selectfield--error': error,
    }, className)

    const inputProps = {
      id: this.id,
      className: menuSkipForClass,
      type: 'text',
      value: !multiple ? inputValue : '',
      error,
      label,
      floatingLabel,
      readOnly: !editable,
      ref: ref => this.input = ref,
    }

    if (!readOnly) {
      inputProps.onFocus = this.onTextfieldFocus
      inputProps.onBlur = this.onTextfieldBlur
      inputProps.onChange = this.onTextfieldChange
      inputProps.onKeyDown = this.onTextfieldKeyDown
    }

    return (

        <Textfield {...inputProps}/>

        {!readOnly &&
          <Icon
            className={'mdl-selectfield__arrow'}
            name={`arrow_drop_${focused ? 'up' : 'down'}`}
            onClick={this.showMenu}
          />}

        {!readOnly &&
          <Menu target={this.id} ripple>
            {Children.map(children, child => {
              const className = classnames({
                'mdl-menu__item--selected': !multiple && child.props.value === value,
                'mdl-menu__item--disabled': child.props.disabled,
              })
              return React.cloneElement(child, {
                className,
                onClick: () => this.onMenuItemClick(child),
              })
            })}
          </Menu>}

    )
  }

}

/**
 * MDL v1 is hard to extend with react ...
 */

/**
 * Increment selectfield id for automatic menu target
 *
 * @type {Number}
 */
let selectFieldIndex = 0

/**
 * Has override been applied
 *
 * @type {Boolean}
 */
let overrideApplied = false

/**
 * Currently open menu
 *
 * @type {Boolean|String}
 */
let menuOpenCurrent = false

/**
 * Skip menu for click class
 *
 * @type {String}
 */
const menuSkipForClass = 'mdl-menu--skip-for-click'

/**
 * Check if element has class
 *
 * @param  {HTMLElement} node
 * @param  {String}  cls
 * @return {Boolean}
 */
function hasClass(node, cls) {
    return (' ' + node.className + ' ').indexOf(' ' + cls + ' ') > -1;
}

/**
 * Override MaterialMenu
 *
 * @see https://github.com/google/material-design-lite/issues/4450#issuecomment-228093633
 */
function applyOverride() {
  overrideApplied = true
  window.MaterialMenu.prototype.handleForClick_ = function(evt) {
    // START OVERRIDE
    if (hasClass(evt.target.parentNode, menuSkipForClass)) {
      evt.stopPropagation()
      evt.preventDefault()
      return false
    }
    // END OVERRIDE
    if (this.element_ && this.forElement_) {
      var rect = this.forElement_.getBoundingClientRect();
      var forRect = this.forElement_.parentElement.getBoundingClientRect();

      if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) {
        // Do not position the menu automatically. Requires the developer to
        // manually specify position.
      } else if (this.element_.classList.contains(
          this.CssClasses_.BOTTOM_RIGHT)) {
        // Position below the "for" element, aligned to its right.
        this.container_.style.right = (forRect.right - rect.right) + 'px';
        this.container_.style.top =
            this.forElement_.offsetTop + this.forElement_.offsetHeight + 'px';
      } else if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) {
        // Position above the "for" element, aligned to its left.
        this.container_.style.left = this.forElement_.offsetLeft + 'px';
        this.container_.style.bottom = (forRect.bottom - rect.top) + 'px';
      } else if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) {
        // Position above the "for" element, aligned to its right.
        this.container_.style.right = (forRect.right - rect.right) + 'px';
        this.container_.style.bottom = (forRect.bottom - rect.top) + 'px';
      } else {
        // Default: position below the "for" element, aligned to its left.
        this.container_.style.left = this.forElement_.offsetLeft + 'px';
        this.container_.style.top =
            this.forElement_.offsetTop + this.forElement_.offsetHeight + 'px';
      }
    }

    this.toggle(evt);
  };
}
<commit_msg>fix: Add missing readOnly prop validation<commit_after>import React, { Component, Children, PropTypes } from 'react'
import { Textfield, Menu, Icon } from 'react-mdl'
import classnames from 'classnames'

import './SelectField.scss'

import Option from '../Option/Option'

export default class SelectField extends Component {

  static propTypes = {
    className: PropTypes.string,
    floatingLabel: PropTypes.bool,
    label: PropTypes.string.isRequired,
    value: PropTypes.any,
    error: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
    multiple: PropTypes.bool,
    readOnly: PropTypes.bool,
    editable: PropTypes.bool,
    skipValues: PropTypes.array,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    onChange: PropTypes.func,
    children: PropTypes.arrayOf(PropTypes.element).isRequired,
  }

  static defaultProps = {
    editable: false,
    multiple: false,
    skipValues: [],
  }

  constructor(props) {
    super(props)

    if (props.readOnly && props.editable) {
      throw new Error('MultiSelectField cannot be both "editable" and "readOnly"!')
    }

    this.state = {
      value: null,
      inputValue: '',
      focused: false,
    }

    // generate selectfield id
    this.id = `mdl-selectfield-${selectFieldIndex}`
    selectFieldIndex++

    // override material menu if needed
    // this needs to be done in the constructor
    // otherwise menu does not work properly
    if (!overrideApplied) applyOverride()

    this.showMenu = this.showMenu.bind(this)
    this.hideMenu = this.hideMenu.bind(this)
    this.onMenuItemClick = this.onMenuItemClick.bind(this)
    this.onTextfieldFocus = this.onTextfieldFocus.bind(this)
    this.onTextfieldBlur = this.onTextfieldBlur.bind(this)
    this.onTextfieldChange = this.onTextfieldChange.bind(this)
    this.onTextfieldKeyDown = this.onTextfieldKeyDown.bind(this)
  }

  componentWillMount() {
    const { value, multiple, children } = this.props
    if (value && !multiple) {
      Children.forEach(children, child => {
        if (child.props.value === value) {
          this.setState({
            value: child.props.value,
            inputValue: child.props.children || '',
          })
        }
      })
    }
  }

  getInputNode() {
    return this.input.refs.input
  }

  getMenu() {
    return this.getMenuNode().MaterialMenu
  }

  getMenuNode() {
    if (!this.menuNode) {
      this.menuNode = document.querySelectorAll(`[data-mdl-for="${this.id}"]`)[0]
    }
    return this.menuNode
  }

  menuVisible() {
    return hasClass(this.getMenuNode().parentNode, 'is-visible')
  }

  showMenu() {
    const menu = this.getMenu()
    if (menuOpenCurrent && menu !== menuOpenCurrent) {
      menuOpenCurrent.hide()
      menuOpenCurrent = null
    }
    if (!this.menuVisible()) {
      menu.show()
      menuOpenCurrent = menu
    }
  }

  hideMenu() {
    this.getMenu().hide()
    menuOpenCurrent = false
  }

  focusMenu() {
    this.getMenu().element_.children[0].focus()
  }

  fixMenuHeight() {
    // TODO: find a better solution or implement boundaries
    const node = this.getMenuNode()
    const box = node.getBoundingClientRect()
    const width = box.width
    const height = box.height > 250 ? 250 : box.height
    node.style.clip = `rect(0 ${width}px ${height}px 0)`
    node.parentNode.style.height = `${height}px`
    node.previousSibling.style.height = `${height}px`
  }

  onMenuItemClick(child) {
    const { multiple } = this.props
    const { value, children } = child.props
    const inputValue = value ? children || '' : ''
    if (multiple || value !== this.state.value) {
      this.setState({ value, inputValue })
      if (this.props.onChange) this.props.onChange(value, inputValue)
    }
    this.hideMenu()
  }

  onTextfieldFocus(e) {
    this.showMenu()
    this.setState({ focused: true })
    if (this.props.onFocus) this.props.onFocus(e)
  }

  onTextfieldBlur(e) {
    this.setState({ focused: false })
    if (this.props.onBlur) this.props.onBlur(e)
  }

  onTextfieldChange(e) {
    const newValue = e.target.value
    this.setState({ value: null, inputValue: newValue }, this.fixMenuHeight)
  }

  onTextfieldKeyDown(e) {
    const TAB = 9
    //const ENTER = 13
    const ESCAPE = 27
    //const DOWN_ARROW = 40

    switch (e.which) {
      case TAB:
        this.hideMenu()
        break
      case ESCAPE:
        this.getInputNode().blur()
        this.hideMenu()
        break
    }
  }

  getChildren() {
    const { editable, skipValues } = this.props
    const { value, inputValue } = this.state
    let children = Children.toArray(this.props.children)
    // needed for multiselect
    if (skipValues.length) {
      children = children.filter(child => skipValues.indexOf(child.props.value) === -1)
      // no more children
      if (!children.length) {
        return [<Option value={''} disabled>No values</Option>]
      }
    }
    // return all
    if (value || !editable || !inputValue) {
      return children
    }
    // filter children
    const re = new RegExp(inputValue, 'gi');
    return children.filter(child => child.props.children.match(re))
  }

  render() {
    const {
      floatingLabel, className, label,
      error, multiple, readOnly, editable,
    } = this.props

    const {
      value, inputValue, focused,
    } = this.state

    const children = this.getChildren()

    const mainClass = classnames({
      'mdl-selectfield': true,
      'mdl-selectfield--editable': editable,
      'mdl-selectfield--error': error,
    }, className)

    const inputProps = {
      id: this.id,
      className: menuSkipForClass,
      type: 'text',
      value: !multiple ? inputValue : '',
      error,
      label,
      floatingLabel,
      readOnly: !editable,
      ref: ref => this.input = ref,
    }

    if (!readOnly) {
      inputProps.onFocus = this.onTextfieldFocus
      inputProps.onBlur = this.onTextfieldBlur
      inputProps.onChange = this.onTextfieldChange
      inputProps.onKeyDown = this.onTextfieldKeyDown
    }

    return (

        <Textfield {...inputProps}/>

        {!readOnly &&
          <Icon
            className={'mdl-selectfield__arrow'}
            name={`arrow_drop_${focused ? 'up' : 'down'}`}
            onClick={this.showMenu}
          />}

        {!readOnly &&
          <Menu target={this.id} ripple>
            {Children.map(children, child => {
              const className = classnames({
                'mdl-menu__item--selected': !multiple && child.props.value === value,
                'mdl-menu__item--disabled': child.props.disabled,
              })
              return React.cloneElement(child, {
                className,
                onClick: () => this.onMenuItemClick(child),
              })
            })}
          </Menu>}

    )
  }

}

/**
 * MDL v1 is hard to extend with react ...
 */

/**
 * Increment selectfield id for automatic menu target
 *
 * @type {Number}
 */
let selectFieldIndex = 0

/**
 * Has override been applied
 *
 * @type {Boolean}
 */
let overrideApplied = false

/**
 * Currently open menu
 *
 * @type {Boolean|String}
 */
let menuOpenCurrent = false

/**
 * Skip menu for click class
 *
 * @type {String}
 */
const menuSkipForClass = 'mdl-menu--skip-for-click'

/**
 * Check if element has class
 *
 * @param  {HTMLElement} node
 * @param  {String}  cls
 * @return {Boolean}
 */
function hasClass(node, cls) {
    return (' ' + node.className + ' ').indexOf(' ' + cls + ' ') > -1;
}

/**
 * Override MaterialMenu
 *
 * @see https://github.com/google/material-design-lite/issues/4450#issuecomment-228093633
 */
function applyOverride() {
  overrideApplied = true
  window.MaterialMenu.prototype.handleForClick_ = function(evt) {
    // START OVERRIDE
    if (hasClass(evt.target.parentNode, menuSkipForClass)) {
      evt.stopPropagation()
      evt.preventDefault()
      return false
    }
    // END OVERRIDE
    if (this.element_ && this.forElement_) {
      var rect = this.forElement_.getBoundingClientRect();
      var forRect = this.forElement_.parentElement.getBoundingClientRect();

      if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) {
        // Do not position the menu automatically. Requires the developer to
        // manually specify position.
      } else if (this.element_.classList.contains(
          this.CssClasses_.BOTTOM_RIGHT)) {
        // Position below the "for" element, aligned to its right.
        this.container_.style.right = (forRect.right - rect.right) + 'px';
        this.container_.style.top =
            this.forElement_.offsetTop + this.forElement_.offsetHeight + 'px';
      } else if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) {
        // Position above the "for" element, aligned to its left.
        this.container_.style.left = this.forElement_.offsetLeft + 'px';
        this.container_.style.bottom = (forRect.bottom - rect.top) + 'px';
      } else if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) {
        // Position above the "for" element, aligned to its right.
        this.container_.style.right = (forRect.right - rect.right) + 'px';
        this.container_.style.bottom = (forRect.bottom - rect.top) + 'px';
      } else {
        // Default: position below the "for" element, aligned to its left.
        this.container_.style.left = this.forElement_.offsetLeft + 'px';
        this.container_.style.top =
            this.forElement_.offsetTop + this.forElement_.offsetHeight + 'px';
      }
    }

    this.toggle(evt);
  };
}
<|endoftext|>


<commit_before>/**
 * @file SpanLoading component
 * @author wendy(wendy.wei@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

class SpanLoading extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            spanning: props.spanning
        };

    }

    componentWillReceiveProps(nextProps) {

        const spanning = nextProps.spanning;
        const {delay} = this.props;

        if (spanning && delay && !isNaN(Number(delay))) {
            this.delayTimeout = setTimeout(() => this.setState({spanning}), delay);
        } else {
            this.setState({spanning});
        }

    }

    componentWillUnmount() {
        this.delayTimeout && clearTimeout(this.delayTimeout);
    }

    render() {

        const {className, style, description, size, children} = this.props,
            {spanning} = this.state,

            loadingClassName = classNames('span-loading', {
                [`span-loading-${size}`]: size,
                [className]: className
            });

        return (

                {
                    spanning ?
                        <span className={`span-loading-dot ${size ? size : ''}`}>

                        :
                        null

                }

                {children}

                {
                    description ?
                        <div className={`span-loading-text`}>{description}

                        :
                        null
                }

        );
    }
}

SpanLoading.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * If true,will show a span loading animation.
     */
    spanning: PropTypes.bool,

    /**
     * Set the tip text,there will be a description under the loading.
     */
    tip: PropTypes.string,

    /**
     * Set the size of loading,can use small or large.
     */
    size: PropTypes.string,

    /**
     * Set the delay time of loading animation.
     */
    delay: PropTypes.number
};

SpanLoading.defaultProps = {

    className: '',
    style: null,

    spanning: true,
    tip: '',
    type: ''

};

export default SpanLoading;<commit_msg>update SpanLoading<commit_after>/**
 * @file SpanLoading component
 * @author wendy(wendy.wei@derbysoft.com)
 */

import React, {Component} from 'react';
import classNames from 'classnames';

import PureRender from '../_vendors/PureRender';

@PureRender
class SpanLoading extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            spanning: props.spanning
        };

    }

    componentWillReceiveProps(nextProps) {

        const spanning = nextProps.spanning;
        const {delay} = this.props;

        if (spanning && delay && !isNaN(Number(delay))) {
            this.delayTimeout = setTimeout(() => this.setState({spanning}), delay);
        } else {
            this.setState({spanning});
        }

    }

    componentWillUnmount() {
        this.delayTimeout && clearTimeout(this.delayTimeout);
    }

    render() {

        const {className, style, description, size, children} = this.props,
            {spanning} = this.state,

            loadingClassName = classNames('span-loading', {
                [`span-loading-${size}`]: size,
                [className]: className
            });

        return (

                {
                    spanning ?
                        <span className={`span-loading-dot ${size ? size : ''}`}>

                        :
                        null

                }

                {children}

                {
                    description ?
                        <div className={`span-loading-text`}>{description}

                        :
                        null
                }

        );
    }
}

if (process.env.NODE_ENV === 'development') {

    const PropTypes = require('prop-types');

    SpanLoading.propTypes = {

        /**
         * The CSS class name of the root element.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the root element.
         */
        style: PropTypes.object,

        /**
         * If true,will show a span loading animation.
         */
        spanning: PropTypes.bool,

        /**
         * Set the tip text,there will be a description under the loading.
         */
        tip: PropTypes.string,

        /**
         * Set the size of loading,can use small or large.
         */
        size: PropTypes.string,

        /**
         * Set the delay time of loading animation.
         */
        delay: PropTypes.number

    };

}

SpanLoading.defaultProps = {
    spanning: true,
    tip: '',
    type: ''
};

export default SpanLoading;<|endoftext|>


<commit_before>/* Copyright 2015 IBM Corporation

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. */

var express = require('express');
var router = express.Router();
var config = require('../config/server');
var parseString = require('xml2js').parseString;
var request = require('request');

/* GET home page. */
router.get('/', function(req, res, next) {
  res.redirect('/');
});

//getfeed for home page content
router.get('/feed', function(req, res, next){
  if(!req.user)
    res.redirect('/');

  //config.server.domain is the domain name of the server (without the https or the directoy i.e example.com)

  var url = 'https://' + config.server.domain + '/files/oauth/api/documents/feed?visibility=public&includeTags=true';

  //if query parameters exist, append them onto the url
  if(!isEmpty(req.query.q)){
    url = url + '?tag=' + req.query.q;
  }

  var headers = {};

  // we must attach the key we got through passportto the header as
  // Authorization: Bearer + key. Passport gives us access to the user profile
  // we saved through the request user object
  headers['Authorization'] = 'Bearer ' + req.user.accessToken;

  var options = {
    url: url,
    headers: headers
  };

  request.get(options, function(error, response, body){

    // if there is an error lets log it to the console and inform the angular
    // of our app so it can be handled
    if(error){
      console.log('Error occured while getting feed from Connections Cloud');
      res.send(error);
    } else {

      // otherwise, the api returns an xml which can be easily converted to a
      // JSON to make parsing easier using the xml2js module for nodejs
      parseString(body, function(err, result){

        // initialize the array of photos we will be sending back
        var photos = [];

        // get the actual entries object in the response
        var entries = result.feed.entry;

        // iterate over the entries to send back each photo that was returned
        for(var i = 0; i < entries.length; i++){
          var photo = {};
          var entry = entries[i];

          // the photo id which is used to reference the photo internally for
          // ibm connection cloud, this will need to be stored to quickly
          // get the photo and information on the photo later
          photo.id = entry['td:uuid'][0];

          // iterate through the tags in the entry and build an object that has
          // all the tags, starting at 1 because the first category describes
          // the document and is not a true 'tag'
          var tags = [];
          for(var j = 1; j < entry.category.length; j ++){
            var category = entry.category[j];
            var tag = category.$.label;
            tags.push(tag);
          }
          photo.tags = tags;

          // the author of the file, and in our case the photographer
          photo.photographer = entry.author[0].name[0];

          // the title of the document
          photo.title = entry.title['_'];

          // the upload date of the document
          photo.published = entry.published[0];

          // the link object contains many links related to the document,
          // however we want the link to the actual image, therefore we will
          // look for the object with the type of image
          for(var j = 0; j < entry.link.length; j++){
            var link = entry.link[j];
            var type = link.$.type;
            if(!(type === undefined) && (type.indexOf('image') > -1)){
              photo.link = link.$.href;
              break;
            }
          }

          // push the photo to our photos array
          console.log('pushing :' + JSON.stringify(photo));
          photos.push(photo);
        }

        //return our photos array
        console.log('sending response');
        res.send(photos);
      });
    }
  });
});

//get photo for retrieving a photo by id
router.get('/photo', function(req, res, next){
  if(!req.user)
    res.redirect('/');

  //if no id was passed, return an error code
  if(isEmpty(req.query.id)){
    res.status(412).end();
  } else {
      var url = 'https://' + server.domain + '/files/oauth/api/myuserlibrary/document/' + req.query.id + '/media';

      // we must attach the key we got through passportto the header as
      // Authorization: Bearer + key. Passport gives us access to the user profile
      // we saved through the request user object
      var headers = {'Authorization': 'Bearer ' + req.user.accessToken};

      var options = {
        url: url,
        headers: headers
      };

      request.get(options, function(error, response, body){
        if(error){
          res.send(error);
        } else {

        }
      });
  }

});

//get a file likes
router.get('/like', function(req, res, next){
  if(!req.user)
    res.redirect('/');

  //if no id was passed
  if(isEmpty(req.query.id)){
    res.status(412).end();
  } else {
    var url = 'https://' + config.server.domain + 'files/ouath/api/myuserlibrary/document/' + req.query.id + '/entry';

    var headers = {'Authorization': 'Bearer ' + req.user.accessToken};

    var options = {
      url: url,
      headers: headers
    };

    request.get(options, function(error, response, body){
      if(error){
        res.send(error);
      } else {
        parseString(body, function(err, result){
          console.log(result);
        });
      }
    });
  }
});

router.post('/like', function(req, res, next){
  if(!req.user)
    res.redirect('/');

  if(isEmpty(req.query.id)){
    req.status(412).end();
  } else {

  }
})

router.get('/commments', function(req, res, next){
  if(!req.user)
    res.redirect('/');

  //if no id was passed
  if(isEmpty(req.query.id)){
    res.status(412).end();
  } else if(isEmpty(req.query.userid)){
    res.status(412).end();
  } else {
    var url = 'https://' + config.server.domain + 'files/oauth/api/userlibrary/' + req.query.userid + '/document/' + req.query.id + '/feed';

    var headers = {'Authorization': 'Bearer ' + req.user.accessToken};

    var options = {
      url: url,
      headers: headers
    };

    request.get(options, function(error, response, body){
      if(error){
        res.send(error);
      } else {
        res.send(body);
      }
    });
  }
});

//upload a file
router.post('/upload', function(req, res, next){

  var url = 'https://' + config.server.domain + '/files/oauth/api/nonce';

  var headers = {'Authorization': 'Bearer ' + req.user.accessToken};

  var options = {
    url: url,
    headers: headers
  };

  request.get(options, function(error, response, body){
    if(error){
      res.send(error);
    } else {
      var nonce = body;
      var busboy = new Busyboy({headers: req.headers});

      busboy.on('file', function(fieldname, file, filename, encoding, mimetype){
        var url = 'https://' + server.domain + '/files/oauth/api/myuserlibrary/feed';
        var headers = {
          'Authorization': 'Bearer ' + req.user.accessToken,
          'Slug': filename,
          'X-Update-Nonce': nonce
        };

        var options = {
          url: url,
          headers: headers
        };

        file.pipe(request.post(options, function(error, response, body){
          if(error){
            res.send(error);
          }
        }));

      });

      busboy.on('finish', function(){
        res.status(200).end();
      });
    }
  });
});

var hasOwnProperty = Object.prototype.hasOwnProperty;

function isEmpty(obj) {

    // null and undefined are "empty"
    if (obj == null) return true;

    // Assume if it has a length property with a non-zero value
    // that that property is correct.
    if (obj.length > 0)    return false;
    if (obj.length === 0)  return true;

    // Otherwise, does it have any properties of its own?
    // Note that this doesn't handle
    // toString and valueOf enumeration bugs in IE < 9
    for (var key in obj) {
        if (hasOwnProperty.call(obj, key)) return false;
    }

    return true;
}

module.exports = router;
<commit_msg>cleaned up the upload route and added comments<commit_after>/* Copyright 2015 IBM Corporation

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. */

var express = require('express');
var router = express.Router();
var config = require('../config/server');
var parseString = require('xml2js').parseString;
var request = require('request');
var Busboy = require('busboy');

/* GET home page. */
router.get('/', function(req, res, next) {
  res.redirect('/');
});

//getfeed for home page content
router.get('/feed', function(req, res, next){
  if(!req.user)
    res.redirect('/');

  //config.server.domain is the domain name of the server (without the https or the directoy i.e example.com)

  var url = 'https://' + config.server.domain + '/files/oauth/api/documents/feed?visibility=public&includeTags=true';

  //if query parameters exist, append them onto the url
  if(!isEmpty(req.query.q)){
    url = url + '?tag=' + req.query.q;
  }

  var headers = {};

  // we must attach the key we got through passportto the header as
  // Authorization: Bearer + key. Passport gives us access to the user profile
  // we saved through the request user object
  headers['Authorization'] = 'Bearer ' + req.user.accessToken;

  var options = {
    url: url,
    headers: headers
  };

  request.get(options, function(error, response, body){

    // if there is an error lets log it to the console and inform the angular
    // of our app so it can be handled
    if(error){
      console.log('Error occured while getting feed from Connections Cloud');
      res.send(error);
    } else {

      // otherwise, the api returns an xml which can be easily converted to a
      // JSON to make parsing easier using the xml2js module for nodejs
      parseString(body, function(err, result){

        // initialize the array of photos we will be sending back
        var photos = [];

        // get the actual entries object in the response
        var entries = result.feed.entry;

        // iterate over the entries to send back each photo that was returned
        for(var i = 0; i < entries.length; i++){
          var photo = {};
          var entry = entries[i];

          // the photo id which is used to reference the photo internally for
          // ibm connection cloud, this will need to be stored to quickly
          // get the photo and information on the photo later
          photo.id = entry['td:uuid'][0];

          // iterate through the tags in the entry and build an object that has
          // all the tags, starting at 1 because the first category describes
          // the document and is not a true 'tag'
          var tags = [];
          for(var j = 1; j < entry.category.length; j ++){
            var category = entry.category[j];
            var tag = category.$.label;
            tags.push(tag);
          }
          photo.tags = tags;

          // the author of the file, and in our case the photographer
          photo.photographer = entry.author[0].name[0];

          // the title of the document
          photo.title = entry.title['_'];

          // the upload date of the document
          photo.published = entry.published[0];

          // the link object contains many links related to the document,
          // however we want the link to the actual image, therefore we will
          // look for the object with the type of image
          for(var j = 0; j < entry.link.length; j++){
            var link = entry.link[j];
            var type = link.$.type;
            if(!(type === undefined) && (type.indexOf('image') > -1)){
              photo.link = link.$.href;
              break;
            }
          }

          // push the photo to our photos array
          console.log('pushing :' + JSON.stringify(photo));
          photos.push(photo);
        }

        //return our photos array
        console.log('sending response');
        res.send(photos);
      });
    }
  });
});

//get photo for retrieving a photo by id
router.get('/photo', function(req, res, next){
  if(!req.user)
    res.redirect('/');

  //if no id was passed, return an error code
  if(isEmpty(req.query.id)){
    res.status(412).end();
  } else {
      var url = 'https://' + server.domain + '/files/oauth/api/myuserlibrary/document/' + req.query.id + '/media';

      // we must attach the key we got through passportto the header as
      // Authorization: Bearer + key. Passport gives us access to the user profile
      // we saved through the request user object
      var headers = {'Authorization': 'Bearer ' + req.user.accessToken};

      var options = {
        url: url,
        headers: headers
      };

      request.get(options, function(error, response, body){
        if(error){
          res.send(error);
        } else {

        }
      });
  }

});

//get a file likes
router.get('/like', function(req, res, next){
  if(!req.user)
    res.redirect('/');

  //if no id was passed
  if(isEmpty(req.query.id)){
    res.status(412).end();
  } else {
    var url = 'https://' + config.server.domain + 'files/ouath/api/myuserlibrary/document/' + req.query.id + '/entry';

    var headers = {'Authorization': 'Bearer ' + req.user.accessToken};

    var options = {
      url: url,
      headers: headers
    };

    request.get(options, function(error, response, body){
      if(error){
        res.send(error);
      } else {
        parseString(body, function(err, result){
          console.log(result);
        });
      }
    });
  }
});

router.post('/like', function(req, res, next){
  if(!req.user)
    res.status(403).end();

  if(isEmpty(req.query.id)){
    req.status(412).end();
  } else {

  }
})

router.get('/commments', function(req, res, next){
  if(!req.user)
    res.redirect('/');

  //if no id was passed
  if(isEmpty(req.query.id)){
    res.status(412).end();
  } else if(isEmpty(req.query.userid)){
    res.status(412).end();
  } else {
    var url = 'https://' + config.server.domain + 'files/oauth/api/userlibrary/' + req.query.userid + '/document/' + req.query.id + '/feed';

    var headers = {'Authorization': 'Bearer ' + req.user.accessToken};

    var options = {
      url: url,
      headers: headers
    };

    request.get(options, function(error, response, body){
      if(error){
        res.send(error);
      } else {
        res.send(body);
      }
    });
  }
});

//upload a file
router.post('/upload', function(req, res, next){
  // if the user does not exist, send back forbidden
  if(!req.user)
    res.status(403).end()

  // before uploading, we must obtain a nonce, which is a handshake between
  // the api and our server to allow us to post to the server
  var url = 'https://' + config.server.domain + '/files/oauth/api/nonce';

  var headers = {'Authorization': 'Bearer ' + req.user.accessToken};

  var options = {
    url: url,
    headers: headers
  };

  // making the nonce request
  request.get(options, function(error, response, body){

    // if there was an error log the error and send back an error
    if(error){
      console.log('nonce failed: ' + error);
      res.status(500).end()
    } else {

      // the nonce is returned in the body of the response
      var nonce = body;

      // to obtain the file from the client, we use a module called busboy
      // that allows us to obtain the file stream from the client
      var busboy = new Busboy({headers: req.headers});

      // when busboy encounters a file (which should be the only thing it
      // obtains from the page) it will then pip the file to a request to the
      // api server
      busboy.on('file', function(fieldname, file, filename, encoding, mimetype){
        var url = 'https://' + server.domain + '/files/oauth/api/myuserlibrary/feed';

        // the slug is used to tell the api what it should call the file
        var slug = filename;

        var headers = {
          'Authorization': 'Bearer ' + req.user.accessToken,
          'Slug': slug,
          //the nonce is the nonce we obtained before
          'X-Update-Nonce': nonce
        };

        var options = {
          url: url,
          headers: headers
        };

        // we then pipe the file to the request to the api server
        file.pipe(request.post(options, function(error, response, body){

          // if we recieve an error then log it and send and erro back to the
          // client
          if(error){
            console.log('upload failed: ' + error);
            res.status(500).end();
          }
        }));

      });

      // when the busboy finishes processing the file, send back an OK status
      // and close the connection
      busboy.on('finish', function(){
        res.status(200).end();
      });
    }
  });
});

var hasOwnProperty = Object.prototype.hasOwnProperty;

function isEmpty(obj) {

    // null and undefined are "empty"
    if (obj == null) return true;

    // Assume if it has a length property with a non-zero value
    // that that property is correct.
    if (obj.length > 0)    return false;
    if (obj.length === 0)  return true;

    // Otherwise, does it have any properties of its own?
    // Note that this doesn't handle
    // toString and valueOf enumeration bugs in IE < 9
    for (var key in obj) {
        if (hasOwnProperty.call(obj, key)) return false;
    }

    return true;
}

module.exports = router;
<|endoftext|>


<commit_before>'use strict';

const mongoose = requireLocal('controller/mongo.js');
const fs = require('fs');
const path = require('path');
const renderer = requireLocal('services/renderer');
const fileSystem = requireLocal('services/file-system');
const multer = require('multer');
const adminAuth = requireLocal('controller/admin-auth');
const api = requireLocal('controller/api-proxy');

const express = require('express');
const reader = requireLocal('services/template-reader.js');
const router = express.Router();

const models = {
  view: mongoose.model('view', requireLocal('schemas/view.js')),
  page: mongoose.model('page', requireLocal('schemas/page.js')),
  menu: mongoose.model('menu', requireLocal('schemas/menu.js'))
};

// Creates regex string for filtering valid models
const allowedModels = '(' + Object.keys(models).reduce((p, k) => p + '|' + k, '').substr(1) + ')';

const storage = multer.diskStorage({
  destination: (req, file, callback) => {
    callback(null, './public/img/uploads');
  },

  filename: (req, file, callback) => {
    const fn = file.originalname;
    callback(null, fn + '-' + Date.now() + path.extname(fn));
  }
});
const upload = multer({ storage: storage }).single('image');

router.use(adminAuth.ensureAuthenticated);

/**
 * Reads a file path originating from / and sends it to the response
 * @param fpath Path to the file
 * @param res The HTTP response object
 * @param next
 */
function serveFile(fpath, res, next) {
  fs.access(fpath, fs.R_OK, err => err ? next(err) : res.sendFile(fpath));
}

router.post('/image', upload, (req, res) =>
  res.json({
    filePath: '/img/uploads/' + req.file.filename
  })
);

router.post('/auth/login', function(req, res) {
  api.authenticate(req.body.email, req.body.password)
    .then(() => {
      res.send({ token: adminAuth.createJWT(req.body.email) });
    })
    .catch(() => {
      return res.status(401).send({ message: 'Invalid email and/or password' });
    });
});

router.delete('/image/:filename', (req, res, next) =>
  fs.unlink('./public/img/uploads/' + req.params.filename, (err) => {
    if (err) return next(err);

    res.json({
      result: 'ok'
    });
  })
);

router.get('/getList', (req, res) =>
  res.json(reader.getAll())
);

router.get('/css', (req, res, next) =>
  serveFile(path.join(global.ROOT, 'public/css/styles.min.css'), res, next)
);

router.get('/html/:name', (req, res, next) =>
  req.params.name === 'master' ?
    serveFile(fileSystem.buildMasterTemplatePath(), res, next) :
    serveFile(fileSystem.buildTemplatePath(req.params.name), res, next)
);

router.get('/:model' + allowedModels, (req, res, next) =>
  models[req.params.model].find({}).exec((err, docs) =>
    err ? next(err) : res.json(docs)
  )
);

router.get('/:model' + allowedModels + '/:id', (req, res, next) =>
  models[req.params.model].findOne({ _id: req.params.id }).exec((err, docs) =>
    err ? next(err) : res.json(docs)
  )
);

router.get('/render/:pageid', (req, res) => {
  renderer.renderAndSavePageByID(req.params.pageid);
  res.json({
    status: 'ok'
  });
});

// Specific override for POST /api/view
router.post('/view', (req, res, next) => {
  if (!req.body || !req.body.name) {
    return res.sendStatus(400);
  }

  const template = reader.getByName(req.body.name);
  if (!template) {
    return res.sendStatus(404);
  }

  const rawView = {
    templateName: template.name,
    variables: []
  };

  //FILL WITH DEFAULT VALUES
  for (let variable of template.variables) {
    variable.values = [
      { language: 'de', value: 'defaultValue' },
      { language: 'en', value: 'defaultValue' }
    ];
    rawView.variables.push(variable);
  }

  models.view.create(rawView, (err, docs) => {
    console.log(docs);
    if (err) {
      next(err);
    } else {
      res.json(docs);
    }
  });
});

router.post('/:model' + allowedModels, (req, res, next) => {
  if (!req.body) {
    res.sendStatus(400);
    return;
  }

  models[req.params.model].create(req.body, (err, docs) => {
    if (err) {
      next(err);
    } else {
      res.json(docs);
    }
  });

});

router.post('/:model' + allowedModels + '/:id', (req, res, next) => {
  if (!req.body) {
    res.sendStatus(400);
    return;
  }

  models[req.params.model]
    .findOneAndUpdate({ _id: req.params.id }, req.body, { new: true }, (err, doc) => {
      if (err) {
        next(err);
      } else {
        res.json(doc);
      }
    });
});

router.delete('/:model' + allowedModels + '/:id', (req, res, next) => {
  models[req.params.model].findOneAndRemove({ _id: req.params.id }, (err, doc) => {
    if (err) {
      next(err);
    } else {
      res.json(doc);
    }
  });
});

module.exports = router;
<commit_msg>Fix CORS needs<commit_after>'use strict';

const mongoose = requireLocal('controller/mongo.js');
const fs = require('fs');
const path = require('path');
const renderer = requireLocal('services/renderer');
const fileSystem = requireLocal('services/file-system');
const multer = require('multer');
const adminAuth = requireLocal('controller/admin-auth');
const api = requireLocal('controller/api-proxy');

const express = require('express');
const reader = requireLocal('services/template-reader.js');
const router = express.Router();

const models = {
  view: mongoose.model('view', requireLocal('schemas/view.js')),
  page: mongoose.model('page', requireLocal('schemas/page.js')),
  menu: mongoose.model('menu', requireLocal('schemas/menu.js'))
};

// Creates regex string for filtering valid models
const allowedModels = '(' + Object.keys(models).reduce((p, k) => p + '|' + k, '').substr(1) + ')';

const storage = multer.diskStorage({
  destination: (req, file, callback) => {
    callback(null, './public/img/uploads');
  },

  filename: (req, file, callback) => {
    const fn = file.originalname;
    callback(null, fn + '-' + Date.now() + path.extname(fn));
  }
});
const upload = multer({ storage: storage }).single('image');

router.use((req, res, next) => {
  res.set({
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE',
    'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
  });
  if ('OPTIONS' == req.method) {
    res.sendStatus(200);
  }
  else {
    next();
  }
});

router.post('/auth/login', function(req, res) {
  console.log(req.body);
  api.authenticate(req.body.email, req.body.password)
    .then(() => {
      res.send({ token: adminAuth.createJWT(req.body.email) });
    })
    .catch(() => {
      return res.status(401).send({ message: 'Invalid email and/or password' });
    });
});

router.use(adminAuth.ensureAuthenticated);

/**
 * Reads a file path originating from / and sends it to the response
 * @param fpath Path to the file
 * @param res The HTTP response object
 * @param next
 */
function serveFile(fpath, res, next) {
  fs.access(fpath, fs.R_OK, err => err ? next(err) : res.sendFile(fpath));
}

router.post('/image', upload, (req, res) =>
  res.json({
    filePath: '/img/uploads/' + req.file.filename
  })
);

router.delete('/image/:filename', (req, res, next) =>
  fs.unlink('./public/img/uploads/' + req.params.filename, (err) => {
    if (err) return next(err);

    res.json({
      result: 'ok'
    });
  })
);

router.get('/getList', (req, res) =>
  res.json(reader.getAll())
);

router.get('/css', (req, res, next) =>
  serveFile(path.join(global.ROOT, 'public/css/styles.min.css'), res, next)
);

router.get('/html/:name', (req, res, next) =>
  req.params.name === 'master' ?
    serveFile(fileSystem.buildMasterTemplatePath(), res, next) :
    serveFile(fileSystem.buildTemplatePath(req.params.name), res, next)
);

router.get('/:model' + allowedModels, (req, res, next) =>
  models[req.params.model].find({}).exec((err, docs) =>
    err ? next(err) : res.json(docs)
  )
);

router.get('/:model' + allowedModels + '/:id', (req, res, next) =>
  models[req.params.model].findOne({ _id: req.params.id }).exec((err, docs) =>
    err ? next(err) : res.json(docs)
  )
);

router.get('/render/:pageid', (req, res) => {
  renderer.renderAndSavePageByID(req.params.pageid);
  res.json({
    status: 'ok'
  });
});

// Specific override for POST /api/view
router.post('/view', (req, res, next) => {
  if (!req.body || !req.body.name) {
    return res.sendStatus(400);
  }

  const template = reader.getByName(req.body.name);
  if (!template) {
    return res.sendStatus(404);
  }

  const rawView = {
    templateName: template.name,
    variables: []
  };

  //FILL WITH DEFAULT VALUES
  for (let variable of template.variables) {
    variable.values = [
      { language: 'de', value: 'defaultValue' },
      { language: 'en', value: 'defaultValue' }
    ];
    rawView.variables.push(variable);
  }

  models.view.create(rawView, (err, docs) => {
    console.log(docs);
    if (err) {
      next(err);
    } else {
      res.json(docs);
    }
  });
});

router.post('/:model' + allowedModels, (req, res, next) => {
  if (!req.body) {
    res.sendStatus(400);
    return;
  }

  models[req.params.model].create(req.body, (err, docs) => {
    if (err) {
      next(err);
    } else {
      res.json(docs);
    }
  });

});

router.post('/:model' + allowedModels + '/:id', (req, res, next) => {
  if (!req.body) {
    res.sendStatus(400);
    return;
  }

  models[req.params.model]
    .findOneAndUpdate({ _id: req.params.id }, req.body, { new: true }, (err, doc) => {
      if (err) {
        next(err);
      } else {
        res.json(doc);
      }
    });
});

router.delete('/:model' + allowedModels + '/:id', (req, res, next) => {
  models[req.params.model].findOneAndRemove({ _id: req.params.id }, (err, doc) => {
    if (err) {
      next(err);
    } else {
      res.json(doc);
    }
  });
});

module.exports = router;
<|endoftext|>


<commit_before>var express = require('express');
var _ = require('lodash');
var router = express.Router();
var request = require('request');

router.get('/flights/:from/:to/:start/:end', function(req, res, next) {
	var leaveFrom = req.params.from;
	var goTo = req.params.to;
	var start = req.params.start;
	var end = req.params.end;

	var parsedBody;
	var jsonUrl = 'http://static.letsgo.woooooo.science/json.json';

	function parseBody(err, resp, body) {
		if(!err && resp.statusCode == 200) {
			parsedBody = JSON.parse(body)["airSearchRsp"];
			var sliceMap = parsedBody["sliceMap"];
			var segmentMap = parsedBody["segmentMap"];

			var segments = _.map(segmentMap, function(segment) {
				return {
					'flightID': segment.uniqueSegId,
					'arrival': segment.arrivalDateTime,
					'depart': segment.departDateTime,
					'origin': segment.origAirport,
					'dest': segment.destAirport,
					'airline': segment.marketingAirline,
					'fltno': segment.flightNumber,
					'aircraft': segment.equipmentCode,
					'duration': segment.duration
				}
			});

			var flights = _.map(sliceMap, function(slice) {

				var fullSegment = [];
				var flightduration = 0;
				for (var i = 0; i < slice.segment.length; i++) {
					var applicableSegments = _.filter(segments, {'flightID': slice.segment[i].uniqueSegId});
					fullSegment.push(applicableSegments);
					applicableSegments.forEach(function(element) {
						flightduration += element.duration;
					}, this);
				}
				return {
					'layoverTime': slice.duration - flightduration,
					'tripSegment': fullSegment
				}
			});

			//console.log(flights);

			// sliceMap.forEach(function(entry) {
			// 	var fullSegment = [];
			// 	entry["segment"].forEach(function(flight) {
			// 		fullSegment.push(segmentMap[flight.uniqueSegId]);
			// 	});
			// 	flights.push(fullSegment);
			// });
			res.json(flights);
		}
	}

	request(jsonUrl, parseBody);
});

//Query http link
//  receive JSON
//    parse usable data into js array
router.get('/hotels/:state/:city', function(req, res, next) {
	var city = req.params.city;
	var state = req.params.state;
	var searchRes = [];
	var hotel;
	var cityID;

	request('http://www.priceline.com/svcs/ac/index/hotels/'+city, function(error, response, body){
		searchRes = JSON.parse(body)["searchItems"];
		//cityID = _.pluck(_.filter(searchRes, {'stateCode': state}), 'cityID')[0];//getting dat cityID

		request('http://priceline.com/api/hotelretail/listing/v3/?cityId='+cityID+"&minStars=3&sort=2", function(error, response, body){
			searchRes = JSON.parse(body)["hotels"][0]; //first element should be cheapest hotel w/ at least 3 stars

		});
	});

});

module.exports = router;<commit_msg>getting points of interest<commit_after>var express = require('express');
var _ = require('lodash');
var router = express.Router();
var request = require('request');

router.get('/flights/:from/:to/:start/:end', function(req, res, next) {
	var leaveFrom = req.params.from;
	var goTo = req.params.to;
	var start = req.params.start;
	var end = req.params.end;

	var parsedBody;
	var jsonUrl = 'http://static.letsgo.woooooo.science/json.json';

	function parseBody(err, resp, body) {
		if(!err && resp.statusCode == 200) {
			parsedBody = JSON.parse(body)["airSearchRsp"];
			var sliceMap = parsedBody["sliceMap"];
			var segmentMap = parsedBody["segmentMap"];

			var segments = _.map(segmentMap, function(segment) {
				return {
					'flightID': segment.uniqueSegId,
					'arrival': segment.arrivalDateTime,
					'depart': segment.departDateTime,
					'origin': segment.origAirport,
					'dest': segment.destAirport,
					'airline': segment.marketingAirline,
					'fltno': segment.flightNumber,
					'aircraft': segment.equipmentCode,
					'duration': segment.duration
				}
			});

			var flights = _.map(sliceMap, function(slice) {

				var fullSegment = [];
				var flightduration = 0;
				for (var i = 0; i < slice.segment.length; i++) {
					var applicableSegments = _.filter(segments, {'flightID': slice.segment[i].uniqueSegId});
					fullSegment.push(applicableSegments);
					applicableSegments.forEach(function(element) {
						flightduration += element.duration;
					}, this);
				}
				return {
					'layoverTime': slice.duration - flightduration,
					'tripSegment': fullSegment
				}
			});

			//console.log(flights);

			// sliceMap.forEach(function(entry) {
			// 	var fullSegment = [];
			// 	entry["segment"].forEach(function(flight) {
			// 		fullSegment.push(segmentMap[flight.uniqueSegId]);
			// 	});
			// 	flights.push(fullSegment);
			// });
			res.json(flights);
		}
	}

	request(jsonUrl, parseBody);
});

//Query http link
//  receive JSON
//    parse usable data into js array
router.get('/hotels/:state/:city', function(req, res, next) {
	var city = req.params.city;
	var state = req.params.state;
	var searchRes = [];
	var hotel;
	var cityID;

	request('http://www.priceline.com/svcs/ac/index/hotels/'+city, function(error, response, body){
		searchRes = JSON.parse(body)["searchItems"];
		//cityID = _.pluck(_.filter(searchRes, {'stateCode': state}), 'cityID')[0];//getting dat cityID

		request('http://priceline.com/api/hotelretail/listing/v3/?cityId='+cityID+"&minStars=3&sort=2", function(error, response, body){
			searchRes = JSON.parse(body)["hotels"][0]; //first element should be cheapest hotel w/ at least 3 stars

		});
	});

});

router.get('/places/:loc/:query', function(req, res, next) {
	var loc = req.params.loc;
	var query = req.params.query;
	var place = [];
	var rand;

	request('https://maps.googleapis.com/maps/api/place/textsearch/json?query='+query+' in '+loc+"key="+process.env.GMAPS_KEY, function(error, response, body){
			console.log(error);
			console.log(response);
			var stuff = JSON.parse(body)["results"];
			rand = (Math.random()*25)%(stuff.length);
			console.log(stuff);
			place.put(stuff[rand]["name"]);
			place.put(stuff[rand]["formatted_address"]);
			res.send(place);
	});

});

module.exports = router;
<|endoftext|>


<commit_before>const express = require('express');
const router = express.Router();
const passport = require('passport');

const models = require('../models');

router.post('/register', passport.authenticate('local-signup'), (req, res) => {
    res.json(req.user);
});

router.post('/authenticate', passport.authenticate('local-login'), (req, res) => {
    res.json(req.user);
});

router.post('/logout', (req, res) => {
    if (!req.user) return res.status(500).json({error: true});

    req.logout();
    res.json({success: true});
});

router.get('/users', (req, res) => {
    if (!req.user) return res.status(401).end();

    models.User.find({}, {'local.username': 1, 'local.online': 1, _id: 0}, (err, users) => {
        if (err) {
            return res.status(500).json({error: true});
        }

        res.json(users);
    });
});

router.get('/user/channels', (req, res) => {
    if (!req.user) return res.status(401).end();

    models.User.findOne({'local.username': req.user}, {'local.channels': 1, _id: 0}, (err, channels) => {
        if (err) {
            return res.status(500).json({error: true});
        }

        res.json(channels);
    });
});

router.get('/channel/:name/messages', (req, res) => {
    if (!req.user) return res.status(401).end();

    models.User.findOne({'local.username': req.user, 'local.channels': req.params.name}).exec()
        .then(user => {
            if (user) {
                return models.Message.find({channel: req.params.name}).exec();
            } else {
                throw 'Not joined to channel.';
            }
        })
        .then(messages => res.json(messages))
        .then(null, error => {
            res.status(401).json({error: error});
        })
});

module.exports = router;
<commit_msg>route to check for username availability<commit_after>const express = require('express');
const router = express.Router();
const passport = require('passport');

const models = require('../models');

router.post('/register', passport.authenticate('local-signup'), (req, res) => {
    res.json(req.user);
});

router.post('/authenticate', passport.authenticate('local-login'), (req, res) => {
    res.json(req.user);
});

router.post('/logout', (req, res) => {
    if (!req.user) return res.status(500).json({error: true});

    req.logout();
    res.json({success: true});
});

router.get('/users', (req, res) => {
    if (!req.user) return res.status(401).end();

    models.User.find({}, {'local.username': 1, 'local.online': 1, _id: 0}, (err, users) => {
        if (err) {
            return res.status(500).json({error: true});
        }

        res.json(users);
    });
});

router.get('/username/:username', (req, res) => {
    req.params.username = req.params.username.toLowerCase();

    models.User.findOne({'local.username': req.params.username}, (err, user) => {
        if (err) {
            return res.status(500).json({error: true});
        }

        return res.json({alreadyInUse: user ? true : false});
    });
});

router.get('/user/channels', (req, res) => {
    if (!req.user) return res.status(401).end();

    models.User.findOne({'local.username': req.user}, {'local.channels': 1, _id: 0}, (err, channels) => {
        if (err) {
            return res.status(500).json({error: true});
        }

        res.json(channels);
    });
});

router.get('/channel/:name/messages', (req, res) => {
    if (!req.user) return res.status(401).end();

    models.User.findOne({'local.username': req.user, 'local.channels': req.params.name}).exec()
        .then(user => {
            if (user) {
                return models.Message.find({channel: req.params.name}).exec();
            } else {
                throw 'Not joined to channel.';
            }
        })
        .then(messages => res.json(messages))
        .then(null, error => {
            res.status(401).json({error: error});
        })
});

module.exports = router;
<|endoftext|>


<commit_before>'use strict';

var express = require('express');
var router = express.Router();
var extend = require('node.extend');
var request = require('request');
var lxc = require('../lxc');
var doapi = require('../doapi')();

var label2container = {};
var workers = [];

var checkBalance = function(){

};

var getFreeMem = function(ip, callback){

	return lxc.exec(
		"python3 -c \"a=`head /proc/meminfo|grep MemAvail|grep -Po '\\d+'`;t=`head /proc/meminfo|grep MemTotal|grep -Po '\\d+'`;print(round(((t-a)/t)*100, 2))\"",
		ip,
		callback
	);
};

var containerFree = function(container){
	lxc.stop(container.name, container.worker.ip);
	container.worker.usedContainer--;
	delete label2container[container.label];
};

var lxcTimeout = function(container, time){
	time = time || 900000; // 15 minutes

	if(container.hasOwnProperty('timeout')){
		clearTimeout(container.timeout);
	}

	return container.timeout = setTimeout(function(){
		containerFree(container)
		return startAll(container.worker);
	}, time);
};

var runner = function(req, res, container){
	console.log('calling runner:', container);

	var httpOptions = {
		url: 'http://' + container.worker.ip,
		headers: {
			Host: container.name
		},
		body: JSON.stringify({
			code: req.body.code
		})
	};

	return request.post(httpOptions, function(error, response, body){
		console.log('runner response:', arguments)
		body = JSON.parse(body);
		var i = -1;
		while(workers[++i].availContainers.length && workers[i].index < container.worker.index){
			containerFree(container);

			container = workers[i].availContainers.pop();
			container.usedContainer++;
		}
		body['ip'] = container.label;
		lxcTimeout(container);
		return res.json(body);

	});
};

var makeWokerObj = function(worker){
	worker.networks.v4.forEach(function(value){
		worker[value.type+'IP'] = value.ip_address;
	});
	worker.availContainers = [];
	worker.ip = worker.privateIP;
	worker.usedContainer = 0;
	return worker;
};

var getWorkers = function(){
	doapi.dropletsByTag('clworker', function(data){
		data = JSON.parse(data);
		data['droplets'].forEach(function(value){
			var workerIDX = workers.push(makeWokerObj(value)) - 1;
			workers[workerIDX].index = workerIDX;

			startWorker(workers[workerIDX]);
		});
	});
};

var getAvailContainer = function(){
	var i = -1;
	while(workers[++i].availContainers.length){
		console.log('found avail on worker:', i);
		var container = workers[i].availContainers.pop();
		label2container[container.label] = container;
		container.worker.usedContainer++;
		console.log('return container:', container);
		return container;
	}
};

var startWorker = function(worker, stopPercent){
	stopPercent = stopPercent || 80;
	getFreeMem(worker.ip, function(usedMemPercent){
		if(usedMemPercent < stopPercent ){
			var name = 'crunner-'+(Math.random()*100).toString().replace('.','');
			return lxc.startEphemeral(name, 'crunner0', worker.ip, function(data){
				if( !data.ip ) return setTimeout(startWorker(worker),0);
				console.log('started container')

				worker.availContainers.push({
					ip: data.ip,
					name: name,
					worker: worker,
					label: worker.name + ':' + name
				});
				return setTimeout(startWorker(worker, stopPercent), 0);
			});
		}else{
			console.log('using', usedMemPercent, 'percent memory, stopping container creation!', worker.availContainers.length, 'created');
		}
	});
};

getWorkers();

// router.get('/start/:name', function(req, res, next){
// 	return lxc.start(req.params.name, function(data){
// 		if(!data){
// 			return res.json({
// 				status: 500,
// 				name: req.params.name,
// 				message: data
// 			});
// 		}else{
// 			res.json({});
// 		}
// 	});
// });

// router.get('/live/:template/:name', function(req, res, next){
// 	return lxc.startEphemeral(req.params.name, req.params.template, function (data) {
// 		console.log('live', arguments);
// 		return res.json(data);
// 	});
// });

// router.get('/clone/:template/:name', function(req, res, next){
// 	return lxc.clone(req.params.name, req.params.template, function(data){
// 		console.log('clone', arguments);
// 		if( data.match(/Created container/) ){
// 			return res.json({status: 200});
// 		}else{
// 			return res.json({status: 500, message: data});
// 		}
// 	});
// });

// router.get('/destroy/:name', function(req, res, next){
// 	return lxc.destroy(req.params.name, function(data){
// 		console.log('destroy', arguments);
// 		if(data){
// 			return res.json({status: 500, message: data});
// 		}else{
// 			return res.json({status: 200});
// 		}
// 	});
// });

// router.get('/info/:name', function(req, res, next){
// 	return lxc.info(req.params.name, function(data){
// 		return res.json(data);
// 	});
// });

// router.get('/list', function(req, res, next) {
// 	return lxc.list(workers.clworker0.ip, function(data){
// 		return res.json(data);
// 	});
// });

router.get('/stop/:name', function(req, res, next){
	return lxc.stop(req.params.name, function(data){
		console.log('stop', arguments);
		if(data){
			return res.json({status: 500, name: req.params.name, message: data});
		}else{
			return res.json({status: 200});
		}
	});
});

router.get('/liststuff', function(req, res, next){
	res.json({'workers': workers})
});

router.post('/run/:ip?', function doRun(req, res, next){
	// check if server is
	console.log('hit runner!')

	var container = label2container[req.params.ip] || getAvailContainer();

	return runner(req, res, container);
});

module.exports = router;
<commit_msg>stuff<commit_after>'use strict';

var express = require('express');
var router = express.Router();
var util = require('util');
var request = require('request');
var lxc = require('../lxc');
var doapi = require('../doapi')();

var label2container = {};
var workers = [];

var checkBalance = function(){

};

var getFreeMem = function(ip, callback){

	return lxc.exec(
		"python3 -c \"a=`head /proc/meminfo|grep MemAvail|grep -Po '\\d+'`;t=`head /proc/meminfo|grep MemTotal|grep -Po '\\d+'`;print(round(((t-a)/t)*100, 2))\"",
		ip,
		callback
	);
};

var containerFree = function(container){
	lxc.stop(container.name, container.worker.ip);
	container.worker.usedContainer--;
	delete label2container[container.label];
};

var lxcTimeout = function(container, time){
	time = time || 900000; // 15 minutes

	if(container.hasOwnProperty('timeout')){
		clearTimeout(container.timeout);
	}

	return container.timeout = setTimeout(function(){
		containerFree(container)
		return startAll(container.worker);
	}, time);
};

var runner = function(req, res, container){

	var httpOptions = {
		url: 'http://' + container.worker.ip,
		headers: {
			Host: container.name
		},
		body: JSON.stringify({
			code: req.body.code
		})
	};

	return request.post(httpOptions, function(error, response, body){
		// console.log('runner response:', arguments)
		body = JSON.parse(body);
		var i = -1;
		while(workers[++i].availContainers.length && workers[i].index < container.worker.index){
			containerFree(container);

			container = workers[i].availContainers.pop();
			container.usedContainer++;
		}
		body['ip'] = container.label;
		lxcTimeout(container);
		return res.json(body);

	});
};

var makeWokerObj = function(worker){
	worker.networks.v4.forEach(function(value){
		worker[value.type+'IP'] = value.ip_address;
	});
	worker.availContainers = [];
	worker.ip = worker.privateIP;
	worker.usedContainer = 0;
	return worker;
};

var getWorkers = function(){
	doapi.dropletsByTag('clworker', function(data){
		data = JSON.parse(data);
		data['droplets'].forEach(function(value){
			var workerIDX = workers.push(makeWokerObj(value)) - 1;
			workers[workerIDX].index = workerIDX;

			startWorker(workers[workerIDX]);
		});
	});
};

var getAvailContainer = function(){
	var i = -1;
	while(workers[++i].availContainers.length){

		var container = workers[i].availContainers.pop();
		label2container[container.label] = container;
		container.worker.usedContainer++;

		return container;
	}
};

var startWorker = function(worker, stopPercent){
	stopPercent = stopPercent || 80;
	getFreeMem(worker.ip, function(usedMemPercent){
		if(usedMemPercent < stopPercent ){
			var name = 'crunner-'+(Math.random()*100).toString().replace('.','');
			return lxc.startEphemeral(name, 'crunner0', worker.ip, function(data){
				if( !data.ip ) return setTimeout(startWorker(worker),0);
				console.log('started container')

				worker.availContainers.push({
					ip: data.ip,
					name: name,
					worker: worker,
					label: worker.name + ':' + name
				});
				return setTimeout(startWorker(worker, stopPercent), 0);
			});
		}else{
			console.log('using', usedMemPercent, 'percent memory, stopping container creation!', worker.availContainers.length, 'created');
		}
	});
};

getWorkers();

// router.get('/start/:name', function(req, res, next){
// 	return lxc.start(req.params.name, function(data){
// 		if(!data){
// 			return res.json({
// 				status: 500,
// 				name: req.params.name,
// 				message: data
// 			});
// 		}else{
// 			res.json({});
// 		}
// 	});
// });

// router.get('/live/:template/:name', function(req, res, next){
// 	return lxc.startEphemeral(req.params.name, req.params.template, function (data) {
// 		console.log('live', arguments);
// 		return res.json(data);
// 	});
// });

// router.get('/clone/:template/:name', function(req, res, next){
// 	return lxc.clone(req.params.name, req.params.template, function(data){
// 		console.log('clone', arguments);
// 		if( data.match(/Created container/) ){
// 			return res.json({status: 200});
// 		}else{
// 			return res.json({status: 500, message: data});
// 		}
// 	});
// });

// router.get('/destroy/:name', function(req, res, next){
// 	return lxc.destroy(req.params.name, function(data){
// 		console.log('destroy', arguments);
// 		if(data){
// 			return res.json({status: 500, message: data});
// 		}else{
// 			return res.json({status: 200});
// 		}
// 	});
// });

// router.get('/info/:name', function(req, res, next){
// 	return lxc.info(req.params.name, function(data){
// 		return res.json(data);
// 	});
// });

// router.get('/list', function(req, res, next) {
// 	return lxc.list(workers.clworker0.ip, function(data){
// 		return res.json(data);
// 	});
// });

router.get('/stop/:name', function(req, res, next){
	return lxc.stop(req.params.name, function(data){
		console.log('stop', arguments);
		if(data){
			return res.json({status: 500, name: req.params.name, message: data});
		}else{
			return res.json({status: 200});
		}
	});
});

router.get('/liststuff', function(req, res, next){
	var obj = util.inspect(workers);
	console.log('worker inspected:', obj)
	res.send(obj);
});

router.post('/run/:ip?', function doRun(req, res, next){
	// check if server is
	console.log('hit runner!')

	var container = label2container[req.params.ip] || getAvailContainer();

	return runner(req, res, container);
});

module.exports = router;
<|endoftext|>


<commit_before>const express = require('express')
const router = express.Router()

const moment = require('moment')

const Knex = require('knex')
const knexConfig = require('../knexfile')

const knex = Knex(knexConfig[process.env.NODE_ENV || 'development'])

router.get('/', (req, res, next) => {
  res.send('At the moment, the only endpoint is /month/. You can either just visit /month/ to see the entire database or visit /month/{monthnumber} where monthnumber is between 1 (Jan) and 12 (Dec). Yeah, it\s not zero indexed ;)')
})

router.get('/month', (req, res, next) => {
  knex.select('*').from('games')
    .then((games) => {
      let releases = []

      for (let i in games) {
        let name = games[i].title
        let date = moment(`${games[i].releaseDate} GMT`)
        let developer = games[i].developer
        let publisher = games[i].publisher
        let description = games[i].description
        let gbID = games[i].gb_id

        releases.push({ gbID, name, date, description, developer, publisher })
      }

      releases.sort((a, b) => {
        return a.date - b.date
      })

      for (let i in releases) {
        releases[i].date = moment(releases[i].date).format('dddd, MMMM Do')
      }

      res.json({ releases })
    })
    .catch((err) => {
      res.send('Something broke! Let me know via Email!')
    })
})

router.get('/month/:month', (req, res, next) => {
  let month = parseInt(req.params.month)

  if (month > 0 && month < 13 && month !== "all") {
    // Months in Moment.js are zero indexed
    let monthName = moment().month(month - 1).format('MMMM')
    knex.select('*').from('games').where('releaseDate', 'LIKE', `%${monthName}%`)
      .then((games) => {
        let releases = []

        for (let i in games) {
          let name = games[i].title
          let date = moment(`${games[i].releaseDate} GMT`)
          let developer = games[i].developer
          let publisher = games[i].publisher
          let description = games[i].description
          let gbID = games[i].gb_id

          releases.push({ gbID, name, date, description, developer, publisher })
        }

        releases.sort((a, b) => {
          return a.date - b.date
        })

        for (let i in releases) {
          releases[i].date = moment(releases[i].date).format('dddd, MMMM Do')
        }

        res.json({ releases })
      })
  } else {
    res.send('That isn\'t a valid month')
  }
})

router.get('/month/all', (req, res, next) => {
  knex.select('*').from('games')
    .then((games) => {
      let releases = []

      for (let i in games) {
        let name = games[i].title
        let date = moment(`${games[i].releaseDate} GMT`)
        let developer = games[i].developer
        let publisher = games[i].publisher
        let description = games[i].description
        let gbID = games[i].gb_id

        releases.push({ gbID, name, date, description, developer, publisher })
      }

      releases.sort((a, b) => {
        return a.date - b.date
      })

      for (let i in releases) {
        releases[i].date = moment(releases[i].date).format('dddd, MMMM Do')
      }

      res.json({ releases })
    })
    .catch((err) => {
      res.send('Something broke! Let me know via Email!')
    })
})

module.exports = router
<commit_msg>Removed unneeded if condition and properly escaped a quote<commit_after>const express = require('express')
const router = express.Router()

const moment = require('moment')

const Knex = require('knex')
const knexConfig = require('../knexfile')

const knex = Knex(knexConfig[process.env.NODE_ENV || 'development'])

router.get('/', (req, res, next) => {
  res.send('At the moment, the only endpoint is /month/. You can either just visit /month/ to see the entire database or visit /month/{monthnumber} where monthnumber is between 1 (Jan) and 12 (Dec). Yeah, it\'s not zero indexed ;)')
})

router.get('/month', (req, res, next) => {
  knex.select('*').from('games')
    .then((games) => {
      let releases = []

      for (let i in games) {
        let name = games[i].title
        let date = moment(`${games[i].releaseDate} GMT`)
        let developer = games[i].developer
        let publisher = games[i].publisher
        let description = games[i].description
        let gbID = games[i].gb_id

        releases.push({ gbID, name, date, description, developer, publisher })
      }

      releases.sort((a, b) => {
        return a.date - b.date
      })

      for (let i in releases) {
        releases[i].date = moment(releases[i].date).format('dddd, MMMM Do')
      }

      res.json({ releases })
    })
    .catch((err) => {
      res.send('Something broke! Let me know via Email!')
    })
})

router.get('/month/:month', (req, res, next) => {
  let month = parseInt(req.params.month)

  if (month > 0 && month < 13) {
    // Months in Moment.js are zero indexed
    let monthName = moment().month(month - 1).format('MMMM')
    knex.select('*').from('games').where('releaseDate', 'LIKE', `%${monthName}%`)
      .then((games) => {
        let releases = []

        for (let i in games) {
          let name = games[i].title
          let date = moment(`${games[i].releaseDate} GMT`)
          let developer = games[i].developer
          let publisher = games[i].publisher
          let description = games[i].description
          let gbID = games[i].gb_id

          releases.push({ gbID, name, date, description, developer, publisher })
        }

        releases.sort((a, b) => {
          return a.date - b.date
        })

        for (let i in releases) {
          releases[i].date = moment(releases[i].date).format('dddd, MMMM Do')
        }

        res.json({ releases })
      })
  } else {
    res.send('That isn\'t a valid month')
  }
})

router.get('/month/all', (req, res, next) => {
  knex.select('*').from('games')
    .then((games) => {
      let releases = []

      for (let i in games) {
        let name = games[i].title
        let date = moment(`${games[i].releaseDate} GMT`)
        let developer = games[i].developer
        let publisher = games[i].publisher
        let description = games[i].description
        let gbID = games[i].gb_id

        releases.push({ gbID, name, date, description, developer, publisher })
      }

      releases.sort((a, b) => {
        return a.date - b.date
      })

      for (let i in releases) {
        releases[i].date = moment(releases[i].date).format('dddd, MMMM Do')
      }

      res.json({ releases })
    })
    .catch((err) => {
      res.send('Something broke! Let me know via Email!')
    })
})

module.exports = router
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * 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.
 */

var LocationProperty = FOAM({
  model_: 'Model',

  name: 'LocationProperty',

  extendsModel: 'Property',

  properties: [
    { name: 'toMemento',      defaultValue:   function(o) { return o; } },
    { name: 'fromMemento',    defaultValue:   function(o) { return o; } },
    { name: 'toURL',          defaultValueFn: function()  { return this.toMemento; } },
    { name: 'defaultMemento', defaultValue:   null }
  ]
});

var Location = FOAM({
  model_: 'Model',

  name: 'Location',

  properties: [
    {
      model_: 'LocationProperty',
      name: 'id'
    },
    {
      model_: 'LocationProperty',
      name: 'createMode',
      defaultValue: false,
      preSet: function(_, v) { return v === "false" ? false : !!v; }
    },
    {
      model_: 'LocationProperty',
      name: 'can',
      // The memento is the can# stored in the 3rd element of the choice
      // The value of 'can' is the value stored in the 1st element of the choice
      toMemento: function(c) {
        var choices = this.searchChoice.choices;
        for ( var i = 0 ; i < choices.length ; i++ )
          if ( choices[i][0] == c )
            return choices[i][2];
        return choices[1][2];
      },
      fromMemento: function(c) {
        var choices = this.searchChoice.choices;
        for ( var i = 0 ; i < choices.length ; i++ )
          if ( choices[i][2] == c ) return choices[i][0];
        return choices[1][0];
      }
    },
    {
      model_: 'LocationProperty',
      name: 'q',
      defaultValue: '',
      toURL: function(q) {
        // Replace short-names will fullnames that quickbug will understand
        return (QueryParser.parseString(q) || TRUE).partialEval().toMQL().replace(/summary:/g, '');
      }
    },
    {
      model_: 'LocationProperty',
      name: 'mode',
      defaultMemento: 'list',
      toMemento: function(mode) { return mode ? mode.label.toLowerCase() : 'list'; },
      fromMemento: function(mode) {
        var view = this.view.views[0];
        for ( var i = 1 ; i < this.view.views.length ; i++ ) {
          if ( this.view.views[i].label.toLowerCase() === mode ) return this.view.views[i];
        }
        return view;
      }
    },
    {
      model_: 'LocationProperty',
      name: 'colspec',
      preSet: function(_, a) {
        if ( a ) {
          for ( var i = 0 ; i < a.length ; i++ ) {
            var prop = this.getPropertyIC(a[i]);

            if ( prop ) {
              a[i] = prop.name;
            } else {
              a.splice(i,1);
              i--;
            }
          }
        }

        return a;
      },
      toMemento: function(properties) { return properties.join(' '); },
      fromMemento: function(colspec) { return colspec ? colspec.split(' ') : null; }
    },
    {
      model_: 'LocationProperty',
      name: 'sort',
      toMemento: function(sortOrder) { return sortOrder.toMQL(); },
      fromMemento: function(sort) {
        var ps = sort.split(' ');
        for ( var i = 0 ; i < ps.length ; i++ ) {
          var p = ps[i];
          if ( p.charAt('0') == '-' ) {
            ps[i] = DESC(QIssue.getProperty(p.substring(1)));
          } else {
            ps[i] = QIssue.getProperty(p);
          }
        }
        return ( ps.length == 1 ) ? ps[0] : CompoundComparator.apply(null, ps) ;
      }
    },
    {
      model_: 'LocationProperty',
      name: 'cells',
      defaultMemento: 'tiles'
    },
    {
      model_: 'LocationProperty',
      name: 'y',
      toMemento: function(y) { return y.name; },
      fromMemento: function(name) { return QIssue.getProperty(name); }
    },
    {
      model_: 'LocationProperty',
      name: 'x',
      toMemento: function(x) { return x.name; },
      fromMemento: function(name) { return QIssue.getProperty(name); }
    },
    {
      model_: 'LocationProperty',
      name: 'scroll',
      defaultMemento: 'Bars'
    },
    {
      model_: 'LocationProperty',
      name: 'createIssueTemplate'
    }
  ],

  methods: {
    getPropertyIC: function(propName) {
      propName = propName.toLowerCase();
      for ( var i = 0 ; i < QIssue.properties.length ; i++ ) {
        var prop = QIssue.properties[i];

        if ( prop.name.toLowerCase() === propName ) return prop;

        if ( prop.shortName.toLowerCase() === propName ) return prop;

        for ( var j = 0 ; j < prop.aliases ; j++ ) {
          if ( prop.aliases[j].toLowerCase() === propName ) return prop;
        }
      }

      return undefined;
    },

    toURL: function(browser) {
      return this.toMemento(browser, 'toURL');
    },

    fromURL: function(browser, params) {
      return this.fromMemento(browser, decodeURIComponent(params).replace(/\+/g, ' '));
    },

    toMemento: function(browser, opt_methodName) {
      var methodName = opt_methodName || 'toMemento';
      var s = '';
      var d = '';
      for ( var i = 0 ; i < this.model_.properties.length ; i++ ) {
        var prop  = this.model_.properties[i];
        var key   = prop.name;
        try {
          if ( this.hasOwnProperty(key) ) {
            var value = prop[methodName].call(browser, this[key]);
            if ( methodName === 'toURL' ) value = encodeURIComponent(value);
            s += d;
            s += key + '=' + value;
            d = '&';
          }
        } catch (x) {
        }
      }

      return s;
    },

    fromMemento: function(browser, s) {
      // Convert URL into a map
      var m = {};
      var params = s.split('&');
      for ( var i = 0 ; i < params.length ; i++ ) {
        var param    = params[i];
        var keyValue = param.match(/([^=]*)=(.*)/);
        if ( keyValue ) {
          var key      = keyValue[1];
          var value    = keyValue[2];
          m[key] = value;
        }
      }

      // Set or reset each property value
      for ( var i = 0 ; i < this.model_.properties.length ; i++ ) {
        var prop = this.model_.properties[i];
        var key  = prop.name;
        try {
          if ( m.hasOwnProperty(key) ) {
            var value = prop.fromMemento.call(browser, m[key]);
            this[key] = value;
          } else if ( prop.defaultMemento ) {
            var value = prop.fromMemento.call(browser, prop.defaultMemento);
            this[key] = value;
          } else {
            // revert to the default value, making sure to still fire a propertyChange event
            // TODO: would be better if the Object had a property reset value to do this instead
            var oldValue = this[key];
            delete this.instance_[key];
            this.propertyChange(key, oldValue, this[key]);
          }
        } catch (x) {
        }
      }

      return this;
    }
  }
});
<commit_msg>QuickBug: Temporarily disabled compound sort orders until DAO.js supports it.<commit_after>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * 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.
 */

var LocationProperty = FOAM({
  model_: 'Model',

  name: 'LocationProperty',

  extendsModel: 'Property',

  properties: [
    { name: 'toMemento',      defaultValue:   function(o) { return o; } },
    { name: 'fromMemento',    defaultValue:   function(o) { return o; } },
    { name: 'toURL',          defaultValueFn: function()  { return this.toMemento; } },
    { name: 'defaultMemento', defaultValue:   null }
  ]
});

var Location = FOAM({
  model_: 'Model',

  name: 'Location',

  properties: [
    {
      model_: 'LocationProperty',
      name: 'id'
    },
    {
      model_: 'LocationProperty',
      name: 'createMode',
      defaultValue: false,
      preSet: function(_, v) { return v === "false" ? false : !!v; }
    },
    {
      model_: 'LocationProperty',
      name: 'can',
      // The memento is the can# stored in the 3rd element of the choice
      // The value of 'can' is the value stored in the 1st element of the choice
      toMemento: function(c) {
        var choices = this.searchChoice.choices;
        for ( var i = 0 ; i < choices.length ; i++ )
          if ( choices[i][0] == c )
            return choices[i][2];
        return choices[1][2];
      },
      fromMemento: function(c) {
        var choices = this.searchChoice.choices;
        for ( var i = 0 ; i < choices.length ; i++ )
          if ( choices[i][2] == c ) return choices[i][0];
        return choices[1][0];
      }
    },
    {
      model_: 'LocationProperty',
      name: 'q',
      defaultValue: '',
      toURL: function(q) {
        // Replace short-names will fullnames that quickbug will understand
        return (QueryParser.parseString(q) || TRUE).partialEval().toMQL().replace(/summary:/g, '');
      }
    },
    {
      model_: 'LocationProperty',
      name: 'mode',
      defaultMemento: 'list',
      toMemento: function(mode) { return mode ? mode.label.toLowerCase() : 'list'; },
      fromMemento: function(mode) {
        var view = this.view.views[0];
        for ( var i = 1 ; i < this.view.views.length ; i++ ) {
          if ( this.view.views[i].label.toLowerCase() === mode ) return this.view.views[i];
        }
        return view;
      }
    },
    {
      model_: 'LocationProperty',
      name: 'colspec',
      preSet: function(_, a) {
        if ( a ) {
          for ( var i = 0 ; i < a.length ; i++ ) {
            var prop = this.getPropertyIC(a[i]);

            if ( prop ) {
              a[i] = prop.name;
            } else {
              a.splice(i,1);
              i--;
            }
          }
        }

        return a;
      },
      toMemento: function(properties) { return properties.join(' '); },
      fromMemento: function(colspec) { return colspec ? colspec.split(' ') : null; }
    },
    {
      model_: 'LocationProperty',
      name: 'sort',
      toMemento: function(sortOrder) { return sortOrder.toMQL(); },
      fromMemento: function(sort) {
        var ps = sort.split(' ');
        for ( var i = 0 ; i < ps.length ; i++ ) {
          var p = ps[i];
          if ( p.charAt('0') == '-' ) {
            ps[i] = DESC(QIssue.getProperty(p.substring(1)));
          } else {
            ps[i] = QIssue.getProperty(p);
          }
        }
        if ( ps.length != 1 ) { console.warn('TODO: implement support for CompoundComparators: ', sort); }
        return ps[0];
//        return ( ps.length == 1 ) ? ps[0] : CompoundComparator.apply(null, ps) ;
      }
    },
    {
      model_: 'LocationProperty',
      name: 'cells',
      defaultMemento: 'tiles'
    },
    {
      model_: 'LocationProperty',
      name: 'y',
      toMemento: function(y) { return y.name; },
      fromMemento: function(name) { return QIssue.getProperty(name); }
    },
    {
      model_: 'LocationProperty',
      name: 'x',
      toMemento: function(x) { return x.name; },
      fromMemento: function(name) { return QIssue.getProperty(name); }
    },
    {
      model_: 'LocationProperty',
      name: 'scroll',
      defaultMemento: 'Bars'
    },
    {
      model_: 'LocationProperty',
      name: 'createIssueTemplate'
    }
  ],

  methods: {
    getPropertyIC: function(propName) {
      propName = propName.toLowerCase();
      for ( var i = 0 ; i < QIssue.properties.length ; i++ ) {
        var prop = QIssue.properties[i];

        if ( prop.name.toLowerCase() === propName ) return prop;

        if ( prop.shortName.toLowerCase() === propName ) return prop;

        for ( var j = 0 ; j < prop.aliases ; j++ ) {
          if ( prop.aliases[j].toLowerCase() === propName ) return prop;
        }
      }

      return undefined;
    },

    toURL: function(browser) {
      return this.toMemento(browser, 'toURL');
    },

    fromURL: function(browser, params) {
      return this.fromMemento(browser, decodeURIComponent(params).replace(/\+/g, ' '));
    },

    toMemento: function(browser, opt_methodName) {
      var methodName = opt_methodName || 'toMemento';
      var s = '';
      var d = '';
      for ( var i = 0 ; i < this.model_.properties.length ; i++ ) {
        var prop  = this.model_.properties[i];
        var key   = prop.name;
        try {
          if ( this.hasOwnProperty(key) ) {
            var value = prop[methodName].call(browser, this[key]);
            if ( methodName === 'toURL' ) value = encodeURIComponent(value);
            s += d;
            s += key + '=' + value;
            d = '&';
          }
        } catch (x) {
        }
      }

      return s;
    },

    fromMemento: function(browser, s) {
      // Convert URL into a map
      var m = {};
      var params = s.split('&');
      for ( var i = 0 ; i < params.length ; i++ ) {
        var param    = params[i];
        var keyValue = param.match(/([^=]*)=(.*)/);
        if ( keyValue ) {
          var key      = keyValue[1];
          var value    = keyValue[2];
          m[key] = value;
        }
      }

      // Set or reset each property value
      for ( var i = 0 ; i < this.model_.properties.length ; i++ ) {
        var prop = this.model_.properties[i];
        var key  = prop.name;
        try {
          if ( m.hasOwnProperty(key) ) {
            var value = prop.fromMemento.call(browser, m[key]);
            this[key] = value;
          } else if ( prop.defaultMemento ) {
            var value = prop.fromMemento.call(browser, prop.defaultMemento);
            this[key] = value;
          } else {
            // revert to the default value, making sure to still fire a propertyChange event
            // TODO: would be better if the Object had a property reset value to do this instead
            var oldValue = this[key];
            delete this.instance_[key];
            this.propertyChange(key, oldValue, this[key]);
          }
        } catch (x) {
        }
      }

      return this;
    }
  }
});
<|endoftext|>