<commit_before>/* global Highcharts */

(function (Highcharts) {
    "use strict";

    var addEvent = Highcharts.addEvent;

    var isTypeSupported = function (chartType) {
        switch (chartType) {
        case "line":
        case "spline":
        case "area":
        case "areaspline":
        case "arearange":
        case "areasplinerange":
        case "column":
        case "columnrange":
        case "bar":
        case "scatter":
        case "bubble":
        case "boxplot":
        case "errorbar":
        case "waterfall":
        case "gauge":
        case "pie":
        case "funnel":
            return true;
        default:
            return false;
        }
    };

    var getItemType = function (item, series) {
        if (item.series) {
            return item.series.type;
        } else {
            return series[item.index].type;
        }
    };

    var getItemIndex = function (item, type) {
        if (item.index !== undefined) {
            return item.index;
        } else {
            return item.series.index;
        }
    };

    // Inject "onmouseenter" & "onmouseleave" event listeners into "renderItem"
    // function (used in Highcharts.Legend.prototype to render single legend label)
    // proceed - default "renderItem" function
    // item - series or point assigned to currently rendered legend label
    Highcharts.wrap(Highcharts.Legend.prototype, "renderItem", function (proceed, item) {
        // Call the default function
        proceed.apply(this, Array.prototype.slice.call(arguments, 1));

        if ((!this.chart.options.legend.highlightSeries) ||
           (this.chart.options.legend.highlightSeries.enabled !== true) ||
           (item._legendHighlightReady !== undefined))
        {
            return;
        }

        var series = this.chart.series;
        var element = item.legendGroup.element;
        var itemType = getItemType(item, series);
        var itemIndex = getItemIndex(item, itemType);
        var options = this.chart.options.legend.highlightSeries;
        var settings = {
            defaultOpacity: options.defaultOpacity ? options.defaultOpacity : 1,
            dimmedOpacity: options.dimmedOpacity ? options.dimmedOpacity : 0.25,
            dimPiePieces: options.dimPiePieces
        };

        if (!isTypeSupported(itemType)) {
            console.error("[highcharts-legend-highlight.js]: Chart type \"" +
                itemType + "\" is not supported");
            return;
        }

        // (Default events) Dim all data series except the currently hovered over one
        addEvent(element, "mouseenter", function () {
            for (var i = 0; i < series.length; ++i) {
                if (i === itemIndex) {
                    continue;
                }
                series[i].group.attr("opacity", settings.dimmedOpacity);
                series[i].markerGroup.attr("opacity", settings.dimmedOpacity);
            }
        });
        addEvent(element, "mouseleave", function () {
            for (var i = 0; i < series.length; ++i) {
                if (i === itemIndex) {
                    continue;
                }
                series[i].group.attr("opacity", settings.defaultOpacity);
                series[i].markerGroup.attr("opacity", settings.defaultOpacity);
            }
        });

        if (itemType === "pie") {
            // Slice out currently hovered over pie piece
            // Dim the other ones if "settings.dimmedOpacity" is true
            addEvent(element, "mouseenter", function () {
                for (var i = 0; i < item.series.data.length; ++i) {
                    if (item.series.data[i].sliced) {
                        item.series.data[i].slice(false, true);
                        item.series.data[i]._restoreSlice = true;
                    }
                    if (settings.dimPiePieces) {
                        item.series.data[i].graphic.attr("opacity", settings.dimmedOpacity);
                    }
                }
                item.slice(true, true);
                if (settings.dimPiePieces) {
                    item.graphic.attr("opacity", settings.defaultOpacity);
                }
            });

            addEvent(element, "mouseleave", function () {
                item.slice(false, true);
                for (var i = 0; i < item.series.data.length; ++i) {
                    if (item.series.data[i]._restoreSlice) {
                        item.series.data[i].slice(true, true);
                        item.series.data[i]._restoreSlice = undefined;
                    }
                    if (settings.dimPiePieces) {
                        item.series.data[i].graphic.attr("opacity", settings.defaultOpacity);
                    }
                }
            });
        }

        if (itemType === "funnel") {
            // Dim all data points in funnel chart except the currently hovered over one
            addEvent(element, "mouseenter", function () {
                for (var i = 0; i < item.series.data.length; ++i) {
                    if (item.series.data[i] !== item) {
                        item.series.data[i].graphic.attr("opacity", settings.dimmedOpacity);
                    }
                }
            });
            addEvent(element, "mouseleave", function () {
                for (var i = 0; i < item.series.data.length; ++i) {
                    if (item.series.data[i] !== item) {
                        item.series.data[i].graphic.attr("opacity", settings.defaultOpacity);
                    }
                }
            });
        }

        item._legendHighlightReady = true;
    });
})(Highcharts);
<commit_msg>Add support for "linkedSeries" property<commit_after>/* global Highcharts */

(function (Highcharts) {
    "use strict";

    var addEvent = Highcharts.addEvent;

    var isTypeSupported = function (chartType) {
        switch (chartType) {
        case "line":
        case "spline":
        case "area":
        case "areaspline":
        case "arearange":
        case "areasplinerange":
        case "column":
        case "columnrange":
        case "bar":
        case "scatter":
        case "bubble":
        case "boxplot":
        case "errorbar":
        case "waterfall":
        case "gauge":
        case "pie":
        case "funnel":
            return true;
        default:
            return false;
        }
    };

    var getItemType = function (item, series) {
        if (item.series) {
            return item.series.type;
        } else {
            return series[item.index].type;
        }
    };

    var getItemIndex = function (item, type) {
        if (item.index !== undefined) {
            return item.index;
        } else {
            return item.series.index;
        }
    };

    // Inject "onmouseenter" & "onmouseleave" event listeners into "renderItem"
    // function (used in Highcharts.Legend.prototype to render single legend label)
    // proceed - default "renderItem" function
    // item - series or point assigned to currently rendered legend label
    Highcharts.wrap(Highcharts.Legend.prototype, "renderItem", function (proceed, item) {
        // Call the default function
        proceed.apply(this, Array.prototype.slice.call(arguments, 1));

        if ((!this.chart.options.legend.highlightSeries) ||
           (this.chart.options.legend.highlightSeries.enabled !== true) ||
           (item._legendHighlightReady !== undefined))
        {
            return;
        }

        var series = this.chart.series;
        var element = item.legendGroup.element;
        var itemType = getItemType(item, series);
        var itemIndex = getItemIndex(item, itemType);
        var options = this.chart.options.legend.highlightSeries;
        var settings = {
            defaultOpacity: options.defaultOpacity ? options.defaultOpacity : 1,
            dimmedOpacity: options.dimmedOpacity ? options.dimmedOpacity : 0.25,
            dimPiePieces: options.dimPiePieces
        };

        if (!isTypeSupported(itemType)) {
            console.error("[highcharts-legend-highlight.js]: Chart type \"" +
                itemType + "\" is not supported");
            return;
        }

        // (Default events) Dim all data series except the currently hovered over one
        addEvent(element, "mouseenter", function () {
            var i;
            var linkedSeries = {};
            if (item.linkedSeries !== undefined) {
                for (i = 0; i < item.linkedSeries.length; ++i) {
                    linkedSeries[item.linkedSeries[i].index] = true;
                }
            }

            for (i = 0; i < series.length; ++i) {
                if (i === itemIndex || linkedSeries[i] !== undefined) {
                    continue;
                }
                series[i].group.attr("opacity", settings.dimmedOpacity);
                series[i].markerGroup.attr("opacity", settings.dimmedOpacity);
            }
        });
        addEvent(element, "mouseleave", function () {
            var i;
            var linkedSeries = {};
            if (item.linkedSeries !== undefined) {
                for (i = 0; i < item.linkedSeries.length; ++i) {
                    linkedSeries[item.linkedSeries[i].index] = true;
                }
            }

            for (i = 0; i < series.length; ++i) {
                if (i === itemIndex || linkedSeries[i] !== undefined) {
                    continue;
                }
                series[i].group.attr("opacity", settings.defaultOpacity);
                series[i].markerGroup.attr("opacity", settings.defaultOpacity);
            }
        });

        if (itemType === "pie") {
            // Slice out currently hovered over pie piece
            // Dim the other ones if "settings.dimmedOpacity" is true
            addEvent(element, "mouseenter", function () {
                for (var i = 0; i < item.series.data.length; ++i) {
                    if (item.series.data[i].sliced) {
                        item.series.data[i].slice(false, true);
                        item.series.data[i]._restoreSlice = true;
                    }
                    if (settings.dimPiePieces) {
                        item.series.data[i].graphic.attr("opacity", settings.dimmedOpacity);
                    }
                }
                item.slice(true, true);
                if (settings.dimPiePieces) {
                    item.graphic.attr("opacity", settings.defaultOpacity);
                }
            });

            addEvent(element, "mouseleave", function () {
                item.slice(false, true);
                for (var i = 0; i < item.series.data.length; ++i) {
                    if (item.series.data[i]._restoreSlice) {
                        item.series.data[i].slice(true, true);
                        item.series.data[i]._restoreSlice = undefined;
                    }
                    if (settings.dimPiePieces) {
                        item.series.data[i].graphic.attr("opacity", settings.defaultOpacity);
                    }
                }
            });
        }

        if (itemType === "funnel") {
            // Dim all data points in funnel chart except the currently hovered over one
            addEvent(element, "mouseenter", function () {
                for (var i = 0; i < item.series.data.length; ++i) {
                    if (item.series.data[i] !== item) {
                        item.series.data[i].graphic.attr("opacity", settings.dimmedOpacity);
                    }
                }
            });
            addEvent(element, "mouseleave", function () {
                for (var i = 0; i < item.series.data.length; ++i) {
                    if (item.series.data[i] !== item) {
                        item.series.data[i].graphic.attr("opacity", settings.defaultOpacity);
                    }
                }
            });
        }

        item._legendHighlightReady = true;
    });
})(Highcharts);
<|endoftext|>


<commit_before>require("requirish")._(module);

var subscription_service = require("lib/services/subscription_service");
var NotificationMessage = subscription_service.NotificationMessage;

var s = require("lib/datamodel/structures");
var StatusCodes = require("lib/datamodel/opcua_status_code").StatusCodes;
var assert = require("better-assert");

var _ = require("underscore");

var debugLog  = require("lib/misc/utils").make_debugLog(__filename);

/**
 * A client side implementation to deal with publish service.
 *
 * @class ClientSidePublishEngine
 *
 * @param session {ClientSession} - the client session
 * @param options {object} - the client session
 * @param options.keepalive_interval {number} - the keep alive interval ( default = 1000 ms)
 * @constructor
 *
 * The ClientSidePublishEngine encapsulates the mechanism to
 * deal with a OPCUA Server and constantly sending PublishRequest
 * The ClientSidePublishEngine also performs  notification acknowledgements.
 * Finally, ClientSidePublishEngine dispatch PublishResponse to the correct
 * Subscription id callback
 */
function ClientSidePublishEngine(session,options) {
        assert(session instanceof Object);

    options = options || {};
    options.keepalive_interval = options.keepalive_interval || 1000;

    this.session = session;
    this.keepalive_interval = options.keepalive_interval;

    this.subscriptionAcknowledgements = [];
    this.subscriptionIdFuncMap = {};
}

/**
 * @method acknowledge_notification
 * @param subscriptionId {Number} the subscription id
 * @param sequenceNumber {Number} the sequence number
 */
ClientSidePublishEngine.prototype.acknowledge_notification = function (subscriptionId, sequenceNumber) {
    this.subscriptionAcknowledgements.push({
        subscriptionId: subscriptionId,
        sequenceNumber: sequenceNumber
    });
};

/**
 * @method send_publish_request
 */
ClientSidePublishEngine.prototype.send_publish_request = function () {
    var self = this;
    setImmediate(function(){
        if (!self.session) {
            // session has been terminated
            return ;
        }
        self._send_publish_request();
    });
};

ClientSidePublishEngine.prototype._send_publish_request = function () {

    debugLog("sending publish request");
    var self = this;
    assert( self.session , "ClientSidePublishEngine terminated ?");

    var subscriptionAcknowledgements = self.subscriptionAcknowledgements;
    self.subscriptionAcknowledgements = [];

    // as started in the spec (Spec 1.02 part 4 page 81 5.13.2.2 Function DequeuePublishReq())
    // the server will dequeue the PublishRequest  in first-in first-out order
    // and will validate if the publish request is still valid by checking the timeoutHint in the RequestHeader.
    // If the request timed out, the server will send a Bad_Timeout service result for the request and de-queue
    // another publish request.
    //
    // in Part 4. page 144 Request Header the timeoutHint is described this way.
    // timeoutHint UInt32 This timeout in milliseconds is used in the Client side Communication Stack to
    //                    set the timeout on a per-call base.
    //                    For a Server this timeout is only a hint and can be used to cancel long running
    //                    operations to free resources. If the Server detects a timeout, he can cancel the
    //                    operation by sending the Service result Bad_Timeout. The Server should wait
    //                    at minimum the timeout after he received the request before cancelling the operation.
    //                    The value of 0 indicates no timeout.
    // In issue#40 (MonitoredItem on changed not fired), we have found that some server migh wrongly interpret
    // the timeoutHint of the request header ( and will bang a Bad_Timeout regardless if client send timeoutHint=0)
    // as a work around here , we force the timeoutHint to be 1 second

    var publish_request = new subscription_service.PublishRequest({
        requestHeader: { timeoutHint: 1000 }, // see note
        subscriptionAcknowledgements: subscriptionAcknowledgements
    });
    self.session.publish(publish_request, function (err, response) {
        if (err) {
            //xx console.log("xxxxxxxxxxxxxxxxxxx ClientSidePublishEngine.prototype._send_publish_request ".red ,err.message.yellow);
        } else {
            self._receive_publish_response(response);
        }
    });
};

ClientSidePublishEngine.prototype.terminate = function() {
    this.session = null;
};

/**
 * the number of active subscriptions managed by this publish engine.
 * @property subscriptionCount
 * @type {Number}
 */
ClientSidePublishEngine.prototype.__defineGetter__("subscriptionCount",function() {
    var self = this;
    return Object.keys(self.subscriptionIdFuncMap).length;
});

/**
 * @method registerSubscriptionCallback
 *
 * @param subscriptionId
 * @param {Function} callback
 */
ClientSidePublishEngine.prototype.registerSubscriptionCallback = function(subscriptionId,callback) {
    var self = this;
    assert(!self.subscriptionIdFuncMap.hasOwnProperty(subscriptionId)); // already registered ?
    self.subscriptionIdFuncMap[subscriptionId] = callback;

    // Spec 1.02 part 4 5.13.5 Publish
    // [..] in high latency networks, the Client may wish to pipeline Publish requests
    // to ensure cyclic reporting from the Server. Pipelining involves sending more than one Publish
    // request for each Subscription before receiving a response. For example, if the network introduces a
    // delay between the Client and the Server of 5 seconds and the publishing interval for a Subscription
    // is one second, then the Client will have to issue Publish requests every second instead of waiting for
    // a response to be received before sending the next request.
    self.send_publish_request();
    self.send_publish_request();
    self.send_publish_request();
    self.send_publish_request();
    self.send_publish_request();
};
/**
 * @method unregisterSubscriptionCallback
 *
 * @param subscriptionId
 */
ClientSidePublishEngine.prototype.unregisterSubscriptionCallback = function(subscriptionId) {
    var self = this;
    if (subscriptionId==="pending") {
        console.log("special subscriptionId here");
    }
    assert(self.subscriptionIdFuncMap.hasOwnProperty(subscriptionId));
    delete self.subscriptionIdFuncMap[subscriptionId];
};

ClientSidePublishEngine.prototype._receive_publish_response= function(response){

    debugLog("receive publish response");
    var self = this;

    // the id of the subscription sending the notification message
    var subscriptionId = response.subscriptionId;

    // the sequence numbers available in this subscription
    // for retransmission and not acknowledged by the client
    var available_seq = response.availableSequenceNumbers;

    // has the server more notification for us ?
    var moreNotifications = response.moreNotifications;

    var notificationMessage = response.notificationMessage;
    //  notificationMessage.sequenceNumber
    //  notificationMessage.publishTime
    //  notificationMessage.notificationData[]
    if (notificationMessage.notificationData.length === 0) {
        // this is a keep-alive notification
        // in this case , we shall not acknowledge notificationMessage.sequenceNumber
        // which is only an information of what will be the future sequenceNumber.
    } else {
        self.acknowledge_notification(subscriptionId, notificationMessage.sequenceNumber);
    }

    var callback_for_subscription =  self.subscriptionIdFuncMap[subscriptionId];
    if (callback_for_subscription && ! (self.session === null) ) {
        // feed the server with a new publish Request to the server
        self.send_publish_request();

        // delegate notificationData to the subscription callback
        callback_for_subscription(notificationMessage.notificationData,notificationMessage.publishTime);
    } else {
       debugLog(" ignoring notificationMessage",notificationMessage," for subscription", subscriptionId);
       debugLog(" because there is no callback for the subscription.");
       debugLog(" or because there is no session for the subscription (session terminated ?).");
    }
};
exports.ClientSidePublishEngine = ClientSidePublishEngine;<commit_msg>#40 undo sending many publish request<commit_after>require("requirish")._(module);

var subscription_service = require("lib/services/subscription_service");
var NotificationMessage = subscription_service.NotificationMessage;

var s = require("lib/datamodel/structures");
var StatusCodes = require("lib/datamodel/opcua_status_code").StatusCodes;
var assert = require("better-assert");

var _ = require("underscore");

var debugLog  = require("lib/misc/utils").make_debugLog(__filename);

/**
 * A client side implementation to deal with publish service.
 *
 * @class ClientSidePublishEngine
 *
 * @param session {ClientSession} - the client session
 * @param options {object} - the client session
 * @param options.keepalive_interval {number} - the keep alive interval ( default = 1000 ms)
 * @constructor
 *
 * The ClientSidePublishEngine encapsulates the mechanism to
 * deal with a OPCUA Server and constantly sending PublishRequest
 * The ClientSidePublishEngine also performs  notification acknowledgements.
 * Finally, ClientSidePublishEngine dispatch PublishResponse to the correct
 * Subscription id callback
 */
function ClientSidePublishEngine(session,options) {
        assert(session instanceof Object);

    options = options || {};
    options.keepalive_interval = options.keepalive_interval || 1000;

    this.session = session;
    this.keepalive_interval = options.keepalive_interval;

    this.subscriptionAcknowledgements = [];
    this.subscriptionIdFuncMap = {};
}

/**
 * @method acknowledge_notification
 * @param subscriptionId {Number} the subscription id
 * @param sequenceNumber {Number} the sequence number
 */
ClientSidePublishEngine.prototype.acknowledge_notification = function (subscriptionId, sequenceNumber) {
    this.subscriptionAcknowledgements.push({
        subscriptionId: subscriptionId,
        sequenceNumber: sequenceNumber
    });
};

/**
 * @method send_publish_request
 */
ClientSidePublishEngine.prototype.send_publish_request = function () {
    var self = this;
    setImmediate(function(){
        if (!self.session) {
            // session has been terminated
            return ;
        }
        self._send_publish_request();
    });
};

ClientSidePublishEngine.prototype._send_publish_request = function () {

    debugLog("sending publish request");
    var self = this;
    assert( self.session , "ClientSidePublishEngine terminated ?");

    var subscriptionAcknowledgements = self.subscriptionAcknowledgements;
    self.subscriptionAcknowledgements = [];

    // as started in the spec (Spec 1.02 part 4 page 81 5.13.2.2 Function DequeuePublishReq())
    // the server will dequeue the PublishRequest  in first-in first-out order
    // and will validate if the publish request is still valid by checking the timeoutHint in the RequestHeader.
    // If the request timed out, the server will send a Bad_Timeout service result for the request and de-queue
    // another publish request.
    //
    // in Part 4. page 144 Request Header the timeoutHint is described this way.
    // timeoutHint UInt32 This timeout in milliseconds is used in the Client side Communication Stack to
    //                    set the timeout on a per-call base.
    //                    For a Server this timeout is only a hint and can be used to cancel long running
    //                    operations to free resources. If the Server detects a timeout, he can cancel the
    //                    operation by sending the Service result Bad_Timeout. The Server should wait
    //                    at minimum the timeout after he received the request before cancelling the operation.
    //                    The value of 0 indicates no timeout.
    // In issue#40 (MonitoredItem on changed not fired), we have found that some server migh wrongly interpret
    // the timeoutHint of the request header ( and will bang a Bad_Timeout regardless if client send timeoutHint=0)
    // as a work around here , we force the timeoutHint to be 1 second

    var publish_request = new subscription_service.PublishRequest({
        requestHeader: { timeoutHint: 1000 }, // see note
        subscriptionAcknowledgements: subscriptionAcknowledgements
    });
    self.session.publish(publish_request, function (err, response) {
        if (err) {
            //xx console.log("xxxxxxxxxxxxxxxxxxx ClientSidePublishEngine.prototype._send_publish_request ".red ,err.message.yellow);
        } else {
            self._receive_publish_response(response);
        }
    });
};

ClientSidePublishEngine.prototype.terminate = function() {
    this.session = null;
};

/**
 * the number of active subscriptions managed by this publish engine.
 * @property subscriptionCount
 * @type {Number}
 */
ClientSidePublishEngine.prototype.__defineGetter__("subscriptionCount",function() {
    var self = this;
    return Object.keys(self.subscriptionIdFuncMap).length;
});

/**
 * @method registerSubscriptionCallback
 *
 * @param subscriptionId
 * @param {Function} callback
 */
ClientSidePublishEngine.prototype.registerSubscriptionCallback = function(subscriptionId,callback) {
    var self = this;
    assert(!self.subscriptionIdFuncMap.hasOwnProperty(subscriptionId)); // already registered ?
    self.subscriptionIdFuncMap[subscriptionId] = callback;

    // Spec 1.02 part 4 5.13.5 Publish
    // [..] in high latency networks, the Client may wish to pipeline Publish requests
    // to ensure cyclic reporting from the Server. Pipelining involves sending more than one Publish
    // request for each Subscription before receiving a response. For example, if the network introduces a
    // delay between the Client and the Server of 5 seconds and the publishing interval for a Subscription
    // is one second, then the Client will have to issue Publish requests every second instead of waiting for
    // a response to be received before sending the next request.
    self.send_publish_request();

    // todo  : send more than only publish request to server to cope with latency and create appropriated tests.
    //xx self.send_publish_request();
    //xx self.send_publish_request();
    //xx self.send_publish_request();
    //xx self.send_publish_request();
};
/**
 * @method unregisterSubscriptionCallback
 *
 * @param subscriptionId
 */
ClientSidePublishEngine.prototype.unregisterSubscriptionCallback = function(subscriptionId) {
    var self = this;
    if (subscriptionId==="pending") {
        console.log("special subscriptionId here");
    }
    assert(self.subscriptionIdFuncMap.hasOwnProperty(subscriptionId));
    delete self.subscriptionIdFuncMap[subscriptionId];
};

ClientSidePublishEngine.prototype._receive_publish_response= function(response){

    debugLog("receive publish response");
    var self = this;

    // the id of the subscription sending the notification message
    var subscriptionId = response.subscriptionId;

    // the sequence numbers available in this subscription
    // for retransmission and not acknowledged by the client
    var available_seq = response.availableSequenceNumbers;

    // has the server more notification for us ?
    var moreNotifications = response.moreNotifications;

    var notificationMessage = response.notificationMessage;
    //  notificationMessage.sequenceNumber
    //  notificationMessage.publishTime
    //  notificationMessage.notificationData[]
    if (notificationMessage.notificationData.length === 0) {
        // this is a keep-alive notification
        // in this case , we shall not acknowledge notificationMessage.sequenceNumber
        // which is only an information of what will be the future sequenceNumber.
    } else {
        self.acknowledge_notification(subscriptionId, notificationMessage.sequenceNumber);
    }

    var callback_for_subscription =  self.subscriptionIdFuncMap[subscriptionId];
    if (callback_for_subscription && ! (self.session === null) ) {
        // feed the server with a new publish Request to the server
        self.send_publish_request();

        // delegate notificationData to the subscription callback
        callback_for_subscription(notificationMessage.notificationData,notificationMessage.publishTime);
    } else {
       debugLog(" ignoring notificationMessage",notificationMessage," for subscription", subscriptionId);
       debugLog(" because there is no callback for the subscription.");
       debugLog(" or because there is no session for the subscription (session terminated ?).");
    }
};
exports.ClientSidePublishEngine = ClientSidePublishEngine;<|endoftext|>


<commit_before>import { getTimeFormat } from '@opentripplanner/core-utils/lib/time'
import moment from 'moment'
import React, {Component} from 'react'
import { injectIntl } from 'react-intl'
import { connect } from 'react-redux'

import * as fieldTripActions from '../../actions/field-trip'
import * as formActions from '../../actions/form'
import { getTripFromRequest } from '../../util/call-taker'

import FieldTripStatusIcon from './field-trip-status-icon'
import {
  Bold,
  Button,
  Full,
  Header,
  Para
} from './styled'

class TripStatus extends Component {
  _formatTime = (time) => moment(time).format(this.props.timeFormat)

  _onDeleteTrip = () => {
    const { deleteRequestTripItineraries, intl, request, trip } = this.props
    if (!confirm('Are you sure you want to delete the planned trip?')) {
      return
    }
    deleteRequestTripItineraries(request, trip.id, intl)
  }

  _onPlanTrip = () => {
    const { intl, outbound, planTrip, request, status, trip } = this.props
    if (status && trip) {
      if (!confirm('Re-planning this trip will cause the trip planner to avoid the currently saved trip. Are you sure you want to continue?')) {
        return
      }
    }
    planTrip(request, outbound, intl)
  }

  _onSaveTrip = () => {
    const { intl, outbound, request, saveRequestTripItineraries } = this.props
    saveRequestTripItineraries(request, outbound, intl)
  }

  _onViewTrip = () => {
    const { outbound, request, viewRequestTripItineraries } = this.props
    viewRequestTripItineraries(request, outbound)
  }

  _tripIsPlanned = () => Boolean(this.props.status && this.props.trip)

  _renderTripStatus = () => {
    const { trip } = this.props
    if (!this._tripIsPlanned()) {
      return (
        <Para>
          No itineraries planned! Click Plan to plan trip.
        </Para>
      )
    }
    return (
      <>
        <Para>
          {trip.groupItineraries.length} group itineraries, planned by{' '}
          {trip.createdBy} at {trip.timeStamp}
        </Para>
        <Para>
          <Button bsSize='xs' onClick={this._onViewTrip}>View</Button>
          <Button bsSize='xs' onClick={this._onDeleteTrip}>Delete</Button>
        </Para>
      </>
    )
  }

  render () {
    const {outbound, request, saveable} = this.props
    const {
      arriveDestinationTime,
      arriveSchoolTime,
      endLocation,
      leaveDestinationTime,
      startLocation
    } = request
    if (!request) {
      console.warn('Could not find field trip request')
      return null
    }
    const start = outbound ? startLocation : endLocation
    const end = outbound ? endLocation : startLocation
    return (
      <Full>
        <Header>
          <FieldTripStatusIcon ok={this._tripIsPlanned()} />
          {outbound ? 'Outbound' : 'Inbound'} trip
          <Button bsSize='xs' onClick={this._onPlanTrip}>Plan</Button>
          <Button
            bsSize='xs'
            disabled={!saveable}
            onClick={this._onSaveTrip}
          >
            Save
          </Button>
        </Header>
        <Para>From <Bold>{start}</Bold> to <Bold>{end}</Bold></Para>
        {outbound
          ? <Para>
            Arriving at {this._formatTime(arriveDestinationTime)}
          </Para>
          : <>
            <Para>
              Leave at {this._formatTime(leaveDestinationTime)},{' '}
              due back at {this._formatTime(arriveSchoolTime)}
            </Para>
          </>
        }
        {this._renderTripStatus()}
      </Full>
    )
  }
}

const mapStateToProps = (state, ownProps) => {
  const { outbound, request } = ownProps
  const { saveable } = state.callTaker.fieldTrip
  return {
    currentQuery: state.otp.currentQuery,
    saveable: outbound ? saveable?.outbound : saveable?.inbound,
    status: outbound ? request.outboundTripStatus : request.inboundTripStatus,
    timeFormat: getTimeFormat(state.otp.config),
    trip: getTripFromRequest(request, outbound)
  }
}

const mapDispatchToProps = {
  deleteRequestTripItineraries: fieldTripActions.deleteRequestTripItineraries,
  planTrip: fieldTripActions.planTrip,
  saveRequestTripItineraries: fieldTripActions.saveRequestTripItineraries,
  setQueryParam: formActions.setQueryParam,
  viewRequestTripItineraries: fieldTripActions.viewRequestTripItineraries
}

export default connect(mapStateToProps, mapDispatchToProps)(
  injectIntl(TripStatus)
)
<commit_msg>refactor(TripStatus): Remove momentjs<commit_after>/* eslint-disable react/prop-types */
import { connect } from 'react-redux'
import { format } from 'date-fns'
import { getTimeFormat } from '@opentripplanner/core-utils/lib/time'
import { injectIntl } from 'react-intl'
import React, { Component } from 'react'

import * as fieldTripActions from '../../actions/field-trip'
import * as formActions from '../../actions/form'
import { getTripFromRequest, parseDate } from '../../util/call-taker'

import { Bold, Button, Full, Header, Para } from './styled'
import FieldTripStatusIcon from './field-trip-status-icon'

class TripStatus extends Component {
  _formatTime = (time) => format(parseDate(time), this.props.timeFormat)

  _onDeleteTrip = () => {
    const { deleteRequestTripItineraries, intl, request, trip } = this.props
    if (!window.confirm('Are you sure you want to delete the planned trip?')) {
      return
    }
    deleteRequestTripItineraries(request, trip.id, intl)
  }

  _onPlanTrip = () => {
    const { intl, outbound, planTrip, request, status, trip } = this.props
    if (status && trip) {
      if (
        !window.confirm(
          'Re-planning this trip will cause the trip planner to avoid the currently saved trip. Are you sure you want to continue?'
        )
      ) {
        return
      }
    }
    planTrip(request, outbound, intl)
  }

  _onSaveTrip = () => {
    const { intl, outbound, request, saveRequestTripItineraries } = this.props
    saveRequestTripItineraries(request, outbound, intl)
  }

  _onViewTrip = () => {
    const { outbound, request, viewRequestTripItineraries } = this.props
    viewRequestTripItineraries(request, outbound)
  }

  _tripIsPlanned = () => Boolean(this.props.status && this.props.trip)

  _renderTripStatus = () => {
    const { trip } = this.props
    if (!this._tripIsPlanned()) {
      return <Para>No itineraries planned! Click Plan to plan trip.</Para>
    }
    return (
      <>
        <Para>
          {trip.groupItineraries.length} group itineraries, planned by{' '}
          {trip.createdBy} at {trip.timeStamp}
        </Para>
        <Para>
          <Button bsSize="xs" onClick={this._onViewTrip}>
            View
          </Button>
          <Button bsSize="xs" onClick={this._onDeleteTrip}>
            Delete
          </Button>
        </Para>
      </>
    )
  }

  render() {
    const { outbound, request, saveable } = this.props
    const {
      arriveDestinationTime,
      arriveSchoolTime,
      endLocation,
      leaveDestinationTime,
      startLocation
    } = request
    if (!request) {
      console.warn('Could not find field trip request')
      return null
    }
    const start = outbound ? startLocation : endLocation
    const end = outbound ? endLocation : startLocation
    return (
      <Full>
        <Header>
          <FieldTripStatusIcon ok={this._tripIsPlanned()} />
          {outbound ? 'Outbound' : 'Inbound'} trip
          <Button bsSize="xs" onClick={this._onPlanTrip}>
            Plan
          </Button>
          <Button bsSize="xs" disabled={!saveable} onClick={this._onSaveTrip}>
            Save
          </Button>
        </Header>
        <Para>
          From <Bold>{start}</Bold> to <Bold>{end}</Bold>
        </Para>
        {outbound ? (
          <Para>Arriving at {this._formatTime(arriveDestinationTime)}</Para>
        ) : (
          <>
            <Para>
              Leave at {this._formatTime(leaveDestinationTime)}, due back at{' '}
              {this._formatTime(arriveSchoolTime)}
            </Para>
          </>
        )}
        {this._renderTripStatus()}
      </Full>
    )
  }
}

const mapStateToProps = (state, ownProps) => {
  const { outbound, request } = ownProps
  const { saveable } = state.callTaker.fieldTrip
  return {
    currentQuery: state.otp.currentQuery,
    saveable: outbound ? saveable?.outbound : saveable?.inbound,
    status: outbound ? request.outboundTripStatus : request.inboundTripStatus,
    timeFormat: getTimeFormat(state.otp.config),
    trip: getTripFromRequest(request, outbound)
  }
}

const mapDispatchToProps = {
  deleteRequestTripItineraries: fieldTripActions.deleteRequestTripItineraries,
  planTrip: fieldTripActions.planTrip,
  saveRequestTripItineraries: fieldTripActions.saveRequestTripItineraries,
  setQueryParam: formActions.setQueryParam,
  viewRequestTripItineraries: fieldTripActions.viewRequestTripItineraries
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(injectIntl(TripStatus))
<|endoftext|>


<commit_before>import React from 'react';
import Relay from 'react-relay';
import cx from 'classnames';

import Octicon from '../views/octicon';

const reactionTypeToEmoji = {
  THUMBS_UP: '👍',
  THUMBS_DOWN: '👎',
  LAUGH: '😆',
  HOORAY: '🎉',
  CONFUSED: '😕',
  HEART: '❤',
};

const prStateToIcon = {
  OPEN: 'git-pull-request',
  CLOSED: 'git-pull-request',
  MERGED: 'git-merge',
};

export class PrInfo extends React.Component {
  static propTypes = {
    repository: React.PropTypes.shape({
      name: React.PropTypes.string.isRequired,
      owner: React.PropTypes.shape({
        login: React.PropTypes.string,
      }),
    }),
    pullRequest: React.PropTypes.shape({
      title: React.PropTypes.string,
      bodyHTML: React.PropTypes.string,
      number: React.PropTypes.number,
      state: React.PropTypes.oneOf([
        'OPEN', 'CLOSED', 'MERGED',
      ]).isRequired,
      author: React.PropTypes.shape({
        login: React.PropTypes.string.isRequired,
        avatarURL: React.PropTypes.string.isRequired,
        url: React.PropTypes.string.isRequired,
      }).isRequired,
      reactionGroups: React.PropTypes.arrayOf(
        React.PropTypes.shape({
          content: React.PropTypes.string.isRequired,
          users: React.PropTypes.shape({
            totalCount: React.PropTypes.number.isRequired,
          }).isRequired,
        }),
      ).isRequired,
    }).isRequired,
  }

  render() {
    const repo = this.props.repository;
    const pr = this.props.pullRequest;
    return (

            <Octicon icon={prStateToIcon[pr.state]} />
            {pr.state.toLowerCase()}

            {repo.owner.login}/{repo.name}#{pr.number}

{pr.title}

          {pr.reactionGroups.map(group => (
            group.users.totalCount > 0
            ?
              {reactionTypeToEmoji[group.content]} {group.users.totalCount}

            : null
          ))}

    );
  }
}

export default Relay.createContainer(PrInfo, {
  fragments: {
    repository: () => Relay.QL`
      fragment on Repository {
        name owner { login }
      }
    `,

    pullRequest: () => Relay.QL`
      fragment on PullRequest {
        url number title state bodyHTML
        author { login avatarURL url }
        reactionGroups {
          content users { totalCount }
        }
      }
    `,
  },
});
<commit_msg>Remove badge from reactions<commit_after>import React from 'react';
import Relay from 'react-relay';
import cx from 'classnames';

import Octicon from '../views/octicon';

const reactionTypeToEmoji = {
  THUMBS_UP: '👍',
  THUMBS_DOWN: '👎',
  LAUGH: '😆',
  HOORAY: '🎉',
  CONFUSED: '😕',
  HEART: '❤',
};

const prStateToIcon = {
  OPEN: 'git-pull-request',
  CLOSED: 'git-pull-request',
  MERGED: 'git-merge',
};

export class PrInfo extends React.Component {
  static propTypes = {
    repository: React.PropTypes.shape({
      name: React.PropTypes.string.isRequired,
      owner: React.PropTypes.shape({
        login: React.PropTypes.string,
      }),
    }),
    pullRequest: React.PropTypes.shape({
      title: React.PropTypes.string,
      bodyHTML: React.PropTypes.string,
      number: React.PropTypes.number,
      state: React.PropTypes.oneOf([
        'OPEN', 'CLOSED', 'MERGED',
      ]).isRequired,
      author: React.PropTypes.shape({
        login: React.PropTypes.string.isRequired,
        avatarURL: React.PropTypes.string.isRequired,
        url: React.PropTypes.string.isRequired,
      }).isRequired,
      reactionGroups: React.PropTypes.arrayOf(
        React.PropTypes.shape({
          content: React.PropTypes.string.isRequired,
          users: React.PropTypes.shape({
            totalCount: React.PropTypes.number.isRequired,
          }).isRequired,
        }),
      ).isRequired,
    }).isRequired,
  }

  render() {
    const repo = this.props.repository;
    const pr = this.props.pullRequest;
    return (

            <Octicon icon={prStateToIcon[pr.state]} />
            {pr.state.toLowerCase()}

            {repo.owner.login}/{repo.name}#{pr.number}

{pr.title}

          {pr.reactionGroups.map(group => (
            group.users.totalCount > 0
            ?
              {reactionTypeToEmoji[group.content]}   {group.users.totalCount}

            : null
          ))}

    );
  }
}

export default Relay.createContainer(PrInfo, {
  fragments: {
    repository: () => Relay.QL`
      fragment on Repository {
        name owner { login }
      }
    `,

    pullRequest: () => Relay.QL`
      fragment on PullRequest {
        url number title state bodyHTML
        author { login avatarURL url }
        reactionGroups {
          content users { totalCount }
        }
      }
    `,
  },
});
<|endoftext|>


<commit_before>'use strict';
var core = require("../soajs.core");
var Mongo = require("../soajs.mongo");
var mongo;

var config = require("./config");
function generateError(errorCode) {
	var error = new Error();
	error.code = errorCode;
	error.message = config.errors[errorCode];
	return error;
}

function ContentBuilder(config, callback) {

	if(!config.name){
		return callback(generateError(190));
	}

	if(!config.version || typeof(config.version) !== 'number'){
		return callback(generateError(191));
	}

	core.registry.profile(function(registry) {
		if(!registry) {
			return callback(generateError(192));
		}

		//connect to mongo
		mongo = new Mongo(registry.coreDB.provision);

		//get the gc schema
		mongo.findOne("gc", {"name": config.name, "v": config.version}, callback);
	});
}

module.exports = ContentBuilder;<commit_msg>when a content service is fetched from gc, add it's db under the environments before returning the config.<commit_after>'use strict';
var core = require("../soajs.core");
var Mongo = require("../soajs.mongo");
var async = require("async");
var mongo;

var config = require("./config");
function generateError(errorCode) {
	var error = new Error();
	error.code = errorCode;
	error.message = config.errors[errorCode];
	return error;
}

function ContentBuilder(config, callback) {

	if(!config.name) {
		return callback(generateError(190));
	}

	if(!config.version || typeof(config.version) !== 'number') {
		return callback(generateError(191));
	}

	core.registry.profile(function(registry) {
		if(!registry) {
			return callback(generateError(192));
		}

		//connect to mongo
		mongo = new Mongo(registry.coreDB.provision);

		//get the gc schema
		mongo.findOne("gc", {"name": config.name, "v": config.version}, function(error, config) {
			if(error) { return callback(error); }

			var envs = Object.keys(config.soajsService.db.config);
			async.mapLimit(envs, envs.length, addDbinEnv, function(error) {
				if(error){ return callback(error); }
				return callback(null, config);
			});

			function addDbinEnv(envCode, cb) {
				var dbName = Object.keys(config.soajsService.db.config[envCode])[0];
				var updateOptions = {
					'$set': {}
				};
				updateOptions['$set']["dbs.databases." + dbName] = config.soajsService.db.config[envCode][dbName];
				mongo.update("environment", {"code": envCode}, updateOptions, {"safe": true}, cb);
			}
		});
	});
}

module.exports = ContentBuilder;<|endoftext|>


<commit_before>import classNames from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';

import SafeAnchor from './SafeAnchor';
import { useBootstrapPrefix } from './ThemeProvider';

const propTypes = {
  /**
   * @default 'breadcrumb-item'
   */
  bsPrefix: PropTypes.string,
  /**
   * Adds a visual "active" state to a Breadcrumb
   * Item and disables the link.
   */
  active: PropTypes.bool,
  /**
   * `href` attribute for the inner `a` element
   */
  href: PropTypes.string,
  /**
   * You can use a custom element type for this component's inner link.
   */
  linkAs: PropTypes.elementType,
  /**
   * `title` attribute for the inner `a` element
   */
  title: PropTypes.node,
  /**
   * `target` attribute for the inner `a` element
   */
  target: PropTypes.string,

  as: PropTypes.elementType,
};

const defaultProps = {
  active: false,
};

const BreadcrumbItem = React.forwardRef(
  // Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
  (
    {
      bsPrefix,
      active,
      children,
      className,
      as: Component = 'li',
      linkAs: LinkComponent = SafeAnchor,
      ...props
    },
    ref,
  ) => {
    const prefix = useBootstrapPrefix(bsPrefix, 'breadcrumb-item');

    const { href, title, target, ...elementProps } = props;
    const linkProps = { href, title, target };

    return (
      <Component
        ref={ref}
        className={classNames(prefix, className, { active })}
        aria-current={active ? 'page' : undefined}
      >
        {active ? children : <LinkComponent {...elementProps} {...linkProps} />}
      </Component>
    );
  },
);

BreadcrumbItem.displayName = 'BreadcrumbItem';
BreadcrumbItem.propTypes = propTypes;
BreadcrumbItem.defaultProps = defaultProps;

export default BreadcrumbItem;
<commit_msg>Update BreadcrumbItem.js<commit_after>import classNames from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';

import SafeAnchor from './SafeAnchor';
import { useBootstrapPrefix } from './ThemeProvider';

const propTypes = {
  /**
   * @default 'breadcrumb-item'
   */
  bsPrefix: PropTypes.string,
  /**
   * Adds a visual "active" state to a Breadcrumb
   * Item and disables the link.
   */
  active: PropTypes.bool,
  /**
   * `href` attribute for the inner `a` element
   */
  href: PropTypes.string,
  /**
   * You can use a custom element type for this component's inner link.
   */
  linkAs: PropTypes.elementType,
  /**
   * `title` attribute for the inner `a` element
   */
  title: PropTypes.node,
  /**
   * `target` attribute for the inner `a` element
   */
  target: PropTypes.string,

  as: PropTypes.elementType,
};

const defaultProps = {
  active: false,
};

const BreadcrumbItem = React.forwardRef(
  (
    {
      bsPrefix,
      active,
      children,
      className,
      // Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
      as: Component = 'li',
      linkAs: LinkComponent = SafeAnchor,
      ...props
    },
    ref,
  ) => {
    const prefix = useBootstrapPrefix(bsPrefix, 'breadcrumb-item');

    const { href, title, target, ...elementProps } = props;
    const linkProps = { href, title, target };

    return (
      <Component
        ref={ref}
        className={classNames(prefix, className, { active })}
        aria-current={active ? 'page' : undefined}
      >
        {active ? children : <LinkComponent {...elementProps} {...linkProps} />}
      </Component>
    );
  },
);

BreadcrumbItem.displayName = 'BreadcrumbItem';
BreadcrumbItem.propTypes = propTypes;
BreadcrumbItem.defaultProps = defaultProps;

export default BreadcrumbItem;
<|endoftext|>


<commit_before>/* Use strict */

// CONSTRUCTORS
// Here is where you'll create your constructors for you player and monster.
// e.g. function Monster(){};
// e.g. function Player(){};

function Player(options){
  this.name = options.name;
  this.health = options.health;
  this.attack = function(monsta){
    return monsta.health = monsta.health - (Math.floor(Math.random() * 10));
  };
};
function Monster(options){
  this.health = options.health;
  this.name = options.name;
  this.fight = function(player){
    return player.health = player.health - (Math.floor(Math.random() * 8));
  };
};

// GLOBAL VARIABLES
// You'll also want to create variables for the specific players and monsters.
// e.g. var purplePeopleEater = new Monster();
// e.g. var tinaFey = new Player();
// e.g. var attackMode = function(target){ Some code that produces an attack - pew, pew! };
//
var dino1 = new Player({
  health: 100,
  name: "cartoon Rex"
});
var dino2 = new Player({
  health: 100,
  name: "T-rex"
});
var dino3 = new Player({
  health: 100,
  name: "Brontasaurus"
});
var monster1 = new Monster({
  name: "Ugly",
  health: 100
});
var monster2 = new Monster({
  name: "Even Uglier",
  health: 200
});

// ACTIONS
// This is where jQuery will come into play and where you'll set a lot of your
// interactions for players and monsters. (e.g. player selection, attack interactions)
// e.g. $('.purple-people-eater').click(function () { Some code that attacks the monster! };

//jQuery Variables
$header = $('header');
$ACS = $('#after-char-select');
image1 = "images/images.duckduckgo.gif"
image2 = "images/images.duckduckgo.jpg"
image3 = "images/images.duckduckgo-1.jpg"
backgroundImage1 = "images/dino-background-1.jpg"
backgroundImage2 = "images/dino-background-2.jpg"
backgroundImage3 = "images/dino-background-3.jpg"

//Select character and add dino1background + dino1 image + dino1 name to battle scene
$('#img1').click(function(){
  $('#character').css('background-image','url('+ image1 +')');
  $('header').css('display', 'none');
  $('#after-char-select').css('display','initial');
  $('#char-name').html(dino1.name);
  $('#background').css('background-image','url('+ backgroundImage1 +')');
});

//Select character and add dino2background + dino2 image + dino2 name to battle scene
$('#img2').click(function(){
  $('#character').css('background-image','url('+ image2 +')');
  $('header').css('display', 'none');
  $('#after-char-select').css('display','initial');
  $('#char-name').html(dino2.name);
  $('#background').css('background-image','url('+ backgroundImage2 +')');
});

//Select character and add dino3background + dino3 image + dino3 name to battle scene
$('#img3').click(function(){
  $('#character').css('background-image','url('+ image3 +')');
  $('header').css('display', 'none');
  $('#after-char-select').css('display','initial');
  $('#char-name').html(dino3.name);
  $('#background').css('background-image','url('+ backgroundImage3 +')');
});

// After selecting character message
$('#after-char-select').click(function(){
  $('#after-char-select').css('display','none');
  $('#battle').css('display','initial');
});

// Adding health remaining to battle scene
$('#dino-health').html(dino1.health);
$('#dino-health').html(dino2.health);
$('#dino-health').html(dino3.health);

//Fighting function for dino1
$('#fightFunction').click(function(){
  dino1.attack(monster1);
  $('#monster-health').html(monster1.health);
  setInterval(function(){
    monster1.fight(dino1);
  },100);
  $('#dino-health').html(dino1.health);
  if(monster1.health < 0){
    $('#battle').css('display','none');
    $('#victoryPage').css('display','initial');
    $('#score').html(dino1.health);
  }
  if(dino3.health < 0){
    $('#battle').css('display','none');
    $('#lostPage').css('display','intial');
  }
});

// Fighting function for dino2
$('#fightFunction').click(function(){
  dino2.attack(monster1);
  $('#monster-health').html(monster1.health);
  setInterval(function(){
    monster1.fight(dino2);
  },100);
  $('#dino-health').html(dino2.health);
  if(monster1.health < 0){
    $('#battle').css('display','none');
    $('#victoryPage').css('display','initial');
    $('#score').html(dino2.health);
  }
  if(dino3.health < 0){
    $('#battle').css('display','none');
    $('#lostPage').css('display','intial');
  }
});

//Fighting function for dino3
$('#fightFunction').click(function(){
  dino3.attack(monster1);
  $('#monster-health').html(monster1.health);
  setInterval(function(){
    monster1.fight(dino3);
  },100);
  $('#dino-health').html(dino3.health);
  if(monster1.health < 0){
    $('#battle').css('display','none');
    $('#victoryPage').css('display','initial');
    $('#score').html(dino3.health);
  }
  if(dino3.health < 0){
    $('#battle').css('display','none');
    $('#lostPage').css('display','initial');
  }
});

$('#newCharSelect').click(function(){
 open('http://localhost:9000')
});
<commit_msg>Added new constructor and cleaned up code<commit_after>/* Use strict */

// CONSTRUCTORS
// Here is where you'll create your constructors for you player and monster.
// e.g. function Monster(){};
// e.g. function Player(){};

function Player(options){
  this.name = options.name;
  this.health = options.health;
  this.attack = function(monsta){
    return monsta.health = monsta.health - (Math.floor(Math.random() * 10));
  };
  this.select = function(dino,image, backgroundimage){
    $('#character').css('background-image','url('+ image +')');
    $('header').css('display', 'none');
    $('#after-char-select').css('display','initial');
    $('#char-name').html(dino.name);
    $('#background').css('background-image','url('+ backgroundimage +')');
  };
  this.startBattle = function(dino,monster){
    dino.attack(monster);
    $('#monster-health').html(monster.health);
    setInterval(function(){
      monster.fight(dino);
    },100);
    $('#dino-health').html(dino.health);
    if(monster.health < 0){
      $('#battle').css('display','none');
      $('#victoryPage').css('display','initial');
      $('#score').html(dino.health);
    }
    if(dino.health < 0){
      $('#battle').css('display','none');
      $('#lostPage').css('display','intial');
    }
  };
};

function Monster(options){
  this.health = options.health;
  this.name = options.name;
  this.fight = function(player){
    return player.health = player.health - (Math.floor(Math.random() * 8));
  };
};

// GLOBAL VARIABLES
// You'll also want to create variables for the specific players and monsters.
// e.g. var purplePeopleEater = new Monster();
// e.g. var tinaFey = new Player();
// e.g. var attackMode = function(target){ Some code that produces an attack - pew, pew! };
//
var dino1 = new Player({
  health: 100,
  name: "cartoon Rex"
});
var dino2 = new Player({
  health: 100,
  name: "T-rex"
});
var dino3 = new Player({
  health: 100,
  name: "Brontasaurus"
});
var monster1 = new Monster({
  name: "Ugly",
  health: 100
});
var monster2 = new Monster({
  name: "Even Uglier",
  health: 200
});

// ACTIONS
// This is where jQuery will come into play and where you'll set a lot of your
// interactions for players and monsters. (e.g. player selection, attack interactions)
// e.g. $('.purple-people-eater').click(function () { Some code that attacks the monster! };

//jQuery Variables
$header = $('header');
$ACS = $('#after-char-select');
image1 = "images/images.duckduckgo.gif"
image2 = "images/images.duckduckgo.jpg"
image3 = "images/images.duckduckgo-1.jpg"
backgroundImage1 = "images/dino-background-1.jpg"
backgroundImage2 = "images/dino-background-2.jpg"
backgroundImage3 = "images/dino-background-3.jpg"

// After selecting character message
$('#after-char-select').click(function(){
  $('#after-char-select').css('display','none');
  $('#battle').css('display','initial');
});

// Adding health remaining to battle scene
$('#dino-health').html(dino1.health);
$('#dino-health').html(dino2.health);
$('#dino-health').html(dino3.health);

//Fighting function for dino1
$('#fightFunction').click(function(){
  dino1.attack(monster1);
  $('#monster-health').html(monster1.health);
  setInterval(function(){
    monster1.fight(dino1);
  },100);
  $('#dino-health').html(dino1.health);
  if(monster1.health < 0){
    $('#battle').css('display','none');
    $('#victoryPage').css('display','initial');
    $('#score').html(dino1.health);
  }
  if(dino3.health < 0){
    $('#battle').css('display','none');
    $('#lostPage').css('display','intial');
  }
});

// Fighting function for dino2
$('#fightFunction').click(function(){
  dino2.attack(monster1);
  $('#monster-health').html(monster1.health);
  setInterval(function(){
    monster1.fight(dino2);
  },100);
  $('#dino-health').html(dino2.health);
  if(monster1.health < 0){
    $('#battle').css('display','none');
    $('#victoryPage').css('display','initial');
    $('#score').html(dino2.health);
  }
  if(dino3.health < 0){
    $('#battle').css('display','none');
    $('#lostPage').css('display','intial');
  }
});

//Fighting function for dino3
$('#fightFunction').click(function(){
  dino3.attack(monster1);
  $('#monster-health').html(monster1.health);
  setInterval(function(){
    monster1.fight(dino3);
  },100);
  $('#dino-health').html(dino3.health);
  if(monster1.health < 0){
    $('#battle').css('display','none');
    $('#victoryPage').css('display','initial');
    $('#score').html(dino3.health);
  }
  if(dino3.health < 0){
    $('#battle').css('display','none');
    $('#lostPage').css('display','initial');
  }
});

$('#newCharSelect').click(function(){
 open('http://localhost:9000')
});

$('#img1').click(function(){
  dino1.select(dino1,image1,backgroundImage1);
});
$('#img2').click(function(){
  dino2.select(dino2,image2,backgroundImage2);
});
$('#img3').click(function(){
  dino3.select(dino3,image3,backgroundImage3);
});
<|endoftext|>


<commit_before>/**
 *
 * Any ref to fixCompletedChallengesItem should be removed post
 * a db migration to fix all completedChallenges
 *
 */
import { Observable } from 'rx';
import _ from 'lodash';
import debug from 'debug';
import accepts from 'accepts';
import dedent from 'dedent';

import { homeLocation } from '../../../config/env.json';

import { ifNoUserSend } from '../utils/middleware';
import { dasherize } from '../utils';
import pathMigrations from '../resources/pathMigration.json';
import { fixCompletedChallengeItem } from '../../common/utils';

const log = debug('fcc:boot:challenges');

const learnURL = `${homeLocation}/learn`;

const jsProjects = [
  'aaa48de84e1ecc7c742e1124',
  'a7f4d8f2483413a6ce226cac',
  '56533eb9ac21ba0edf2244e2',
  'aff0395860f5d3034dc0bfc9',
  'aa2e6f85cab2ab736c9a9b24'
];

function buildUserUpdate(user, challengeId, _completedChallenge, timezone) {
  const { files } = _completedChallenge;
  let completedChallenge = {};

  if (jsProjects.includes(challengeId)) {
    completedChallenge = {
      ..._completedChallenge,
      files: Object.keys(files)
        .map(key => files[key])
        .map(file =>
          _.pick(file, ['contents', 'key', 'index', 'name', 'path', 'ext'])
        )
    };
  } else {
    completedChallenge = _.omit(_completedChallenge, ['files']);
  }
  let finalChallenge;
  const updateData = {};
  const { timezone: userTimezone, completedChallenges = [] } = user;

  const oldChallenge = _.find(
    completedChallenges,
    ({ id }) => challengeId === id
  );
  const alreadyCompleted = !!oldChallenge;

  if (alreadyCompleted) {
    finalChallenge = {
      ...completedChallenge,
      completedDate: oldChallenge.completedDate
    };
  } else {
    updateData.$push = {
      ...updateData.$push,
      progressTimestamps: Date.now()
    };
    finalChallenge = {
      ...completedChallenge
    };
  }

  updateData.$set = {
    completedChallenges: _.uniqBy(
      [finalChallenge, ...completedChallenges.map(fixCompletedChallengeItem)],
      'id'
    )
  };

  if (
    timezone &&
    timezone !== 'UTC' &&
    (!userTimezone || userTimezone === 'UTC')
  ) {
    updateData.$set = {
      ...updateData.$set,
      timezone: userTimezone
    };
  }
  return {
    alreadyCompleted,
    updateData,
    completedDate: finalChallenge.completedDate
  };
}

function buildChallengeUrl(challenge) {
  const { superBlock, block, dashedName } = challenge;
  return `/learn/${dasherize(superBlock)}/${dasherize(block)}/${dashedName}`;
}

function getFirstChallenge(Challenge) {
  return new Promise(resolve => {
    Challenge.find(
      { where: { challengeOrder: 0, superOrder: 1, order: 0 } },
      (err, challenge) => {
        if (err) {
          console.log(err);
          return resolve('/learn');
        }
        return resolve(buildChallengeUrl(challenge));
      }
    );
  });
}

async function createChallengeUrlResolver(app) {
  const { Challenge } = app.models;
  const cache = new Map();
  const firstChallenge = await getFirstChallenge(Challenge);

  return function resolveChallengeUrl(id) {
    return new Promise(resolve => {
      if (cache.has(id)) {
        return resolve(cache.get(id));
      }
      return Challenge.findById(id, (err, challenge) => {
        if (err) {
          console.log(err);
          return firstChallenge;
        }
        const challengeUrl = buildChallengeUrl(challenge);
        cache.set(id, challengeUrl);
        return resolve(challengeUrl);
      });
    });
  };
}

export default async function bootChallenge(app, done) {
  const send200toNonUser = ifNoUserSend(true);
  const api = app.loopback.Router();
  const router = app.loopback.Router();
  const challengeUrlResolver = await createChallengeUrlResolver(app);

  api.post(
    '/modern-challenge-completed',
    send200toNonUser,
    modernChallengeCompleted
  );

  // deprecate endpoint
  // remove once new endpoint is live
  api.post('/completed-challenge', send200toNonUser, completedChallenge);

  api.post('/challenge-completed', send200toNonUser, completedChallenge);

  // deprecate endpoint
  // remove once new endpoint is live
  api.post(
    '/completed-zipline-or-basejump',
    send200toNonUser,
    projectCompleted
  );

  api.post('/project-completed', send200toNonUser, projectCompleted);

  api.post(
    '/backend-challenge-completed',
    send200toNonUser,
    backendChallengeCompleted
  );

  router.get('/challenges/current-challenge', redirectToCurrentChallenge);

  router.get('/challenges', redirectToLearn);

  router.get('/challenges/*', redirectToLearn);

  router.get('/map', redirectToLearn);

  app.use(api);
  app.use('/external', api);
  app.use('/internal', api);
  app.use(router);

  function modernChallengeCompleted(req, res, next) {
    const type = accepts(req).type('html', 'json', 'text');
    req.checkBody('id', 'id must be an ObjectId').isMongoId();

    const errors = req.validationErrors(true);
    if (errors) {
      if (type === 'json') {
        return res.status(403).send({ errors });
      }

      log('errors', errors);
      return res.sendStatus(403);
    }

    const user = req.user;
    return user
      .getCompletedChallenges$()
      .flatMap(() => {
        const completedDate = Date.now();
        const { id, files } = req.body;

        const { alreadyCompleted, updateData } = buildUserUpdate(user, id, {
          id,
          files,
          completedDate
        });

        const points = alreadyCompleted ? user.points : user.points + 1;
        const updatePromise = new Promise((resolve, reject) =>
          user.updateAttributes(updateData, err => {
            if (err) {
              return reject(err);
            }
            return resolve();
          })
        );
        return Observable.fromPromise(updatePromise).map(() => {
          if (type === 'json') {
            return res.json({
              points,
              alreadyCompleted,
              completedDate
            });
          }
          return res.sendStatus(200);
        });
      })
      .subscribe(() => {}, next);
  }

  function completedChallenge(req, res, next) {
    req.checkBody('id', 'id must be an ObjectId').isMongoId();
    const type = accepts(req).type('html', 'json', 'text');
    const errors = req.validationErrors(true);

    const { user } = req;

    if (errors) {
      if (type === 'json') {
        return res.status(403).send({ errors });
      }

      log('errors', errors);
      return res.sendStatus(403);
    }

    return user
      .getCompletedChallenges$()
      .flatMap(() => {
        const completedDate = Date.now();
        const { id, solution, timezone, files } = req.body;

        const { alreadyCompleted, updateData } = buildUserUpdate(
          user,
          id,
          { id, solution, completedDate, files },
          timezone
        );

        const points = alreadyCompleted ? user.points : user.points + 1;

        const updatePromise = new Promise((resolve, reject) =>
          user.updateAttributes(updateData, err => {
            if (err) {
              return reject(err);
            }
            return resolve();
          })
        );
        return Observable.fromPromise(updatePromise).map(() => {
          if (type === 'json') {
            return res.json({
              points,
              alreadyCompleted,
              completedDate
            });
          }
          return res.sendStatus(200);
        });
      })
      .subscribe(() => {}, next);
  }

  function projectCompleted(req, res, next) {
    const type = accepts(req).type('html', 'json', 'text');
    req.checkBody('id', 'id must be an ObjectId').isMongoId();
    req.checkBody('challengeType', 'must be a number').isNumber();
    req.checkBody('solution', 'solution must be a URL').isURL();

    const errors = req.validationErrors(true);

    if (errors) {
      if (type === 'json') {
        return res.status(403).send({ errors });
      }
      log('errors', errors);
      return res.sendStatus(403);
    }

    const { user, body = {} } = req;

    const completedChallenge = _.pick(body, [
      'id',
      'solution',
      'githubLink',
      'challengeType',
      'files'
    ]);
    completedChallenge.completedDate = Date.now();

    if (
      !completedChallenge.solution ||
      // only basejumps require github links
      (completedChallenge.challengeType === 4 && !completedChallenge.githubLink)
    ) {
      req.flash(
        'danger',
        "You haven't supplied the necessary URLs for us to inspect your work."
      );
      return res.sendStatus(403);
    }

    return user
      .getCompletedChallenges$()
      .flatMap(() => {
        const { alreadyCompleted, updateData } = buildUserUpdate(
          user,
          completedChallenge.id,
          completedChallenge
        );

        const updatePromise = new Promise((resolve, reject) =>
          user.updateAttributes(updateData, err => {
            if (err) {
              return reject(err);
            }
            return resolve();
          })
        );
        return Observable.fromPromise(updatePromise).doOnNext(() => {
          if (type === 'json') {
            return res.send({
              alreadyCompleted,
              points: alreadyCompleted ? user.points : user.points + 1,
              completedDate: completedChallenge.completedDate
            });
          }
          return res.status(200).send(true);
        });
      })
      .subscribe(() => {}, next);
  }

  function backendChallengeCompleted(req, res, next) {
    const type = accepts(req).type('html', 'json', 'text');
    req.checkBody('id', 'id must be an ObjectId').isMongoId();
    req.checkBody('solution', 'solution must be a URL').isURL();

    const errors = req.validationErrors(true);

    if (errors) {
      if (type === 'json') {
        return res.status(403).send({ errors });
      }
      log('errors', errors);
      return res.sendStatus(403);
    }

    const { user, body = {} } = req;

    const completedChallenge = _.pick(body, ['id', 'solution']);
    completedChallenge.completedDate = Date.now();

    return user
      .getCompletedChallenges$()
      .flatMap(() => {
        const { alreadyCompleted, updateData } = buildUserUpdate(
          user,
          completedChallenge.id,
          completedChallenge
        );

        const updatePromise = new Promise((resolve, reject) =>
          user.updateAttributes(updateData, err => {
            if (err) {
              return reject(err);
            }
            return resolve();
          })
        );
        return Observable.fromPromise(updatePromise).doOnNext(() => {
          if (type === 'json') {
            return res.send({
              alreadyCompleted,
              points: alreadyCompleted ? user.points : user.points + 1,
              completedDate: completedChallenge.completedDate
            });
          }
          return res.status(200).send(true);
        });
      })
      .subscribe(() => {}, next);
  }

  async function redirectToCurrentChallenge(req, res, next) {
    const { user } = req;
    const challengeId = user && user.currentChallengeId;
    log(req.user.username);
    log(challengeId);
    const challengeUrl = await challengeUrlResolver(challengeId).catch(next);
    log(challengeUrl);
    if (challengeUrl === '/learn') {
      // this should normally not be hit if database is properly seeded
      throw new Error(dedent`
        Attempted to find the url for ${challengeId}'
        but came up empty.
        db may not be properly seeded.
      `);
    }
    return res.redirect(`${homeLocation}${challengeUrl}`);
  }

  function redirectToLearn(req, res) {
    const maybeChallenge = _.last(req.path.split('/'));
    if (maybeChallenge in pathMigrations) {
      const redirectPath = pathMigrations[maybeChallenge];
      return res.status(302).redirect(`${learnURL}${redirectPath}`);
    }
    return res.status(302).redirect(learnURL);
  }
  done();
}
<commit_msg>fix: Handle no user request<commit_after>/**
 *
 * Any ref to fixCompletedChallengesItem should be removed post
 * a db migration to fix all completedChallenges
 *
 */
import { Observable } from 'rx';
import _ from 'lodash';
import debug from 'debug';
import accepts from 'accepts';
import dedent from 'dedent';

import { homeLocation } from '../../../config/env.json';

import { ifNoUserSend } from '../utils/middleware';
import { dasherize } from '../utils';
import pathMigrations from '../resources/pathMigration.json';
import { fixCompletedChallengeItem } from '../../common/utils';

const log = debug('fcc:boot:challenges');

const learnURL = `${homeLocation}/learn`;

const jsProjects = [
  'aaa48de84e1ecc7c742e1124',
  'a7f4d8f2483413a6ce226cac',
  '56533eb9ac21ba0edf2244e2',
  'aff0395860f5d3034dc0bfc9',
  'aa2e6f85cab2ab736c9a9b24'
];

function buildUserUpdate(user, challengeId, _completedChallenge, timezone) {
  const { files } = _completedChallenge;
  let completedChallenge = {};

  if (jsProjects.includes(challengeId)) {
    completedChallenge = {
      ..._completedChallenge,
      files: Object.keys(files)
        .map(key => files[key])
        .map(file =>
          _.pick(file, ['contents', 'key', 'index', 'name', 'path', 'ext'])
        )
    };
  } else {
    completedChallenge = _.omit(_completedChallenge, ['files']);
  }
  let finalChallenge;
  const updateData = {};
  const { timezone: userTimezone, completedChallenges = [] } = user;

  const oldChallenge = _.find(
    completedChallenges,
    ({ id }) => challengeId === id
  );
  const alreadyCompleted = !!oldChallenge;

  if (alreadyCompleted) {
    finalChallenge = {
      ...completedChallenge,
      completedDate: oldChallenge.completedDate
    };
  } else {
    updateData.$push = {
      ...updateData.$push,
      progressTimestamps: Date.now()
    };
    finalChallenge = {
      ...completedChallenge
    };
  }

  updateData.$set = {
    completedChallenges: _.uniqBy(
      [finalChallenge, ...completedChallenges.map(fixCompletedChallengeItem)],
      'id'
    )
  };

  if (
    timezone &&
    timezone !== 'UTC' &&
    (!userTimezone || userTimezone === 'UTC')
  ) {
    updateData.$set = {
      ...updateData.$set,
      timezone: userTimezone
    };
  }
  return {
    alreadyCompleted,
    updateData,
    completedDate: finalChallenge.completedDate
  };
}

function buildChallengeUrl(challenge) {
  const { superBlock, block, dashedName } = challenge;
  return `/learn/${dasherize(superBlock)}/${dasherize(block)}/${dashedName}`;
}

function getFirstChallenge(Challenge) {
  return new Promise(resolve => {
    Challenge.find(
      { where: { challengeOrder: 0, superOrder: 1, order: 0 } },
      (err, challenge) => {
        if (err) {
          console.log(err);
          return resolve('/learn');
        }
        return resolve(buildChallengeUrl(challenge));
      }
    );
  });
}

async function createChallengeUrlResolver(app) {
  const { Challenge } = app.models;
  const cache = new Map();
  const firstChallenge = await getFirstChallenge(Challenge);

  return function resolveChallengeUrl(id) {
    return new Promise(resolve => {
      if (cache.has(id)) {
        return resolve(cache.get(id));
      }
      return Challenge.findById(id, (err, challenge) => {
        if (err) {
          console.log(err);
          return firstChallenge;
        }
        const challengeUrl = buildChallengeUrl(challenge);
        cache.set(id, challengeUrl);
        return resolve(challengeUrl);
      });
    });
  };
}

export default async function bootChallenge(app, done) {
  const send200toNonUser = ifNoUserSend(true);
  const api = app.loopback.Router();
  const router = app.loopback.Router();
  const challengeUrlResolver = await createChallengeUrlResolver(app);

  api.post(
    '/modern-challenge-completed',
    send200toNonUser,
    modernChallengeCompleted
  );

  // deprecate endpoint
  // remove once new endpoint is live
  api.post('/completed-challenge', send200toNonUser, completedChallenge);

  api.post('/challenge-completed', send200toNonUser, completedChallenge);

  // deprecate endpoint
  // remove once new endpoint is live
  api.post(
    '/completed-zipline-or-basejump',
    send200toNonUser,
    projectCompleted
  );

  api.post('/project-completed', send200toNonUser, projectCompleted);

  api.post(
    '/backend-challenge-completed',
    send200toNonUser,
    backendChallengeCompleted
  );

  router.get('/challenges/current-challenge', redirectToCurrentChallenge);

  router.get('/challenges', redirectToLearn);

  router.get('/challenges/*', redirectToLearn);

  router.get('/map', redirectToLearn);

  app.use(api);
  app.use('/external', api);
  app.use('/internal', api);
  app.use(router);

  function modernChallengeCompleted(req, res, next) {
    const type = accepts(req).type('html', 'json', 'text');
    req.checkBody('id', 'id must be an ObjectId').isMongoId();

    const errors = req.validationErrors(true);
    if (errors) {
      if (type === 'json') {
        return res.status(403).send({ errors });
      }

      log('errors', errors);
      return res.sendStatus(403);
    }

    const user = req.user;
    return user
      .getCompletedChallenges$()
      .flatMap(() => {
        const completedDate = Date.now();
        const { id, files } = req.body;

        const { alreadyCompleted, updateData } = buildUserUpdate(user, id, {
          id,
          files,
          completedDate
        });

        const points = alreadyCompleted ? user.points : user.points + 1;
        const updatePromise = new Promise((resolve, reject) =>
          user.updateAttributes(updateData, err => {
            if (err) {
              return reject(err);
            }
            return resolve();
          })
        );
        return Observable.fromPromise(updatePromise).map(() => {
          if (type === 'json') {
            return res.json({
              points,
              alreadyCompleted,
              completedDate
            });
          }
          return res.sendStatus(200);
        });
      })
      .subscribe(() => {}, next);
  }

  function completedChallenge(req, res, next) {
    req.checkBody('id', 'id must be an ObjectId').isMongoId();
    const type = accepts(req).type('html', 'json', 'text');
    const errors = req.validationErrors(true);

    const { user } = req;

    if (errors) {
      if (type === 'json') {
        return res.status(403).send({ errors });
      }

      log('errors', errors);
      return res.sendStatus(403);
    }

    return user
      .getCompletedChallenges$()
      .flatMap(() => {
        const completedDate = Date.now();
        const { id, solution, timezone, files } = req.body;

        const { alreadyCompleted, updateData } = buildUserUpdate(
          user,
          id,
          { id, solution, completedDate, files },
          timezone
        );

        const points = alreadyCompleted ? user.points : user.points + 1;

        const updatePromise = new Promise((resolve, reject) =>
          user.updateAttributes(updateData, err => {
            if (err) {
              return reject(err);
            }
            return resolve();
          })
        );
        return Observable.fromPromise(updatePromise).map(() => {
          if (type === 'json') {
            return res.json({
              points,
              alreadyCompleted,
              completedDate
            });
          }
          return res.sendStatus(200);
        });
      })
      .subscribe(() => {}, next);
  }

  function projectCompleted(req, res, next) {
    const type = accepts(req).type('html', 'json', 'text');
    req.checkBody('id', 'id must be an ObjectId').isMongoId();
    req.checkBody('challengeType', 'must be a number').isNumber();
    req.checkBody('solution', 'solution must be a URL').isURL();

    const errors = req.validationErrors(true);

    if (errors) {
      if (type === 'json') {
        return res.status(403).send({ errors });
      }
      log('errors', errors);
      return res.sendStatus(403);
    }

    const { user, body = {} } = req;

    const completedChallenge = _.pick(body, [
      'id',
      'solution',
      'githubLink',
      'challengeType',
      'files'
    ]);
    completedChallenge.completedDate = Date.now();

    if (
      !completedChallenge.solution ||
      // only basejumps require github links
      (completedChallenge.challengeType === 4 && !completedChallenge.githubLink)
    ) {
      req.flash(
        'danger',
        "You haven't supplied the necessary URLs for us to inspect your work."
      );
      return res.sendStatus(403);
    }

    return user
      .getCompletedChallenges$()
      .flatMap(() => {
        const { alreadyCompleted, updateData } = buildUserUpdate(
          user,
          completedChallenge.id,
          completedChallenge
        );

        const updatePromise = new Promise((resolve, reject) =>
          user.updateAttributes(updateData, err => {
            if (err) {
              return reject(err);
            }
            return resolve();
          })
        );
        return Observable.fromPromise(updatePromise).doOnNext(() => {
          if (type === 'json') {
            return res.send({
              alreadyCompleted,
              points: alreadyCompleted ? user.points : user.points + 1,
              completedDate: completedChallenge.completedDate
            });
          }
          return res.status(200).send(true);
        });
      })
      .subscribe(() => {}, next);
  }

  function backendChallengeCompleted(req, res, next) {
    const type = accepts(req).type('html', 'json', 'text');
    req.checkBody('id', 'id must be an ObjectId').isMongoId();
    req.checkBody('solution', 'solution must be a URL').isURL();

    const errors = req.validationErrors(true);

    if (errors) {
      if (type === 'json') {
        return res.status(403).send({ errors });
      }
      log('errors', errors);
      return res.sendStatus(403);
    }

    const { user, body = {} } = req;

    const completedChallenge = _.pick(body, ['id', 'solution']);
    completedChallenge.completedDate = Date.now();

    return user
      .getCompletedChallenges$()
      .flatMap(() => {
        const { alreadyCompleted, updateData } = buildUserUpdate(
          user,
          completedChallenge.id,
          completedChallenge
        );

        const updatePromise = new Promise((resolve, reject) =>
          user.updateAttributes(updateData, err => {
            if (err) {
              return reject(err);
            }
            return resolve();
          })
        );
        return Observable.fromPromise(updatePromise).doOnNext(() => {
          if (type === 'json') {
            return res.send({
              alreadyCompleted,
              points: alreadyCompleted ? user.points : user.points + 1,
              completedDate: completedChallenge.completedDate
            });
          }
          return res.status(200).send(true);
        });
      })
      .subscribe(() => {}, next);
  }

  async function redirectToCurrentChallenge(req, res, next) {
    const { user } = req;
    if (!user) {
      return res.redirect(learnURL);
    }
    const challengeId = user && user.currentChallengeId;
    log(req.user.username);
    log(challengeId);
    const challengeUrl = await challengeUrlResolver(challengeId).catch(next);
    log(challengeUrl);
    if (challengeUrl === '/learn') {
      // this should normally not be hit if database is properly seeded
      throw new Error(dedent`
        Attempted to find the url for ${challengeId}'
        but came up empty.
        db may not be properly seeded.
      `);
    }
    return res.redirect(`${homeLocation}${challengeUrl}`);
  }

  function redirectToLearn(req, res) {
    const maybeChallenge = _.last(req.path.split('/'));
    if (maybeChallenge in pathMigrations) {
      const redirectPath = pathMigrations[maybeChallenge];
      return res.status(302).redirect(`${learnURL}${redirectPath}`);
    }
    return res.status(302).redirect(learnURL);
  }
  done();
}
<|endoftext|>


<commit_before>/* global Connector, sails */
"use strict";

/**
 * ResearchEntityController
 *
 * @description :: Server-side logic for managing Researchentities
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

var actionUtil = require('sails/lib/hooks/blueprints/actionUtil');

module.exports = {
    createDraft: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var draftData = req.body;
        var Model = getModel(req);
        return res.halt(Model.createDraft(Model, researchEntityId, draftData));
    },
    unverifyDocument: function (req, res) {
        var researcEntityId = req.params.researchEntityId;
        var documentId = req.params.documentId;
        var Model = getModel(req);
        res.halt(Model.unverifyDocument(Model, researcEntityId, documentId));
    },
    verifyDraft: function (req, res) {
        const researchEntityId = req.params.researchEntityId;
        const draftId = req.params.draftId;
        const verificationData = {
            position: req.body.position,
            corresponding: req.body.corresponding,
            affiliationInstituteIds: req.body.affiliations,
            synchronize: req.body.synchronize,
            public: req.body.public,
        };
        const Model = getModel(req);
        res.halt(Model.verifyDraft(Model, researchEntityId, draftId, verificationData));
    },
    verifyDrafts: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var draftIds = req.param('draftIds');
        var Model = getModel(req);
        res.halt(Model.verifyDrafts(Model, researchEntityId, draftIds));
    },
    verifyDocument: function (req, res) {
        const researchEntityId = req.params.researchEntityId;
        const documentId = req.body.id;
        const verificationData = {
            position: req.body.position,
            corresponding: req.body.corresponding,
            affiliationInstituteIds: req.body.affiliations,
            synchronize: req.body.synchronize,
            public: req.body.public
        };
        const Model = getModel(req);
        // TODO in case of failed verify give response with details instead of 400
        res.halt(Model.verifyDocument(Model, researchEntityId, documentId, verificationData));
    },
    verifyDocuments: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var documentIds = req.param('documentIds');
        var Model = getModel(req);
        res.halt(Model.verifyDocuments(Model, researchEntityId, documentIds));
    },
    discardDocument: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var documentId = req.param('documentId');
        var Model = getModel(req);
        res.halt(Model.discardDocument(Model, researchEntityId, documentId));
    },
    discardDocuments: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var documentIds = req.param('documentIds');
        var Model = getModel(req);
        res.halt(Model.discardDocuments(Model, researchEntityId, documentIds));
    },
    createDrafts: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var documents = req.param('documents');
        var Model = getModel(req);
        res.halt(Model.createDrafts(Model, researchEntityId, documents));
    },
    updateDraft: function (req, res) {
        var draftId = req.params.id;
        var draftData = req.body;
        var Model = getModel(req);
        res.halt(Model.updateDraft(Model, draftId, draftData));
    },
    getChartsData: function (req, res) {
        var modelName = req.options.model || req.options.controller;
        var id = req.params.researchEntityId;
        res.halt(Chart.getChartsData(id, modelName));
    },
    setAuthorhips: function (req, res) {
        const draftId = req.params.documentId;
        const authorshipsData = req.body;
        res.halt(Document.setAuthorships(draftId, authorshipsData));
    },
    updateProfile: function (req, res) {
        const researchEntityId = req.params.researchEntityId;
        const Model = getModel(req);
        const researchEntityData = req.body;
        res.halt(Model.updateProfile(Model, researchEntityId, researchEntityData));
    },
    deleteDraft: function (req, res) {
        const Model = getModel(req);
        const draftId = req.params.draftId;
        res.halt(Model.deleteDraft(Model, draftId));
    },
    deleteDrafts: function (req, res) {
        const Model = getModel(req);
        var draftIds = req.param('draftIds');
        res.halt(Model.deleteDrafts(Model, draftIds));
    },
    setAuthorshipPrivacy: function (req, res) {
        const researchEntityId = req.params.researchEntityId;
        const documentId = req.params.documentId;
        const AuthorshipModel = getAuthorshipModel(req);
        const privacy = req.body.privacy;
        res.halt(AuthorshipModel.setPrivacy(documentId, researchEntityId, privacy));
    },
    getPublicDocuments: async (req, res) => {
        const researchEntityModel = getModel(req);
        const searchKey = getSearchKey(researchEntityModel);
        const searchCriteria = {
            [searchKey]: req.params[searchKey]
        };
        const attribute = `publicDocuments`;
        res.halt(researchEntityModel.makeInternalRequest(researchEntityModel, searchCriteria, req.query, attribute));
    },
    getPublications: async (req, res) => {
        const researchEntityModel = getModel(req);
        const searchKey = getSearchKey(researchEntityModel);
        const searchCriteria = {
            [searchKey]: req.params[searchKey]
        };
        const attribute = `publications`;
        res.halt(researchEntityModel.makeInternalRequest(researchEntityModel, searchCriteria, req.query, attribute));
    },
    getDisseminationTalks: async (req, res) => {
        const researchEntityModel = getModel(req);
        const searchKey = getSearchKey(researchEntityModel);
        const searchCriteria = {
            [searchKey]: req.params[searchKey]
        };
        const attribute = `disseminationTalks`;
        res.halt(researchEntityModel.makeInternalRequest(researchEntityModel, searchCriteria, req.query, attribute));
    },
    getScientificTalks: async (req, res) => {
        const researchEntityModel = getModel(req);
        const searchKey = getSearchKey(researchEntityModel);
        const searchCriteria = {
            [searchKey]: req.params[searchKey]
        };
        const attribute = `scientificTalks`;
        res.halt(researchEntityModel.makeInternalRequest(researchEntityModel, searchCriteria, req.query, attribute));
    }
};

function getModel(req) {
    const model_name = req.options.model || req.options.controller;
    return req._sails.models[model_name];
}

function getAuthorshipModel(req) {
    const Model = getModel(req);
    return Model.getAuthorshipModel();
}

function getSearchKey(Model) {
    const searchKey = _.findKey(Model._attributes, a => a.searchKey);
    return searchKey;
}

function getPopulateFields(req) {
    var populate = req.query.populate;
    if (_.isString(populate))
        populate = [populate];
    return populate;
}

function getQuery(req) {
    var query = {
        limit: actionUtil.parseLimit(req),
        skip: actionUtil.parseSkip(req),
        where: JSON.parse(req.query.where || '{}')
    };
    return query;
}

<commit_msg>Refactor.<commit_after>/* global Connector, sails */
"use strict";

/**
 * ResearchEntityController
 *
 * @description :: Server-side logic for managing Researchentities
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

var actionUtil = require('sails/lib/hooks/blueprints/actionUtil');

module.exports = {
    createDraft: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var draftData = req.body;
        var Model = getModel(req);
        return res.halt(Model.createDraft(Model, researchEntityId, draftData));
    },
    unverifyDocument: function (req, res) {
        var researcEntityId = req.params.researchEntityId;
        var documentId = req.params.documentId;
        var Model = getModel(req);
        res.halt(Model.unverifyDocument(Model, researcEntityId, documentId));
    },
    verifyDraft: function (req, res) {
        const researchEntityId = req.params.researchEntityId;
        const draftId = req.params.draftId;
        const verificationData = {
            position: req.body.position,
            corresponding: req.body.corresponding,
            affiliationInstituteIds: req.body.affiliations,
            synchronize: req.body.synchronize,
            public: req.body.public,
        };
        const Model = getModel(req);
        res.halt(Model.verifyDraft(Model, researchEntityId, draftId, verificationData));
    },
    verifyDrafts: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var draftIds = req.param('draftIds');
        var Model = getModel(req);
        res.halt(Model.verifyDrafts(Model, researchEntityId, draftIds));
    },
    verifyDocument: function (req, res) {
        const researchEntityId = req.params.researchEntityId;
        const documentId = req.body.id;
        const verificationData = {
            position: req.body.position,
            corresponding: req.body.corresponding,
            affiliationInstituteIds: req.body.affiliations,
            synchronize: req.body.synchronize,
            public: req.body.public
        };
        const Model = getModel(req);
        // TODO in case of failed verify give response with details instead of 400
        res.halt(Model.verifyDocument(Model, researchEntityId, documentId, verificationData));
    },
    verifyDocuments: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var documentIds = req.param('documentIds');
        var Model = getModel(req);
        res.halt(Model.verifyDocuments(Model, researchEntityId, documentIds));
    },
    discardDocument: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var documentId = req.param('documentId');
        var Model = getModel(req);
        res.halt(Model.discardDocument(Model, researchEntityId, documentId));
    },
    discardDocuments: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var documentIds = req.param('documentIds');
        var Model = getModel(req);
        res.halt(Model.discardDocuments(Model, researchEntityId, documentIds));
    },
    createDrafts: function (req, res) {
        var researchEntityId = req.params.researchEntityId;
        var documents = req.param('documents');
        var Model = getModel(req);
        res.halt(Model.createDrafts(Model, researchEntityId, documents));
    },
    updateDraft: function (req, res) {
        var draftId = req.params.id;
        var draftData = req.body;
        var Model = getModel(req);
        res.halt(Model.updateDraft(Model, draftId, draftData));
    },
    getChartsData: function (req, res) {
        var modelName = req.options.model || req.options.controller;
        var id = req.params.researchEntityId;
        res.halt(Chart.getChartsData(id, modelName));
    },
    setAuthorhips: function (req, res) {
        const draftId = req.params.documentId;
        const authorshipsData = req.body;
        res.halt(Document.setAuthorships(draftId, authorshipsData));
    },
    updateProfile: function (req, res) {
        const researchEntityId = req.params.researchEntityId;
        const Model = getModel(req);
        const researchEntityData = req.body;
        res.halt(Model.updateProfile(Model, researchEntityId, researchEntityData));
    },
    deleteDraft: function (req, res) {
        const Model = getModel(req);
        const draftId = req.params.draftId;
        res.halt(Model.deleteDraft(Model, draftId));
    },
    deleteDrafts: function (req, res) {
        const Model = getModel(req);
        var draftIds = req.param('draftIds');
        res.halt(Model.deleteDrafts(Model, draftIds));
    },
    setAuthorshipPrivacy: function (req, res) {
        const researchEntityId = req.params.researchEntityId;
        const documentId = req.params.documentId;
        const AuthorshipModel = getAuthorshipModel(req);
        const privacy = req.body.privacy;
        res.halt(AuthorshipModel.setPrivacy(documentId, researchEntityId, privacy));
    },
    getPublicDocuments: async (req, res) => makePublicAPIrequest(req, res, 'documents'),
    getPublications: async (req, res) => makePublicAPIrequest(req, res, 'publications'),
    getDisseminationTalks: async (req, res) => makePublicAPIrequest(req, res, 'disseminationTalks'),
    getScientificTalks: async (req, res) => makePublicAPIrequest(req, res, 'scientificTalks')
};

function makePublicAPIrequest(req, res, attribute) {
    const researchEntityModel = getModel(req);
    const searchKey = getSearchKey(researchEntityModel);
    const searchCriteria = {
        [searchKey]: req.params[searchKey]
    };
    res.halt(researchEntityModel.makeInternalRequest(researchEntityModel, searchCriteria, req.query, attribute));
}

function getModel(req) {
    const model_name = req.options.model || req.options.controller;
    return req._sails.models[model_name];
}

function getAuthorshipModel(req) {
    const Model = getModel(req);
    return Model.getAuthorshipModel();
}

function getSearchKey(Model) {
    const searchKey = _.findKey(Model._attributes, a => a.searchKey);
    return searchKey;
}

function getPopulateFields(req) {
    var populate = req.query.populate;
    if (_.isString(populate))
        populate = [populate];
    return populate;
}

function getQuery(req) {
    var query = {
        limit: actionUtil.parseLimit(req),
        skip: actionUtil.parseSkip(req),
        where: JSON.parse(req.query.where || '{}')
    };
    return query;
}

<|endoftext|>