<commit_before>(function ($, $$) {

    "use strict";

    var action = "share", shipment;

    var shipments = {
            123:
            {id : 123, status : "Waiting",  description : "Cellular Accessories and Phones",  date: "12/20/2013",
                trucks : [
                    {truck : "Box Truck 304", driverNumber : "D4702",
                        departs : {city : "Denver, CO", day : "12/18/2013", time : "08:15 AM"},
                        arrives : {city : "San Francisco, CA", day : "09/20/2013", time : "09:30 AM"}},
                    {truck : "Box Truck 512", driverNumber : "D0123",
                        departs : {city : "Los Angeles, CA", day : "12/19/2013", time : "08:00 AM"},
                        arrives : {city : "San Francisco, CA", day : "12/19/2013", time : "5:00 PM"}}
                ],
                destination : {name : "The Tech Store", address : {street : "55 Fourth Street", city : "San Francisco", state : "CA", zip : "94103"}},
                total : "$23500.00"
            },
            124:
            {id : 124, status : "Approved", description : "Laptop Supplies",  date: "09/10/2013",
                trucks : [
                    {truck : "Bus 005", driverNumber : "D2702",
                        departs : {city : "Austin, TX", day : "09/5/2013", time : "08:15 AM"},
                        arrives : {city : "San Francisco, CA", day : "09/10/2013", time : "09:30 AM"}},
                    {truck : "Lowboy 201", driverNumber : "UA123",
                        departs : {city : "Las Vegas, NV", day : "09/8/2013", time : "08:00 AM"},
                        arrives : {city : "San Francisco, CA", day : "09/10/2013", time : "5:00 PM"}}
                ],
                destination : {name : "DigiMedia", address : {street : "150 Van Ness St", city : "San Francisco", state : "CA", zip : "94134"}},
                total : "$17750.00"
            },
            125:
            {id : 125, status : "Complete", description : "Tablets",  date: "06/18/2013",
                trucks : [
                    {truck : "Box Truck 117", driverNumber : "D6702",
                        departs : {city : "Salt Lake City, UT", day : "06/14/2013", time : "08:00 AM"},
                        arrives : {city : "San Francisco, CA", day : "06/18/2013", time : "09:30 AM"}}
                ],
                destination : {name : "Munder Difflin Paperless Company", address : {street : "160 Brannan St", city : "San Francisco", state : "CA", zip : "94103"}},
                total : "$13000.00"
            },
            126:
            {id : 126, status : "Complete", description : "TVs, Projectors, and Desktops, oh my!",  date: "04/02/2013",
                trucks : [
                    {truck : "Bus 006", driverNumber : "D2202",
                        departs : {city : "Portland, OR", day : "04/02/2013", time : "08:15 AM"},
                        arrives : {city : "San Francisco, CA", day : "04/05/2013", time : "09:30 AM"}},
                    {truck : "Box Truck 215", driverNumber : "UA123",
                        departs : {city : "San Diego, CA", day : "04/10/2013", time : "03:00 PM"},
                        arrives : {city : "San Francisco, CA", day : "04/12/2013", time : "5:30 PM"}}
                ],
                destination : {name : "Salesforce", address : {street : "1 Market St", city : "San Francisco", state : "CA", zip : "94105"}},
                total : "$3300.00"
            }
        };

    var module = {

        instance : function (sr) {
            var payload;

            function refresh(id) {
                var v, $tbody;
                if (!$$.isNil(id)) {
                    $tbody = $("#reservation tbody");
                    v = shipments[id];
                    $tbody.append(
                        "
" + v.status  +
                            "	" + v.description + "	" + v.total + "	" + v.date + "
");
                }
                else {
                    $tbody = $("#reservations tbody");
                    $.each(shipments, function(i, v) {
                        $tbody.append(
                            "
" + v.status  +
                                "	" + v.description + "	" + v.date + "
");
                    });
                }
            }

            function prettyPrint(id) {

                var it = shipments[id];

                var text = "My Shipment For: " + it.description + "\n";
                	text += "Status: " + it.status + "\n";
                	text += "Date: " + it.date + "\n\n";
                    for (var i = 0; i < it.trucks.length; i++) {
                        var f = it.trucks[i];
                        text += "Truck: " + f.truck + " " + f.driverNumber + "- " + f.departs.city +"\n";
                        text += "Departs: " + f.departs.city + ": " + f.departs.day + " " + f.departs.time + "\n";
                        text += "Arrives: " + f.arrives.city + ": " + f.departs.day + " " + f.arrives.time + "\n\n";
                    }
                    text += "Shipped To: " + it.destination.name + ", " + it.destination.address.street + ", " + it.destination.address.city + ", " + it.destination.address.state + "\n";
                    text += "Total Cost: " + it.total;

                return text;
            }

            function approve(id) {

                $(function() {
                    $("button" )
                        .button()
                        .click(function( event ) {
                            event.preventDefault();
                            action = $(this).attr("id");
                            $("#status").empty().append(("approve" === action) ? "Approved" : "Denied");
                        });
                });

                console.log("Approve...." + id);
                refresh(id);
            }

            function draw() {

                $("#reservations").chromatable({
                    width: "100%",
                    height: "100%",
                    scrolling: "yes"
                });

                $("#reservations").selectable({
                    filter:'tr',
                    selected: function(event, ui){
                        var s = $(this).find('.ui-selected');
                        shipment = s[0].id;
                        console.log("Shipment: " + shipment);

                        // @review - generate named methods instead (fireEnable())
                        console.log("Fire event from client");
                        $$.client.publish(sr.client, {name : 'publisher.setValidForSubmit', payload : true});
                    }
                });

                $( "#radio" ).buttonset();
                $("#radio :radio").click(function(e) {
                    var rawElement = this;
                    var $element = $(this);
                    action = $(this).attr("id");
                    console.log("Action: " + action);
                });

                $( "#switch" ).buttonset();
                $("#switch :radio").click(function(e) {
                    var rawElement = this;
                    var $element = $(this);
                    var tempAction = $(this).attr("id");
                  	action = "share";
                    $('#reservations .ui-selected').removeClass('ui-selected')
                    console.log("Action: " + action);
                });

                $( "#radio2" ).buttonset();
				$("#radio2 :radio").click(function(e) {
                    var rawElement = this;
                    var $element = $(this);
                    action = $(this).attr("id");
                    console.log("Action: " + action);
                });

                refresh();
            }

            var handlers = {
                onSetupPanel : function(payload) {
                	console.log("EH Module setupPanel..", payload);
                },
                onShowPanel : function(payload) {
                    console.log("EH Module showPanel", payload);
                },
                onClearPanelState : function(payload) {
                    console.log("EH Module clearPanelState");
                    // Clear the selected reservation
                    $('#reservations .ui-selected').removeClass('ui-selected')

                    // Clear the selected radio buttons
                    $('input[name="radio"]').prop('checked', false);

                    // Re enable the default selection
                    action = "share";
                    $('#share').prop('checked', true);
                    $("#radio :radio").button( "refresh");
                    $('#itin').prop('checked', true);
                },
                onSuccess : function() {
                    console.log("EH Module onSuccess");
                },
                onFailure : function () {
                    console.log("EH Module onFailure");
                },
                onGetPayload : function () {
                    var p = {};
                    console.log("EH Module getPayload");
                    if ("share" === action) {
                        p.feedItemType = "TextPost";
                        p.auxText = prettyPrint(shipment);
                    }
                    else if ("link" === action) {
                        p.feedItemType = "LinkPost";
                        p.auxText = "Please Approve my trip: " + shipments[shipment].description;
                        p.url = "https://immense-springs-2619.herokuapp.com/signed-request.jsp?shipment=" + shipment; /* change this to your heroku app */
                        p.urlName = shipments[shipment].description;
                    }
                    else if ("approval" === action) {
                         p.feedItemType = "CanvasPost";
                         p.auxText = "Please approve this shipment: " + shipments[shipment].description;
                         p.namespace =  sr.context.application.namespace;
                         p.developerName =  sr.context.application.developerName;
                         p.thumbnailUrl = "https://cdn1.iconfinder.com/data/icons/VISTA/project_managment/png/48/deliverables.png";
                         p.parameters =  "{\"shipment\":\"" + shipment + "\"}";
                         p.title =  "Shipment - " +shipments[shipment].description;
                         p.description = "This is a travel shipment for Shipment - " + shipments[shipment].description + ".  Click the link to open the Canvas App.";
                    }

                    // Note: we can extend the payload here to include more then just value.
                    $$.client.publish(sr.client, {name : 'publisher.setPayload', payload : p});
                }
            };

            var that = {

                draw : draw,
                refresh : refresh,
                approve : approve,

                // Subscriptions to callbacks from publisher...
                subscriptions : [
                    {name : 'publisher.setupPanel', onData : handlers.onSetupPanel},
                    {name : 'publisher.showPanel', onData : handlers.onShowPanel},
                    {name : 'publisher.clearPanelState',  onData : handlers.onClearPanelState},
                    {name : 'publisher.failure', onData : handlers.onFailure},
                    {name : 'publisher.success', onData : handlers.onSuccess},
                    {name : 'publisher.getPayload', onData : handlers.onGetPayload}
                ]
            };
            return that;
        }
    };

    // Replace with module pattern
    window.shipment = module;

}(jQuery, Sfdc.canvas));<commit_msg>add shipment<commit_after>(function ($, $$) {

    "use strict";

    var action = "share", shipment;

    var shipments = {
            123:
            {id : 123, status : "Waiting",  description : "Cellular Accessories and Phones",  date: "12/20/2013",
                trucks : [
                    {truck : "Box Truck 304", driverNumber : "D4702",
                        departs : {city : "Denver, CO", day : "12/18/2013", time : "08:15 AM"},
                        arrives : {city : "San Francisco, CA", day : "09/20/2013", time : "09:30 AM"}},
                    {truck : "Box Truck 512", driverNumber : "D0123",
                        departs : {city : "Los Angeles, CA", day : "12/19/2013", time : "08:00 AM"},
                        arrives : {city : "San Francisco, CA", day : "12/19/2013", time : "5:00 PM"}}
                ],
                destination : {name : "The Tech Store", address : {street : "55 Fourth Street", city : "San Francisco", state : "CA", zip : "94103"}},
                total : "$23500.00"
            },
            124:
            {id : 124, status : "Approved", description : "Laptop Supplies",  date: "09/10/2013",
                trucks : [
                    {truck : "Bus 005", driverNumber : "D2702",
                        departs : {city : "Austin, TX", day : "09/5/2013", time : "08:15 AM"},
                        arrives : {city : "San Francisco, CA", day : "09/10/2013", time : "09:30 AM"}},
                    {truck : "Lowboy 201", driverNumber : "UA123",
                        departs : {city : "Las Vegas, NV", day : "09/8/2013", time : "08:00 AM"},
                        arrives : {city : "San Francisco, CA", day : "09/10/2013", time : "5:00 PM"}}
                ],
                destination : {name : "DigiMedia", address : {street : "150 Van Ness St", city : "San Francisco", state : "CA", zip : "94134"}},
                total : "$17750.00"
            },
            125:
            {id : 125, status : "Complete", description : "Tablets",  date: "06/18/2013",
                trucks : [
                    {truck : "Box Truck 117", driverNumber : "D6702",
                        departs : {city : "Salt Lake City, UT", day : "06/14/2013", time : "08:00 AM"},
                        arrives : {city : "San Francisco, CA", day : "06/18/2013", time : "09:30 AM"}}
                ],
                destination : {name : "Munder Difflin Paperless Company", address : {street : "160 Brannan St", city : "San Francisco", state : "CA", zip : "94103"}},
                total : "$13000.00"
            },
            126:
            {id : 126, status : "Complete", description : "TVs, Projectors, and Desktops, oh my!",  date: "04/02/2013",
                trucks : [
                    {truck : "Bus 006", driverNumber : "D2202",
                        departs : {city : "Portland, OR", day : "04/02/2013", time : "08:15 AM"},
                        arrives : {city : "San Francisco, CA", day : "04/05/2013", time : "09:30 AM"}},
                    {truck : "Box Truck 215", driverNumber : "UA123",
                        departs : {city : "San Diego, CA", day : "04/10/2013", time : "03:00 PM"},
                        arrives : {city : "San Francisco, CA", day : "04/12/2013", time : "5:30 PM"}}
                ],
                destination : {name : "Salesforce", address : {street : "1 Market St", city : "San Francisco", state : "CA", zip : "94105"}},
                total : "$3300.00"
            }
        };

    var module = {

        instance : function (sr) {
            var payload;

            function refresh(id) {
                var v, $tbody;
                if (!$$.isNil(id)) {
                    $tbody = $("#reservation tbody");
                    v = shipments[id];
                    $tbody.append(
                        "
" + v.status  +
                            "	" + v.description + "	" + v.total + "	" + v.date + "
");
                }
                else {
                    $tbody = $("#reservations tbody");
                    $.each(shipments, function(i, v) {
                        $tbody.append(
                            "
" + v.status  +
                                "	" + v.description + "	" + v.date + "
");
                    });
                }
            }

            function prettyPrint(id) {

                var it = shipments[id];

                var text = "My Shipment For: " + it.description + "\n";
                	text += "Status: " + it.status + "\n";
                	text += "Date: " + it.date + "\n\n";
                    for (var i = 0; i < it.trucks.length; i++) {
                        var f = it.trucks[i];
                        text += "Truck: " + f.truck + " " + f.driverNumber + "- " + f.departs.city +"\n";
                        text += "Departs: " + f.departs.city + ": " + f.departs.day + " " + f.departs.time + "\n";
                        text += "Arrives: " + f.arrives.city + ": " + f.departs.day + " " + f.arrives.time + "\n\n";
                    }
                    text += "Shipped To: " + it.destination.name + ", " + it.destination.address.street + ", " + it.destination.address.city + ", " + it.destination.address.state + "\n";
                    text += "Total Cost: " + it.total;

                return text;
            }

            function approve(id) {

                $(function() {
                    $("button" )
                        .button()
                        .click(function( event ) {
                            event.preventDefault();
                            action = $(this).attr("id");
                            $("#status").empty().append(("approve" === action) ? "Approved" : "Denied");
                        });
                });

                console.log("Approve...." + id);
                refresh(id);
            }

            function draw() {

                $("#reservations").chromatable({
                    width: "100%",
                    height: "100%",
                    scrolling: "yes"
                });

                $("#reservations").selectable({
                    filter:'tr',
                    selected: function(event, ui){
                        var s = $(this).find('.ui-selected');
                        shipment = s[0].id;
                        console.log("Shipment: " + shipment);

                        // @review - generate named methods instead (fireEnable())
                        console.log("Fire event from client");
                        $$.client.publish(sr.client, {name : 'publisher.setValidForSubmit', payload : true});
                    }
                });

                $( "#radio" ).buttonset();
                $("#radio :radio").click(function(e) {
                    var rawElement = this;
                    var $element = $(this);
                    action = $(this).attr("id");
                    console.log("Action: " + action);
                });

                $( "#switch" ).buttonset();
                $("#switch :radio").click(function(e) {
                    var rawElement = this;
                    var $element = $(this);
                    var tempAction = $(this).attr("id");
                  	action = "share";
                    $('#reservations .ui-selected').removeClass('ui-selected')
                    console.log("Action: " + action);
                });

                $( "#radio2" ).buttonset();
				$("#radio2 :radio").click(function(e) {
                    var rawElement = this;
                    var $element = $(this);
                    action = $(this).attr("id");
                    console.log("Action: " + action);
                });

                refresh();
            }

            var handlers = {
                onSetupPanel : function(payload) {
                	console.log("EH Module setupPanel..", payload);
                },
                onShowPanel : function(payload) {
                    console.log("EH Module showPanel", payload);
                },
                onClearPanelState : function(payload) {
                    console.log("EH Module clearPanelState");
                    // Clear the selected reservation
                    $('#reservations .ui-selected').removeClass('ui-selected')

                    // Clear the selected radio buttons
                    $('input[name="radio"]').prop('checked', false);

                    // Re enable the default selection
                    action = "share";
                    $('#share').prop('checked', true);
                    $("#radio :radio").button( "refresh");
                    $('#itin').prop('checked', true);
                },
                onSuccess : function() {
                    console.log("EH Module onSuccess");
                },
                onFailure : function () {
                    console.log("EH Module onFailure");
                },
                onGetPayload : function () {
                    var p = {};
                    console.log("EH Module getPayload");
                    if ("share" === action) {
                        p.feedItemType = "TextPost";
                        p.auxText = prettyPrint(shipment);
                    }
                    else if ("link" === action) {
                        p.feedItemType = "LinkPost";
                        p.auxText = "Please approve my shipment: " + shipments[shipment].description;
                        p.url = "https://immense-springs-2619.herokuapp.com/signed-request.jsp?shipment=" + shipment; /* change this to your heroku app */
                        p.urlName = shipments[shipment].description;
                    }
                    else if ("approval" === action) {
                         p.feedItemType = "CanvasPost";
                         p.auxText = "Please approve this shipment: " + shipments[shipment].description;
                         p.namespace =  sr.context.application.namespace;
                         p.developerName =  sr.context.application.developerName;
                         p.thumbnailUrl = "https://cdn1.iconfinder.com/data/icons/VISTA/project_managment/png/48/deliverables.png";
                         p.parameters =  "{\"shipment\":\"" + shipment + "\"}";
                         p.title =  "Shipment - " +shipments[shipment].description;
                         p.description = "This is a travel shipment for Shipment - " + shipments[shipment].description + ".  Click the link to open the Canvas App.";
                    }

                    // Note: we can extend the payload here to include more then just value.
                    $$.client.publish(sr.client, {name : 'publisher.setPayload', payload : p});
                }
            };

            var that = {

                draw : draw,
                refresh : refresh,
                approve : approve,

                // Subscriptions to callbacks from publisher...
                subscriptions : [
                    {name : 'publisher.setupPanel', onData : handlers.onSetupPanel},
                    {name : 'publisher.showPanel', onData : handlers.onShowPanel},
                    {name : 'publisher.clearPanelState',  onData : handlers.onClearPanelState},
                    {name : 'publisher.failure', onData : handlers.onFailure},
                    {name : 'publisher.success', onData : handlers.onSuccess},
                    {name : 'publisher.getPayload', onData : handlers.onGetPayload}
                ]
            };
            return that;
        }
    };

    // Replace with module pattern
    window.shipment = module;

}(jQuery, Sfdc.canvas));<|endoftext|>


<commit_before>// functions public to partners
function cgLaunch (URL, name, features) {
    window.open(citygrid.data.dartClickTrackUrl+URL, name, features);
}

// internal tools
var citygrid = {

    // nearby widget
    nearby : {
        createwidget : function(data) {
            var widgeturl = citygrid.common.getHostName(data.site);
            widgeturl += '?what='+data.what;
            widgeturl += '&where='+data.where;
            widgeturl += '&publisher='+data.publisher;
            widgeturl += '&latitude='+data.latitude;
            widgeturl += '&longitude='+data.longitude;
            widgeturl += '&tags='+data.tags;
            widgeturl += '&radius='+data.radius;
            widgeturl += '&callBackFunction='+data.callBackFunction;
            widgeturl += '&callBackUrl='+data.callBackUrl;
            widgeturl += '&adUnitName='+data.adUnitName;
            widgeturl += '&adUnitSize='+data.adUnitSize;
            widgeturl += '&clientIP='+data.clientIP;
            widgeturl += '&dartClickTrackUrl='+data.dartClickTrackUrl;

            citygrid.common.scriptInject(widgeturl);
        }
    },

    // review widget
    review : {
        createwidget : function(data) {
            var widgeturl = citygrid.common.getHostName(data.site);
            widgeturl += '?what='+data.what;
            widgeturl += '&where='+data.where;
            widgeturl += '&publisher='+data.publisher;
            widgeturl += '&latitude='+data.latitude;
            widgeturl += '&longitude='+data.longitude;
            widgeturl += '&tags='+data.tags;
            widgeturl += '&radius='+data.radius;
            widgeturl += '&callBackFunction='+data.callBackFunction;
            widgeturl += '&callBackUrl='+data.callBackUrl;
            widgeturl += '&adUnitName='+data.adUnitName;
            widgeturl += '&adUnitSize='+data.adUnitSize;
            widgeturl += '&clientIP='+data.clientIP;
            widgeturl += '&dartClickTrackUrl='+data.dartClickTrackUrl;

            citygrid.common.scriptInject(widgeturl);
        },

        showDetail : function() {
            document.getElementById('cs_mainContainer').style.display='none';
            document.getElementById('cs_mainContainer_detail').style.display='block';
        },

        hideDetail : function() {
            document.getElementById('cs_mainContainer').style.display='block';
            document.getElementById('cs_mainContainer_detail').style.display='none';
        }
    },

    // common utils functions
    common : {
        scriptInject : function(url) {
            var script = document.createElement("script");
            script.setAttribute("src", url);
            script.setAttribute("type","text/javascript");
            document.body.appendChild(script);
        },

        loadWidget : function(widgetHTML) {
            widgetHTML = widgetHTML.replace(/&/g, "&");
            widgetHTML = widgetHTML.replace(/</g, "<");
            widgetHTML = widgetHTML.replace(/>/g, ">");
            widgetHTML = widgetHTML.replace(/"/g, "\"");
            document.getElementById(citygrid.data.target).innerHTML = widgetHTML;
        },

        getHostName : function(site) {
            if (site == "dev")
                return "http://localhost:8080/web-widgets/getwidget";
            else if (site == "qa")
                return "http://contentads.qat.citygridmedia.com/ads/getwidget";
            else
                return "http://contentads.citygridmedia.com/ads/getwidget";
        },

        checkInput : function(data) {
            // hardcode ad unit name to offers
            data.adUnitName = 'offers';

            // validate user data
            if (!data.what) { data.what = 'Restaurants'; }
            if (!data.where) { data.where = 'West Hollywood, CA'; }
            if (!data.publisher) { data.publisher = ''; }
            if (!data.latitude) { data.latitude = ''; }
            if (!data.longitude) { data.longitude = ''; }
            if (!data.tags) { data.tags = ''; }
            if (!data.radius) { data.radius = '10'; }
            if (!data.callBackUrl) { data.callBackUrl = ''; }
            if (!data.callBackFunction) { data.callBackFunction = ''; }
            if (!data.adUnitSize) { data.adUnitSize = '300x250'; }
            if (!data.clientIP) { data.clientIP = '127.0.0.1'; }

            // validate dart data
            data.dartClickTrackUrl = (window.cgDartTrackUrl) ? window.cgDartTrackUrl : '';

            citygrid.data = data;
            return data;
        }
    }
};

(function() {
    var scriptSrc = document.getElementById("CSWScript").src;
    var data = eval(scriptSrc.split("?var=")[1]);

    data = citygrid.common.checkInput(data);
    citygrid.nearby.createwidget(data);
}());<commit_msg>apply review changes to offers js<commit_after>// functions public to partners
function cgLaunch (URL, name, features) {
    window.open(citygrid.data.dartClickTrackUrl+URL, name, features);
}

// internal tools
var citygrid = {
    common : {
        // sends request to citygrid server
        createwidget : function(data) {
            var widgeturl = citygrid.common.getHostName(data.site);
            widgeturl += '?what='+data.what;
            widgeturl += '&where='+data.where;
            widgeturl += '&publisher='+data.publisher;
            widgeturl += '&latitude='+data.latitude;
            widgeturl += '&longitude='+data.longitude;
            widgeturl += '&tags='+data.tags;
            widgeturl += '&radius='+data.radius;
            widgeturl += '&callBackFunction='+data.callBackFunction;
            widgeturl += '&callBackUrl='+data.callBackUrl;
            widgeturl += '&adUnitName='+data.adUnitName;
            widgeturl += '&adUnitSize='+data.adUnitSize;
            widgeturl += '&clientIP='+data.clientIP;
            widgeturl += '&dartClickTrackUrl='+data.dartClickTrackUrl;

            citygrid.common.scriptInject(widgeturl);
        },

        // script tag injection to fetch html
        scriptInject : function(url) {
            var script = document.createElement("script");
            script.setAttribute("src", url);
            script.setAttribute("type","text/javascript");
            document.body.appendChild(script);
        },

        // call by the code provided by backend
        loadWidget : function(widgetHTML) {
            widgetHTML = widgetHTML.replace(/&/g, "&");
            widgetHTML = widgetHTML.replace(/</g, "<");
            widgetHTML = widgetHTML.replace(/>/g, ">");
            widgetHTML = widgetHTML.replace(/"/g, "\"");
            document.getElementById(citygrid.data.target).innerHTML = widgetHTML;
        },

        getHostName : function(site) {
            if (site == "dev")
                return "http://localhost:8080/web-widgets/getwidget";
            else if (site == "qa")
                return "http://contentads.qat.citygridmedia.com/ads/getwidget";
            else
                return "http://contentads.citygridmedia.com/ads/getwidget";
        },

        checkInput : function(data) {
            // hardcode ad unit name to offers
            data.adUnitName = 'offers';

            // validate user data
            if (!data.what) { data.what = 'Restaurants'; }
            if (!data.where) { data.where = 'Los Angeles, CA'; }
            if (!data.publisher) { data.publisher = ''; }
            if (!data.latitude) { data.latitude = ''; }
            if (!data.longitude) { data.longitude = ''; }
            if (!data.tags) { data.tags = ''; }
            if (!data.radius) { data.radius = '25'; }
            if (!data.callBackUrl) { data.callBackUrl = ''; }
            if (!data.callBackFunction) { data.callBackFunction = ''; }
            if (!data.adUnitSize) { data.adUnitSize = '300x250'; }
            if (!data.clientIP) { data.clientIP = '127.0.0.1'; }

            // validate dart data
            data.dartClickTrackUrl = (window.cgDartTrackUrl) ? window.cgDartTrackUrl : '';

            citygrid.data = data;
            return data;
        }
    }
};

(function() {
    var scriptSrc = document.getElementById("CSWScript").src;
    var data = eval(scriptSrc.split("?var=")[1]);

    data = citygrid.common.checkInput(data);
    citygrid.common.createwidget(data);
}());<|endoftext|>


<commit_before>$(function() {
  var poll_interval = 2

  var relatizer = function(){
    var dt = $(this).text(), relatized = $.relatizeDate(this)
    if ($(this).parents("a").length > 0 || $(this).is("a")) {
      $(this).relatizeDate()
      if (!$(this).attr('title')) {
        $(this).attr('title', dt)
      }
    } else {
      $(this)
        .text('')
        .append( $('')
        .append('' + dt +
                '' +
                relatized + '') )
    }
  };

  $('.time').each(relatizer);

  $('.time a.toggle_format .date_time').hide()

  var format_toggler = function(){
    $('.time a.toggle_format span').toggle()
    $(this).attr('title', $('span:hidden',this).text())
    return false
  };

  $('.time a.toggle_format').click(format_toggler);

  $('.backtrace').click(function() {
    $(this).next().toggle()
    return false
  })

  var poll_start = function(el) {
    var href = el.attr('href')
    el.parent().text('Starting...')
    $("#main").addClass('polling')

    setInterval(function() {
      $.ajax({dataType: 'text', type: 'get', url: href, success: function(data) {
        $('#main').html(data)
        $('#main .time').relatizeDate()
      }})
    }, poll_interval * 1000)

    location.hash = '#poll'

    return false
  };

  if (location.hash == '#poll') poll_start($('a[rel=poll]'))

  $('a[rel=poll]').click(function() { return poll_start($(this)) })

  $('ul.failed li').hover(function() {
    $(this).addClass('hover');
  }, function() {
    $(this).removeClass('hover');
  })

  $('ul.failed a[rel=retry]').click(function() {
    var href = $(this).attr('href');
    $(this).text('Retrying...');
    var parent = $(this).parent();
    $.ajax({dataType: 'text', type: 'get', url: href, success: function(data) {
      parent.html('Retried ' + data + '');
      relatizer.apply($('.time', parent));
      $('.date_time', parent).hide();
      $('a.toggle_format span', parent).click(format_toggler);
    }});
    return false;
  })

  $('#clear-failed-jobs').click(function(){
    return confirm('Are you sure you want to clear ALL failed jobs?');
  })

  $('#retry-failed-jobs').click(function(){
    return confirm('Are you sure you want to retry ALL failed jobs?');
  })
})
<commit_msg>Redirect unauthorized resque-web polling requests to root url<commit_after>$(function() {
  var poll_interval = 2

  var relatizer = function(){
    var dt = $(this).text(), relatized = $.relatizeDate(this)
    if ($(this).parents("a").length > 0 || $(this).is("a")) {
      $(this).relatizeDate()
      if (!$(this).attr('title')) {
        $(this).attr('title', dt)
      }
    } else {
      $(this)
        .text('')
        .append( $('')
        .append('' + dt +
                '' +
                relatized + '') )
    }
  };

  $('.time').each(relatizer);

  $('.time a.toggle_format .date_time').hide()

  var format_toggler = function(){
    $('.time a.toggle_format span').toggle()
    $(this).attr('title', $('span:hidden',this).text())
    return false
  };

  $('.time a.toggle_format').click(format_toggler);

  $('.backtrace').click(function() {
    $(this).next().toggle()
    return false
  })

  var poll_start = function(el) {
    var href = el.attr('href')
    el.parent().text('Starting...')
    $("#main").addClass('polling')

    setInterval(function() {
      $.ajax({dataType: 'text', type: 'get', url: href,
        success: function(data) {
          $('#main').html(data)
          $('#main .time').relatizeDate()
        },
        error: function(data) {
          if (data.status == '401') { window.location.href = '/' }
        }
      })
    }, poll_interval * 1000)

    location.hash = '#poll'

    return false
  };

  if (location.hash == '#poll') poll_start($('a[rel=poll]'))

  $('a[rel=poll]').click(function() { return poll_start($(this)) })

  $('ul.failed li').hover(function() {
    $(this).addClass('hover');
  }, function() {
    $(this).removeClass('hover');
  })

  $('ul.failed a[rel=retry]').click(function() {
    var href = $(this).attr('href');
    $(this).text('Retrying...');
    var parent = $(this).parent();
    $.ajax({dataType: 'text', type: 'get', url: href, success: function(data) {
      parent.html('Retried ' + data + '');
      relatizer.apply($('.time', parent));
      $('.date_time', parent).hide();
      $('a.toggle_format span', parent).click(format_toggler);
    }});
    return false;
  })

  $('#clear-failed-jobs').click(function(){
    return confirm('Are you sure you want to clear ALL failed jobs?');
  })

  $('#retry-failed-jobs').click(function(){
    return confirm('Are you sure you want to retry ALL failed jobs?');
  })
})
<|endoftext|>


<commit_before>'use strict';

const {
  GraphQLSchema,
  GraphQLObjectType,
  GraphQLList,
  GraphQLID,
  GraphQLInt,
  GraphQLFloat,
  GraphQLBoolean,
  GraphQLString,
  GraphQLNonNull,
  printSchema: graphQLPrintSchema,
} = require('graphql');
const titleize = require('underscore.string/titleize');
const camelize = require('underscore.string/camelize');
const { plural, singular } = require('pluralize');

const { EngineError } = require('../../../error');

// Validate IDL definition
// Also performs some transformation, e.g. adding default values
// TODO: use JSON schema validation|transformation instead
// TODO: move all validation into this method
const validateIdlDefinition = function (obj) {
  const modelTypes = Object.keys(obj.models).map(key => obj.models[key].type);
  obj.modelTypes = modelTypes;
  validateModelsDefinition(obj.models, { modelTypes });
  return obj;
};

const validateModelsDefinition = function (obj, { modelTypes }) {
  if (typeof obj !== 'object') { return obj; }

  Object.keys(obj).forEach(attrName => {
    const child = obj[attrName];
    if (typeof child === 'object') {
      // TODO: should detect whether child _could_ have `type` instead (i.e. is a JSON schema), as we want `type` to be optional
      // Adds def.name default value, by using parent property name
      if (child.type && !child.name) {
        child.name = attrName;
      }
      // Definitions of type `object` must have valid `properties`
      if (child.type === 'object') {
        if (!child.properties || typeof child.properties !== 'object' || Object.keys(child.properties).length === 0) {
          throw new EngineError(`The following definition of type 'object' is missing 'properties': ${JSON.stringify(child)}`, {
            reason: 'IDL_WRONG_DEFINITION',
          });
        }
      }
      // Replace { type: "Model" } by { type: "object", modelName: "Model" }
      const isModel = modelTypes.includes(child.type);
      if (isModel) {
        // Make sure we are not overriding user definitions
        if (child.modelName) {
          throw new EngineError(`The following model cannot have a property named 'modelName': ${JSON.stringify(child)}`, {
            reason: 'IDL_WRONG_DEFINITION',
          });
        }
        Object.assign(child, {
          //type: 'object',
          modelName: child.type,
        });
      }
    }
    // Recurse over children
    validateModelsDefinition(child, { modelTypes });
  }, {});

  return obj;
};

// Transforms an IDL definition into an object easy to parse by GraphQL
const getRootDefinition = function ({ definitions, bulkOptions: { write: allowBulkWrite, delete: allowBulkDelete } }) {
  const models = validateIdlDefinition(definitions).models;

  const safeOperations = operations.filter(operation => operation.safe);
  const unsafeOperations = operations.filter(operation => {
    return !operation.safe
      && !(!allowBulkWrite && operation.isBulkWrite)
      && !(!allowBulkDelete && operation.isBulkDelete);
  });
  const safeProperties = getOperationDefinitions({ models, operations: safeOperations });
  const unsafeProperties = getOperationDefinitions({ models, operations: unsafeOperations });

  return {
    query: {
      name: 'Query',
      type: 'object',
      description: 'Fetches information about different entities',
      properties: safeProperties,
    },
    mutation: {
      name: 'Mutation',
      type: 'object',
      description: 'Modifies information about different entities',
      properties: unsafeProperties,
    },
  };
};

const getOperationDefinitions = function({ models, operations }) {
  return operations.reduce((memo, operation) => {
    const properties = getOperationDefinition({ models, operation });
    Object.assign(memo, properties);
    return memo;
  }, {});
};

const getOperationDefinition = function ({ models, operation }) {
  return Object.keys(models).reduce((properties, modelName) => {
    const model = models[modelName];
    const name = model.name || modelName;
    const def = Object.assign({}, model, { name });

    // `find*` operations are aliased for convenience
    // E.g. `findPet` and `findPets` -> `pet` and `pets`
    const isFind = operation.prefix === 'find';

    // E.g. `updatePets` operation
    let operationName;
    if (operation.multiple) {
      operationName = isFind ? getPluralName(def) : getPluralOperationName(def, operation.prefix);
      properties[operationName] = { type: 'array', items: def };
    // E.g. `updatePet` operation
    } else {
      operationName = isFind ? getSingularName(def) : getSingularOperationName(def, operation.prefix);
      properties[operationName] = def;
    }

    properties[operationName].operation = operation.prefix;

    return properties;
  }, {});
};

/* eslint-disable no-multi-spaces */
const operations = [
  { name: 'findOne',      prefix: 'find',     safe: true,   multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'findMany',     prefix: 'find',     safe: true,   multiple: true,   isBulkWrite: false, isBulkDelete: false },
  { name: 'createOne',    prefix: 'create',   safe: false,  multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'createMany',   prefix: 'create',   safe: false,  multiple: true,   isBulkWrite: true,  isBulkDelete: false },
  { name: 'replaceOne',   prefix: 'replace',  safe: false,  multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'replaceMany',  prefix: 'replace',  safe: false,  multiple: true,   isBulkWrite: true,  isBulkDelete: false },
  { name: 'updateOne',    prefix: 'update',   safe: false,  multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'updateMany',   prefix: 'update',   safe: false,  multiple: true,   isBulkWrite: true,  isBulkDelete: false },
  { name: 'upsertOne',    prefix: 'upsert',   safe: false,  multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'upsertMany',   prefix: 'upsert',   safe: false,  multiple: true,   isBulkWrite: true,  isBulkDelete: false },
  { name: 'deleteOne',    prefix: 'delete',   safe: false,  multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'deleteMany',   prefix: 'delete',   safe: false,  multiple: true,   isBulkWrite: false, isBulkDelete: true  },
];
/* eslint-enable no-multi-spaces */

// Returns GraphQL schema
const getSchema = function ({ definitions, bulkOptions }) {
  if (cache.exists({ rootDef: definitions, type: 'schema', key: 'top' })) {
    return cache.get({ rootDef: definitions, type: 'schema', key: 'top' });
  }

  const rootDef = getRootDefinition({ definitions, bulkOptions });

  // Apply `getType` to each top-level operation, i.e. Query and Mutation
  const topLevelSchema = Object.keys(rootDef).reduce((memo, name) => {
    const def = rootDef[name];
    memo[name] = getType({ def, rootDef });
    return memo;
  }, {});

  const rootSchema = new GraphQLSchema(topLevelSchema);
  cache.set({ rootDef: definitions, type: 'schema', key: 'top', value: rootSchema });
  return rootSchema;
};

// Retrieve a top-level definition, using a type name
const findModel = function ({ type, rootDef }) {
  // Performance optimization
  if (type === 'object') { return; }
  // Flattens root definition
  const models = Object.keys(rootDef).reduce((memo, name) => {
    Object.assign(memo, rootDef[name].properties);
    return memo;
  }, {});
  const name = Object.keys(models).find(modelName => {
    return models[modelName].type === type;
  });
  return models[name];
};

// Retrieves a GraphQL field info for a given IDL definition, i.e. an object that can be passed to new GraphQLObjectType({ fields })
// Includes return type, resolve function, arguments, etc.
const getField = function ({ def, rootDef }) {
  // Dones so that children can get a cached reference of parent type, while avoiding infinite recursion
  if (cache.exists({ key: def, rootDef, type: 'field' })) {
    return cache.get({ key: def, rootDef, type: 'field' });
  }

  // Extract modifiers-specific information from defintion
  const isRequired = def.required;

  // Pass array items definition to `graphQLFieldsInfo`, not array itself
  const isArray = def.items !== undefined;
  const unwrappedDef = isArray ? def.items : def;

  // If a top-level type exists, uses its definition, instead of the sub-definition
  const topDef = findModel({ type: unwrappedDef.type, rootDef });
  const isTopDef = topDef !== undefined;
  const actualDef = isTopDef ? topDef : unwrappedDef;

  // Retrieves correct field
  const fieldInfo = graphQLFieldsInfo.find(possibleType => {
    return possibleType.condition({ isArray, isRequired, isTopDef, def: actualDef });
  });
  if (!fieldInfo) {
    throw new EngineError(`Could not parse property into a GraphQL type: ${JSON.stringify(def)}`, { reason: 'GRAPHQL_WRONG_DEFINITION' });
  }

  const field = fieldInfo.value({ def: actualDef, rootDef });
  field.description = actualDef.description;

  cache.set({ key: def, rootDef, type: 'field', value: field });
  return field;
};

// Retrieves the GraphQL type for a given IDL definition
const getType = function ({ def, rootDef }) {
  return getField({ def, rootDef }).type;
};

// Like `getType`, but modifies current definition
// Goal is to avoid infinite recursion, i.e. without modification the same graphQLFieldsInfo would be hit again
const getModifiedType = function ({ def, rootDef, attributes }) {
  const modifiedDef = Object.assign({}, def, attributes);
  return getType({ def: modifiedDef, rootDef });
};

const executeOperation = async function ({ operation, args = {}, callback }) {
  const response = await callback({ operation, args });
  return response;
};

// Like `graphQLFieldsInfo` but for top-level operations
const graphQLOperationsFieldsInfo = [

  {
    condition: ({ isArray, isTopDef }) => isArray && isTopDef,
    value({ def, rootDef }) {
      const subType = getModifiedType({ def, rootDef, attributes: { type: 'object' } });
      const type = new GraphQLList(subType);
      return {
        type,
        args: {
          id: {
            type: GraphQLInt,
            description: 'id to look at',
            defaultValue: 10
          },
        },
        //description: `Fetches information about a list of ${getPluralName(def)}`,
        async resolve(_, args, { callback }) {
          // TODO: fix this
          const operation = operations[1];
          return await executeOperation({ operation, args, callback });
        },
      };
    },
  },

  {
    condition: ({ isTopDef }) => isTopDef,
    value({ def, rootDef }) {
      const type = getModifiedType({ def, rootDef, attributes: { type: 'object' } });
      return {
        type,
        //description: `Fetches information about a ${getSingularName(def)}`,
        async resolve(_, args, { callback }) {
          // TODO: fix this
          const operation = operations[0];
          return await executeOperation({ operation, args, callback });
        },
      };
    },
  },

];

/**
 * Maps an IDL definition into a GraphQL field information, including type
 * The first matching one will be used, i.e. order matters:
 *   - required modifier comes first
 *   - array modifier comes next
 *   - top-level types must come before normal types
 * Some types modifies the current definition, to avoid infinite recursion, i.e. being hit again on next loop
 */
const graphQLFieldsInfo = [

  {
    condition: ({ isRequired }) => isRequired,
    value({ def, rootDef }) {
      const subType = getModifiedType({ def, rootDef, attributes: { required: false } });
      const type = new GraphQLNonNull(subType);
      return { type };
    },
  },

  ...graphQLOperationsFieldsInfo,

  {
    condition: ({ isArray }) => isArray,
    value({ def, rootDef }) {
      const type = new GraphQLList(getType({ def, rootDef }));
      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'object',
    value({ def, rootDef }) {
      let name = getTypeName(def);
      // Cannot create two GraphQL object types with the same name
      // Fix it by appending underscores to the name
      // TODO: either prefix with top-level model name, or throw exception, or some other better solution
      while (cache.exists({ key: name, rootDef, type: 'typename' })) {
        name += '_';
      }
      cache.set({ key: name, rootDef, type: 'typename', value: true });

      const type = new GraphQLObjectType({
        name,
        description: def.description,

        // This needs to be function, otherwise we run in an infinite recursion,
        // if the children try to reference a parent type
        fields() {
          return Object.keys(def.properties).reduce((fields, attrName) => {
            const childDef = def.properties[attrName];
            fields[attrName] = getField({ def: childDef, rootDef });
            return fields;
          }, {});
        },
      });

      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'integer' && def.format === 'id',
    value() {
      const type = GraphQLID;
      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'integer',
    value() {
      const type = GraphQLInt;
      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'number',
    value() {
      const type = GraphQLFloat;
      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'string',
    value() {
      const type = GraphQLString;
      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'boolean',
    value() {
      const type = GraphQLBoolean;
      return { type };
    },
  },

];

// Returns def.name
const getDefinitionName = function (def) {
  const name = def.name;
  if (!name) {
    throw new EngineError(`Missing "name" key in definition ${JSON.stringify(def)}`, { reason: 'GRAPHQL_WRONG_DEFINITION' });
  }
  return name;
};

// Returns def.name, in plural form, lowercased, e.g. `pets`, for findMany queries
const getPluralName = function (def) {
  const name = getDefinitionName(def);
  return plural(name).toLowerCase();
};

// Returns def.name, in plural form, lowercased, e.g. `pet`, for findOne queries
const getSingularName = function (def) {
  const name = getDefinitionName(def);
  return singular(name).toLowerCase();
};

// Returns operation name, camelized, in plural form, e.g. `findPets` or `deletePets`
const getPluralOperationName = function (def, operation) {
  const name = getPluralName(def);
  return camelize(`${operation} ${name}`);
};

// Returns operation name, camelized, in singular form, e.g. `findPet` or `deletePet`
const getSingularOperationName = function (def, operation) {
  const name = getSingularName(def);
  return camelize(`${operation} ${name}`);
};

// Returns def.name, titleized, e.g. `Pet`, for schema type name
const getTypeName = function (def) {
  const name = getDefinitionName(def);
  return titleize(singular(name));
};

const printSchema = function () {
  const schema = getSchema();
  return graphQLPrintSchema(schema);
};

// General key-value cache, specific for each root IDL definition
const cache = {

  _data: {},

  getBase({ rootDef, type }) {
    const rootDefId = JSON.stringify(rootDef);
    if (!this._data[rootDefId]) {
      this._data[rootDefId] = {};
    }
    const data = this._data[rootDefId];

    if (!data[type]) {
      data[type] = {};
    }
    return data[type];
  },

  get({ rootDef, type, key }) {
    const keyId = JSON.stringify(key);
    const data = this.getBase({ rootDef, type });
    return data[keyId];
  },

  exists({ rootDef, type, key }) {
    return this.get({ rootDef, type, key }) != null;
  },

  set({ rootDef, type, key, value }) {
    const keyId = JSON.stringify(key);
    const data = this.getBase({ rootDef, type });
    data[keyId] = value;
  },

};

module.exports = {
  graphqlGetSchema: getSchema,
  graphqlPrintSchema: printSchema,
};<commit_msg>Transform model.type 'Model' to model.type 'object' in GraphQL parsing<commit_after>'use strict';

const {
  GraphQLSchema,
  GraphQLObjectType,
  GraphQLList,
  GraphQLID,
  GraphQLInt,
  GraphQLFloat,
  GraphQLBoolean,
  GraphQLString,
  GraphQLNonNull,
  printSchema: graphQLPrintSchema,
} = require('graphql');
const titleize = require('underscore.string/titleize');
const camelize = require('underscore.string/camelize');
const { plural, singular } = require('pluralize');

const { EngineError } = require('../../../error');

// Validate IDL definition
// Also performs some transformation, e.g. adding default values
// TODO: use JSON schema validation|transformation instead
// TODO: move all validation into this method
const validateIdlDefinition = function (obj) {
  const modelTypes = Object.keys(obj.models).map(key => obj.models[key].type);
  obj.modelTypes = modelTypes;
  validateModelsDefinition(obj.models, { modelTypes });
  return obj;
};

const validateModelsDefinition = function (obj, { modelTypes }) {
  if (typeof obj !== 'object') { return obj; }

  Object.keys(obj).forEach(attrName => {
    const child = obj[attrName];
    if (typeof child === 'object') {
      // TODO: should detect whether child _could_ have `type` instead (i.e. is a JSON schema), as we want `type` to be optional
      // Adds def.name default value, by using parent property name
      if (child.type && !child.name) {
        child.name = attrName;
      }
      // Definitions of type `object` must have valid `properties`
      if (child.type === 'object') {
        if (!child.properties || typeof child.properties !== 'object' || Object.keys(child.properties).length === 0) {
          throw new EngineError(`The following definition of type 'object' is missing 'properties': ${JSON.stringify(child)}`, {
            reason: 'IDL_WRONG_DEFINITION',
          });
        }
      }
      // Replace { type: "Model" } by { type: "object", modelName: "Model" }
      const isModel = modelTypes.includes(child.type);
      if (isModel) {
        // Make sure we are not overriding user definitions
        if (child.modelName) {
          throw new EngineError(`The following model cannot have a property named 'modelName': ${JSON.stringify(child)}`, {
            reason: 'IDL_WRONG_DEFINITION',
          });
        }
        Object.assign(child, {
          type: 'object',
          modelName: child.type,
        });
      }
    }
    // Recurse over children
    validateModelsDefinition(child, { modelTypes });
  }, {});

  return obj;
};

// Transforms an IDL definition into an object easy to parse by GraphQL
const getRootDefinition = function ({ definitions, bulkOptions: { write: allowBulkWrite, delete: allowBulkDelete } }) {
  const models = validateIdlDefinition(definitions).models;

  const safeOperations = operations.filter(operation => operation.safe);
  const unsafeOperations = operations.filter(operation => {
    return !operation.safe
      && !(!allowBulkWrite && operation.isBulkWrite)
      && !(!allowBulkDelete && operation.isBulkDelete);
  });
  const safeProperties = getOperationDefinitions({ models, operations: safeOperations });
  const unsafeProperties = getOperationDefinitions({ models, operations: unsafeOperations });

  return {
    query: {
      name: 'Query',
      type: 'object',
      description: 'Fetches information about different entities',
      properties: safeProperties,
    },
    mutation: {
      name: 'Mutation',
      type: 'object',
      description: 'Modifies information about different entities',
      properties: unsafeProperties,
    },
  };
};

const getOperationDefinitions = function({ models, operations }) {
  return operations.reduce((memo, operation) => {
    const properties = getOperationDefinition({ models, operation });
    Object.assign(memo, properties);
    return memo;
  }, {});
};

const getOperationDefinition = function ({ models, operation }) {
  return Object.keys(models).reduce((properties, modelName) => {
    const model = models[modelName];
    const name = model.name || modelName;
    const def = Object.assign({}, model, { name });

    // `find*` operations are aliased for convenience
    // E.g. `findPet` and `findPets` -> `pet` and `pets`
    const isFind = operation.prefix === 'find';

    // E.g. `updatePets` operation
    let operationName;
    if (operation.multiple) {
      operationName = isFind ? getPluralName(def) : getPluralOperationName(def, operation.prefix);
      properties[operationName] = { type: 'array', items: def };
    // E.g. `updatePet` operation
    } else {
      operationName = isFind ? getSingularName(def) : getSingularOperationName(def, operation.prefix);
      properties[operationName] = def;
    }

    properties[operationName].operation = operation.prefix;

    return properties;
  }, {});
};

/* eslint-disable no-multi-spaces */
const operations = [
  { name: 'findOne',      prefix: 'find',     safe: true,   multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'findMany',     prefix: 'find',     safe: true,   multiple: true,   isBulkWrite: false, isBulkDelete: false },
  { name: 'createOne',    prefix: 'create',   safe: false,  multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'createMany',   prefix: 'create',   safe: false,  multiple: true,   isBulkWrite: true,  isBulkDelete: false },
  { name: 'replaceOne',   prefix: 'replace',  safe: false,  multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'replaceMany',  prefix: 'replace',  safe: false,  multiple: true,   isBulkWrite: true,  isBulkDelete: false },
  { name: 'updateOne',    prefix: 'update',   safe: false,  multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'updateMany',   prefix: 'update',   safe: false,  multiple: true,   isBulkWrite: true,  isBulkDelete: false },
  { name: 'upsertOne',    prefix: 'upsert',   safe: false,  multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'upsertMany',   prefix: 'upsert',   safe: false,  multiple: true,   isBulkWrite: true,  isBulkDelete: false },
  { name: 'deleteOne',    prefix: 'delete',   safe: false,  multiple: false,  isBulkWrite: false, isBulkDelete: false },
  { name: 'deleteMany',   prefix: 'delete',   safe: false,  multiple: true,   isBulkWrite: false, isBulkDelete: true  },
];
/* eslint-enable no-multi-spaces */

// Returns GraphQL schema
const getSchema = function ({ definitions, bulkOptions }) {
  if (cache.exists({ rootDef: definitions, type: 'schema', key: 'top' })) {
    return cache.get({ rootDef: definitions, type: 'schema', key: 'top' });
  }

  const rootDef = getRootDefinition({ definitions, bulkOptions });

  // Apply `getType` to each top-level operation, i.e. Query and Mutation
  const topLevelSchema = Object.keys(rootDef).reduce((memo, name) => {
    const def = rootDef[name];
    memo[name] = getType({ def, rootDef });
    return memo;
  }, {});

  const rootSchema = new GraphQLSchema(topLevelSchema);
  cache.set({ rootDef: definitions, type: 'schema', key: 'top', value: rootSchema });
  return rootSchema;
};

// Retrieve a top-level definition, using a type name
const findModel = function ({ def, rootDef }) {
  const modelName = def.modelName;
  if (!modelName) { return; }
  // Flattens root definition
  const models = Object.keys(rootDef).reduce((memo, name) => {
    Object.assign(memo, rootDef[name].properties);
    return memo;
  }, {});
  const correctName = Object.keys(models).find(name => {
    return models[name].modelName === modelName;
  });
  return models[correctName];
};

// Retrieves a GraphQL field info for a given IDL definition, i.e. an object that can be passed to new GraphQLObjectType({ fields })
// Includes return type, resolve function, arguments, etc.
const getField = function ({ def, rootDef }) {
  // Dones so that children can get a cached reference of parent type, while avoiding infinite recursion
  if (cache.exists({ key: def, rootDef, type: 'field' })) {
    return cache.get({ key: def, rootDef, type: 'field' });
  }

  // Extract modifiers-specific information from defintion
  const isRequired = def.required;

  // Pass array items definition to `graphQLFieldsInfo`, not array itself
  const isArray = def.items !== undefined;
  const unwrappedDef = isArray ? def.items : def;

  // If a top-level type exists, uses its definition, instead of the sub-definition
  const topDef = findModel({ def: unwrappedDef, rootDef });
  const isTopDef = topDef !== undefined;
  const actualDef = isTopDef ? topDef : unwrappedDef;

  // Retrieves correct field
  const fieldInfo = graphQLFieldsInfo.find(possibleType => {
    return possibleType.condition({ isArray, isRequired, isTopDef, def: actualDef });
  });
  if (!fieldInfo) {
    throw new EngineError(`Could not parse property into a GraphQL type: ${JSON.stringify(def)}`, { reason: 'GRAPHQL_WRONG_DEFINITION' });
  }

  const field = fieldInfo.value({ def: actualDef, rootDef });
  field.description = actualDef.description;

  cache.set({ key: def, rootDef, type: 'field', value: field });
  return field;
};

// Retrieves the GraphQL type for a given IDL definition
const getType = function ({ def, rootDef }) {
  return getField({ def, rootDef }).type;
};

// Like `getType`, but modifies current definition
// Goal is to avoid infinite recursion, i.e. without modification the same graphQLFieldsInfo would be hit again
const getModifiedType = function ({ def, rootDef, attributes }) {
  const modifiedDef = Object.assign({}, def, attributes);
  return getType({ def: modifiedDef, rootDef });
};

const executeOperation = async function ({ operation, args = {}, callback }) {
  const response = await callback({ operation, args });
  return response;
};

// Like `graphQLFieldsInfo` but for top-level operations
const graphQLOperationsFieldsInfo = [

  {
    condition: ({ isArray, isTopDef }) => isArray && isTopDef,
    value({ def, rootDef }) {
      const subType = getModifiedType({ def, rootDef, attributes: { modelName: '' } });
      const type = new GraphQLList(subType);
      return {
        type,
        args: {
          id: {
            type: GraphQLInt,
            description: 'id to look at',
            defaultValue: 10
          },
        },
        //description: `Fetches information about a list of ${getPluralName(def)}`,
        async resolve(_, args, { callback }) {
          // TODO: fix this
          const operation = operations[1];
          return await executeOperation({ operation, args, callback });
        },
      };
    },
  },

  {
    condition: ({ isTopDef }) => isTopDef,
    value({ def, rootDef }) {
      const type = getModifiedType({ def, rootDef, attributes: { modelName: '' } });
      return {
        type,
        //description: `Fetches information about a ${getSingularName(def)}`,
        async resolve(_, args, { callback }) {
          // TODO: fix this
          const operation = operations[0];
          return await executeOperation({ operation, args, callback });
        },
      };
    },
  },

];

/**
 * Maps an IDL definition into a GraphQL field information, including type
 * The first matching one will be used, i.e. order matters:
 *   - required modifier comes first
 *   - array modifier comes next
 *   - top-level types must come before normal types
 * Some types modifies the current definition, to avoid infinite recursion, i.e. being hit again on next loop
 */
const graphQLFieldsInfo = [

  {
    condition: ({ isRequired }) => isRequired,
    value({ def, rootDef }) {
      const subType = getModifiedType({ def, rootDef, attributes: { required: false } });
      const type = new GraphQLNonNull(subType);
      return { type };
    },
  },

  ...graphQLOperationsFieldsInfo,

  {
    condition: ({ isArray }) => isArray,
    value({ def, rootDef }) {
      const type = new GraphQLList(getType({ def, rootDef }));
      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'object',
    value({ def, rootDef }) {
      let name = getTypeName(def);
      // Cannot create two GraphQL object types with the same name
      // Fix it by appending underscores to the name
      // TODO: either prefix with top-level model name, or throw exception, or some other better solution
      while (cache.exists({ key: name, rootDef, type: 'typename' })) {
        name += '_';
      }
      cache.set({ key: name, rootDef, type: 'typename', value: true });

      const type = new GraphQLObjectType({
        name,
        description: def.description,

        // This needs to be function, otherwise we run in an infinite recursion,
        // if the children try to reference a parent type
        fields() {
          return Object.keys(def.properties).reduce((fields, attrName) => {
            const childDef = def.properties[attrName];
            fields[attrName] = getField({ def: childDef, rootDef });
            return fields;
          }, {});
        },
      });

      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'integer' && def.format === 'id',
    value() {
      const type = GraphQLID;
      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'integer',
    value() {
      const type = GraphQLInt;
      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'number',
    value() {
      const type = GraphQLFloat;
      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'string',
    value() {
      const type = GraphQLString;
      return { type };
    },
  },

  {
    condition: ({ def }) => def.type === 'boolean',
    value() {
      const type = GraphQLBoolean;
      return { type };
    },
  },

];

// Returns def.name
const getDefinitionName = function (def) {
  const name = def.name;
  if (!name) {
    throw new EngineError(`Missing "name" key in definition ${JSON.stringify(def)}`, { reason: 'GRAPHQL_WRONG_DEFINITION' });
  }
  return name;
};

// Returns def.name, in plural form, lowercased, e.g. `pets`, for findMany queries
const getPluralName = function (def) {
  const name = getDefinitionName(def);
  return plural(name).toLowerCase();
};

// Returns def.name, in plural form, lowercased, e.g. `pet`, for findOne queries
const getSingularName = function (def) {
  const name = getDefinitionName(def);
  return singular(name).toLowerCase();
};

// Returns operation name, camelized, in plural form, e.g. `findPets` or `deletePets`
const getPluralOperationName = function (def, operation) {
  const name = getPluralName(def);
  return camelize(`${operation} ${name}`);
};

// Returns operation name, camelized, in singular form, e.g. `findPet` or `deletePet`
const getSingularOperationName = function (def, operation) {
  const name = getSingularName(def);
  return camelize(`${operation} ${name}`);
};

// Returns def.name, titleized, e.g. `Pet`, for schema type name
const getTypeName = function (def) {
  const name = getDefinitionName(def);
  return titleize(singular(name));
};

const printSchema = function () {
  const schema = getSchema();
  return graphQLPrintSchema(schema);
};

// General key-value cache, specific for each root IDL definition
const cache = {

  _data: {},

  getBase({ rootDef, type }) {
    const rootDefId = JSON.stringify(rootDef);
    if (!this._data[rootDefId]) {
      this._data[rootDefId] = {};
    }
    const data = this._data[rootDefId];

    if (!data[type]) {
      data[type] = {};
    }
    return data[type];
  },

  get({ rootDef, type, key }) {
    const keyId = JSON.stringify(key);
    const data = this.getBase({ rootDef, type });
    return data[keyId];
  },

  exists({ rootDef, type, key }) {
    return this.get({ rootDef, type, key }) != null;
  },

  set({ rootDef, type, key, value }) {
    const keyId = JSON.stringify(key);
    const data = this.getBase({ rootDef, type });
    data[keyId] = value;
  },

};

module.exports = {
  graphqlGetSchema: getSchema,
  graphqlPrintSchema: printSchema,
};<|endoftext|>


<commit_before>import expect from 'expect';
import requestMiddleware from '../request';
import types from '../../types';
import itemsAPI from '../../api/items';
import { generetaFetchTypes } from '../../shared/type-helper';

const mockData = [{"userId":1,"id":1,"title":"sunt aut facere repellat provident occaecati excepturi optio reprehenderit","body":"quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"},{"userId":1,"id":2,"title":"qui est esse","body":"est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"},{"userId":1,"id":3,"title":"ea molestias quasi exercitationem repellat qui ipsa sit aut","body":"et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"}]

const createFakeStore = fakeData => ({
  getState() {
    return fakeData;
  }
});

const dispatchWithStoreOf = (storeData, action) => {
  let dispatched = null;
  const dispatch = requestMiddleware(createFakeStore(storeData))(actionAttempt => dispatched = actionAttempt);
  dispatch(action);
  return dispatched;
}

describe('middleware', () => {

  describe('request', () => {

    it('requestMiddleware', () => {

      const props= {
        category: 'news'
      };

      const actions = {
        types: generetaFetchTypes(types.ITEMS_REQUEST),
        request: itemsAPI.getItems(props.category)
      };

      const expectedAction = {
        type: 'ITEMS_REQUEST'
      }

      expect(dispatchWithStoreOf({}, actions)).toEqual(expectedAction);
    });

    it('requestMiddleware', () => {

      const actions = {
        types: generetaFetchTypes(types.ITEMS_REQUEST)
      };

      expect(dispatchWithStoreOf({}, actions)).toEqual(actions);
    });

  });

});<commit_msg>udate test middleware<commit_after>import expect from 'expect';
import requestMiddleware from '../request';
import types from '../../types';
import itemsAPI from '../../api/items';
import { generetaFetchTypes } from '../../shared/type-helper';

const mockData = [{"userId":1,"id":1,"title":"sunt aut facere repellat provident occaecati excepturi optio reprehenderit","body":"quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"},{"userId":1,"id":2,"title":"qui est esse","body":"est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"},{"userId":1,"id":3,"title":"ea molestias quasi exercitationem repellat qui ipsa sit aut","body":"et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"}]

const createFakeStore = fakeData => ({
  getState() {
    return fakeData;
  }
});

const dispatchWithStoreOf = (storeData, action) => {
  let dispatched = null;
  const dispatch = requestMiddleware(createFakeStore(storeData))(actionAttempt => dispatched = actionAttempt);
  dispatch(action);
  return dispatched;
}

describe('middleware', () => {

  describe('request', () => {

    it('requestMiddleware with request', () => {

      const props= {
        category: 'news'
      };

      const actions = {
        types: generetaFetchTypes(types.ITEMS_REQUEST),
        request: itemsAPI.getItems(props.category)
      };

      const expectedAction = {
        type: 'ITEMS_REQUEST'
      }

      expect(dispatchWithStoreOf({}, actions)).toEqual(expectedAction);
    });

    it('requestMiddleware without resquest action', () => {

      const actions = {
        types: generetaFetchTypes(types.ITEMS_REQUEST)
      };

      expect(dispatchWithStoreOf({}, actions)).toEqual(actions);
    });

  });

});<|endoftext|>


<commit_before>'use strict';

//var _ = require('lodash');
var Q = require('q');
var expand = require('glob-expand');

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var $28 = new (require('28').$28)('http://portal.28.io/api');
var VFS = require('28').VFS;
var _ = require('lodash');

var Config = require('./config');

var credentials;

var Options = {
    OVERWRITE_ALWAYS: 0,
    OVERWRITE_NEVER: 1,
    OVERWRITE_ASK: 2,
    OVERWRITE_IF_NEWER: 3
};

var castToJson = function(obj){
    var result = obj;
    if(_.isString(obj)){
        try {
            result = JSON.parse(obj);
        } catch (e) {

        }
    }
    return result;
};

var throwError = function (error) {
    var message = JSON.stringify(error);
    if(error.stack || error.filename){
        message = error.toString();
        $.util.log(error.stack);
        $.util.log(error.filename);
    } else if(_.isString(error.message)){
        message = error.message;
    }
    if(error.body){
        var body = castToJson(error.body);
        message = _.isObject(body) ? JSON.stringify(body, null, '\t') : body;
        if((_.isObject(body) && body.context) || (_.isArray(body) && body[0].context)){
            $.util.log(message);
            message = 'Compilation error';
        }
    }

    // truncate error message if too long
    if(message.length > 500){
        message = message.substring(0, 500) + ' ... (truncated)';
    }
    throw new $.util.PluginError(__filename, message);
};

var summarizeTestError = function(error){
    var hasError = false;
    if(error.body) {
        var body = castToJson(error.body);
        if (_.isObject(body) && _.isArray(body.items) && body.items.length > 0) {
            body = castToJson(body.items[0]);
        }
        if (_.isObject(body) && body.content) {
            body = castToJson(body.content);
        }
        /*jshint camelcase:false */
        if (_.isObject(body) && !body.request_id) {
            _.each(body, function(testResult, testName){
                if (_.isObject(testResult) && testResult.url) {
                    hasError = true;
                    $.util.log(testName.red + ': ' + testResult.url);
                    if (_.isObject(testResult.expectedFactTable) && testResult.expectedFactTable.error === true) {
                        // http error (e.g. 404)
                        $.util.log(testName.red + ': ' + JSON.stringify(testResult.expectedFactTable, null, '\t'));
                    }
                    _.each(testResult.factTableDiff, function(diff){
                        if (diff.expectedNumberOfFacts) {
                            $.util.log(testName.red + ': ' + JSON.stringify(diff, null, '\t'));
                        }
                    });
                }
            });
        }
        if (hasError) {
            return new Error('some test queries failed');
        }
    }
    return error;
};

var login = function(email, password){
    $.util.log('Logging in as ' + email);
    return $28.login(email, password).then(function(response){
        $.util.log('Logged in.');
        credentials = response.body;
        return credentials;
    });
};

var removeProject = function(projectName, isIdempotent){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Deleting project ' + projectName);
        $28.deleteProject(projectName, token).then(function () {
            $.util.log('Project deleted.');
            defered.resolve(credentials);
        }).catch(function (error) {
            if (!isIdempotent) {
                defered.reject(error);
            } else {
                defered.resolve(credentials);
            }
        });
    } else {
        $.util.log('Skipping project deletion for production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var createProject = function(projectName){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Creating project ' + projectName);
        $28.createProject(projectName, token).then(function (response) {
            $.util.log('Project  ' + projectName + ' created.');
            /*jshint camelcase:false */
            credentials.project_tokens['project_' + projectName] = response.body.projectToken;
            defered.resolve(credentials);
        }).catch(function (error) {
            $.util.log('Project creation failed: ' + error);
            defered.reject(error);
        });
    } else {
        $.util.log('Skipping project creation on production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var ignoreQueriesFunction = function(list){
    return list;
};

var upload = function(projectName){
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    if(!projectToken) {
        throw new Error('project not found ' + projectName);
    }
    var projectPath = Config.paths.queries;
    var overwrite = Options.OVERWRITE_ALWAYS;
    var deleteOrphaned = true;
    var simulate = false;
    $.util.log('Uploading queries.');
    return $28.upload(projectName, projectToken, projectPath, overwrite, deleteOrphaned, simulate, ignoreQueriesFunction).then(function(){
        $.util.log('Queries uploaded.');
        return credentials;
    });
};

var runQueriesInParallel = function(projectName, queriesToRun) {
    var promises = [];
    var QueriesAPI = $28.api.Queries(projectName);
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    _.each(queriesToRun, function(nextQuery){
        promises.push(
            QueriesAPI.executeQuery({
                accept: 'application/28.io+json',
                queryPath: nextQuery,
                format: '',
                token: projectToken
            }).then(function (data) {
                $.util.log($.util.colors.gree('✓ ') + nextQuery + ' returned with status code: ' + data.response.statusCode);
                return credentials;
            }).catch(function (error) {
                var requestUri = error.response.request.uri;
                var isTestQuery = (requestUri.pathname.lastIndexOf('/v1/_queries/public/test', 0) === 0);
                var href = isTestQuery ? requestUri.host + requestUri.pathname.substring('/v1/_queries/public'.length) : requestUri.host + requestUri.pathname;
                $.util.log($.util.colors.red('✗ ') + href + ' returned with status code: ' + $.util.colors.red(error.response.statusCode));
                error = isTestQuery ? summarizeTestError(error) : error;
                throw error;
            })
        );
    });
    return Q.all(promises);
};

var runQueries = function(projectName, sequenceOfQueriesToRun) {
    return _.chain(sequenceOfQueriesToRun)
        .map(function(queriesToRun) {
            // create chunks of queries to be executed in parallel
            if (_.isString(queriesToRun)) {
                return expand(queriesToRun);
            } else if (_.isArray(queriesToRun)){
                return _.chain(queriesToRun)
                    .map(function(queriesGlob){
                        return expand(queriesGlob);
                    })
                    .flatten()
                    .value();
            }
        })
        .map(function(queriesToRunArray){
            // substring to relative query path
            return _.map(queriesToRunArray, function(query) {
                return query.substring(Config.paths.queries.length + 1);
            });
        })
        .reduce(function(previousPromise, nextQueriesArray){
            // execute them in chunks
            return previousPromise.then(function() {
                return runQueriesInParallel(projectName, nextQueriesArray);
            });
        }, Q.resolve())
        .value();
};

var createDatasource = function(projectName, datasource){
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        $.util.log('Creating datasource ' + datasource.name);
        var difault = datasource.default ? datasource.default : false;
        /*jshint camelcase:false */
        var projectToken = credentials.project_tokens['project_' + projectName];
        $28.createDatasource(projectName, datasource.category, datasource.name, projectToken, difault, JSON.stringify(datasource.credentials))
            .then(function(){
                $.util.log(datasource.name + ' created');
                defered.resolve(credentials);
            })
            .catch(function (error) {
                $.util.log('datasource creation failed: ' + datasource.name);
                defered.reject(error);
            });
    } else {
        $.util.log('Skipping data source creation on production: ' + datasource.name);
        defered.resolve(credentials);
    }
    return defered.promise;
};

gulp.task('28:login', function(){
    return login(Config.credentials['28'].email, Config.credentials['28'].password).catch(throwError);
});

gulp.task('28:create-project', function(){
    return createProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:remove-project', function(){
    return removeProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:upload', function(){
    return upload(Config.projectName).catch(throwError);
});

gulp.task('28:setup-datasource', function(){
    var promises = [];
    Config.credentials['28'].datasources.forEach(function(datasource){
        promises.push(createDatasource(Config.projectName, datasource).catch(throwError));
    });
    return Q.all(promises);
});

gulp.task('28:init', function(){
    return runQueries(Config.projectName, Config.paths.initQueries).catch(throwError);
});

gulp.task('28:test', function(){
    return runQueries(Config.projectName, Config.paths.apiTestQueries).catch(throwError);
});

module.exports = {
    watchJSONiqQueries: function(){
        //Initialize the VFS
        /*jshint camelcase:false */
        var projectName = Config.projectName;
        var projectToken = credentials.project_tokens['project_' + projectName];
        var path = require('path');
        var projectPath = path.resolve(Config.paths.queries);
        var vfs = new VFS($28.api, projectName, projectToken, projectPath);

        //Do the Watch
        gulp.watch(Config.paths.jsoniq, {}, function(event){
            //Get relative query path
            var query = event.path.substring(projectPath.length + 1);
            $.util.log(query + ' has ' + event.type);

            //Upload
            if(event.type === 'added' || event.type === 'changed') {
                $.util.log($.util.colors.grey('Uploading ' + query));
                vfs.writeRemoteQuery(query, true).then(function(result){
                    //Show compilation errors
                    if(result && result.message) {
                        $.util.log($.util.colors.red(result.message));
                    }
                    $.util.log($.util.colors.green(query + ' uploaded'));
                }).catch(function(error){
                    throwError(error);
                });

            //Delete
            } else if(event.type === 'deleted') {
                $.util.log($.util.colors.grey('Removing ' + query));
                vfs.deleteRemoteQuery(query).then(function(){
                    $.util.log($.util.colors.green(query + ' removed'));
                }).catch(function(error){
                    throwError(error);
                });
            }
        });
    }
};
<commit_msg>Fix typo<commit_after>'use strict';

//var _ = require('lodash');
var Q = require('q');
var expand = require('glob-expand');

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var $28 = new (require('28').$28)('http://portal.28.io/api');
var VFS = require('28').VFS;
var _ = require('lodash');

var Config = require('./config');

var credentials;

var Options = {
    OVERWRITE_ALWAYS: 0,
    OVERWRITE_NEVER: 1,
    OVERWRITE_ASK: 2,
    OVERWRITE_IF_NEWER: 3
};

var castToJson = function(obj){
    var result = obj;
    if(_.isString(obj)){
        try {
            result = JSON.parse(obj);
        } catch (e) {

        }
    }
    return result;
};

var throwError = function (error) {
    var message = JSON.stringify(error);
    if(error.stack || error.filename){
        message = error.toString();
        $.util.log(error.stack);
        $.util.log(error.filename);
    } else if(_.isString(error.message)){
        message = error.message;
    }
    if(error.body){
        var body = castToJson(error.body);
        message = _.isObject(body) ? JSON.stringify(body, null, '\t') : body;
        if((_.isObject(body) && body.context) || (_.isArray(body) && body[0].context)){
            $.util.log(message);
            message = 'Compilation error';
        }
    }

    // truncate error message if too long
    if(message.length > 500){
        message = message.substring(0, 500) + ' ... (truncated)';
    }
    throw new $.util.PluginError(__filename, message);
};

var summarizeTestError = function(error){
    var hasError = false;
    if(error.body) {
        var body = castToJson(error.body);
        if (_.isObject(body) && _.isArray(body.items) && body.items.length > 0) {
            body = castToJson(body.items[0]);
        }
        if (_.isObject(body) && body.content) {
            body = castToJson(body.content);
        }
        /*jshint camelcase:false */
        if (_.isObject(body) && !body.request_id) {
            _.each(body, function(testResult, testName){
                if (_.isObject(testResult) && testResult.url) {
                    hasError = true;
                    $.util.log(testName.red + ': ' + testResult.url);
                    if (_.isObject(testResult.expectedFactTable) && testResult.expectedFactTable.error === true) {
                        // http error (e.g. 404)
                        $.util.log(testName.red + ': ' + JSON.stringify(testResult.expectedFactTable, null, '\t'));
                    }
                    _.each(testResult.factTableDiff, function(diff){
                        if (diff.expectedNumberOfFacts) {
                            $.util.log(testName.red + ': ' + JSON.stringify(diff, null, '\t'));
                        }
                    });
                }
            });
        }
        if (hasError) {
            return new Error('some test queries failed');
        }
    }
    return error;
};

var login = function(email, password){
    $.util.log('Logging in as ' + email);
    return $28.login(email, password).then(function(response){
        $.util.log('Logged in.');
        credentials = response.body;
        return credentials;
    });
};

var removeProject = function(projectName, isIdempotent){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Deleting project ' + projectName);
        $28.deleteProject(projectName, token).then(function () {
            $.util.log('Project deleted.');
            defered.resolve(credentials);
        }).catch(function (error) {
            if (!isIdempotent) {
                defered.reject(error);
            } else {
                defered.resolve(credentials);
            }
        });
    } else {
        $.util.log('Skipping project deletion for production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var createProject = function(projectName){
    /*jshint camelcase:false */
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        var token = credentials.access_token;
        $.util.log('Creating project ' + projectName);
        $28.createProject(projectName, token).then(function (response) {
            $.util.log('Project  ' + projectName + ' created.');
            /*jshint camelcase:false */
            credentials.project_tokens['project_' + projectName] = response.body.projectToken;
            defered.resolve(credentials);
        }).catch(function (error) {
            $.util.log('Project creation failed: ' + error);
            defered.reject(error);
        });
    } else {
        $.util.log('Skipping project creation on production: ' + projectName);
        defered.resolve(credentials);
    }
    return defered.promise;
};

var ignoreQueriesFunction = function(list){
    return list;
};

var upload = function(projectName){
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    if(!projectToken) {
        throw new Error('project not found ' + projectName);
    }
    var projectPath = Config.paths.queries;
    var overwrite = Options.OVERWRITE_ALWAYS;
    var deleteOrphaned = true;
    var simulate = false;
    $.util.log('Uploading queries.');
    return $28.upload(projectName, projectToken, projectPath, overwrite, deleteOrphaned, simulate, ignoreQueriesFunction).then(function(){
        $.util.log('Queries uploaded.');
        return credentials;
    });
};

var runQueriesInParallel = function(projectName, queriesToRun) {
    var promises = [];
    var QueriesAPI = $28.api.Queries(projectName);
    /*jshint camelcase:false */
    var projectToken = credentials.project_tokens['project_' + projectName];
    _.each(queriesToRun, function(nextQuery){
        promises.push(
            QueriesAPI.executeQuery({
                accept: 'application/28.io+json',
                queryPath: nextQuery,
                format: '',
                token: projectToken
            }).then(function (data) {
                $.util.log($.util.colors.green('✓ ') + nextQuery + ' returned with status code: ' + data.response.statusCode);
                return credentials;
            }).catch(function (error) {
                var requestUri = error.response.request.uri;
                var isTestQuery = (requestUri.pathname.lastIndexOf('/v1/_queries/public/test', 0) === 0);
                var href = isTestQuery ? requestUri.host + requestUri.pathname.substring('/v1/_queries/public'.length) : requestUri.host + requestUri.pathname;
                $.util.log($.util.colors.red('✗ ') + href + ' returned with status code: ' + $.util.colors.red(error.response.statusCode));
                error = isTestQuery ? summarizeTestError(error) : error;
                throw error;
            })
        );
    });
    return Q.all(promises);
};

var runQueries = function(projectName, sequenceOfQueriesToRun) {
    return _.chain(sequenceOfQueriesToRun)
        .map(function(queriesToRun) {
            // create chunks of queries to be executed in parallel
            if (_.isString(queriesToRun)) {
                return expand(queriesToRun);
            } else if (_.isArray(queriesToRun)){
                return _.chain(queriesToRun)
                    .map(function(queriesGlob){
                        return expand(queriesGlob);
                    })
                    .flatten()
                    .value();
            }
        })
        .map(function(queriesToRunArray){
            // substring to relative query path
            return _.map(queriesToRunArray, function(query) {
                return query.substring(Config.paths.queries.length + 1);
            });
        })
        .reduce(function(previousPromise, nextQueriesArray){
            // execute them in chunks
            return previousPromise.then(function() {
                return runQueriesInParallel(projectName, nextQueriesArray);
            });
        }, Q.resolve())
        .value();
};

var createDatasource = function(projectName, datasource){
    var defered = Q.defer();
    if(!Config.isOnProduction) {
        $.util.log('Creating datasource ' + datasource.name);
        var difault = datasource.default ? datasource.default : false;
        /*jshint camelcase:false */
        var projectToken = credentials.project_tokens['project_' + projectName];
        $28.createDatasource(projectName, datasource.category, datasource.name, projectToken, difault, JSON.stringify(datasource.credentials))
            .then(function(){
                $.util.log(datasource.name + ' created');
                defered.resolve(credentials);
            })
            .catch(function (error) {
                $.util.log('datasource creation failed: ' + datasource.name);
                defered.reject(error);
            });
    } else {
        $.util.log('Skipping data source creation on production: ' + datasource.name);
        defered.resolve(credentials);
    }
    return defered.promise;
};

gulp.task('28:login', function(){
    return login(Config.credentials['28'].email, Config.credentials['28'].password).catch(throwError);
});

gulp.task('28:create-project', function(){
    return createProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:remove-project', function(){
    return removeProject(Config.projectName, true).catch(throwError);
});

gulp.task('28:upload', function(){
    return upload(Config.projectName).catch(throwError);
});

gulp.task('28:setup-datasource', function(){
    var promises = [];
    Config.credentials['28'].datasources.forEach(function(datasource){
        promises.push(createDatasource(Config.projectName, datasource).catch(throwError));
    });
    return Q.all(promises);
});

gulp.task('28:init', function(){
    return runQueries(Config.projectName, Config.paths.initQueries).catch(throwError);
});

gulp.task('28:test', function(){
    return runQueries(Config.projectName, Config.paths.apiTestQueries).catch(throwError);
});

module.exports = {
    watchJSONiqQueries: function(){
        //Initialize the VFS
        /*jshint camelcase:false */
        var projectName = Config.projectName;
        var projectToken = credentials.project_tokens['project_' + projectName];
        var path = require('path');
        var projectPath = path.resolve(Config.paths.queries);
        var vfs = new VFS($28.api, projectName, projectToken, projectPath);

        //Do the Watch
        gulp.watch(Config.paths.jsoniq, {}, function(event){
            //Get relative query path
            var query = event.path.substring(projectPath.length + 1);
            $.util.log(query + ' has ' + event.type);

            //Upload
            if(event.type === 'added' || event.type === 'changed') {
                $.util.log($.util.colors.grey('Uploading ' + query));
                vfs.writeRemoteQuery(query, true).then(function(result){
                    //Show compilation errors
                    if(result && result.message) {
                        $.util.log($.util.colors.red(result.message));
                    }
                    $.util.log($.util.colors.green(query + ' uploaded'));
                }).catch(function(error){
                    throwError(error);
                });

            //Delete
            } else if(event.type === 'deleted') {
                $.util.log($.util.colors.grey('Removing ' + query));
                vfs.deleteRemoteQuery(query).then(function(){
                    $.util.log($.util.colors.green(query + ' removed'));
                }).catch(function(error){
                    throwError(error);
                });
            }
        });
    }
};
<|endoftext|>


<commit_before>var Template = require('../index.js').Template;
var e = require('element.js').e;
var uuid = require('node-uuid');

Template.prototype.addFI = function (label, input) {
	if (typeof label == 'object') {
		if (typeof label.attr('for') == 'undefined') {
			if (typeof input.attr('id') == 'undefined') {
				var id = uuid.v4();
				label.attr('for',id);
				input.attr('id',id);
			} else {
				label.attr('for',input.attr('id'));
			}
		}
	} else {
		label = e.label(label);
		if (typeof input.attr('id') == 'undefined') {
			var id = uuid.v4();
			label.attr('for',id);
			input.attr('id',id);
		} else {
			label.attr('for',input.attr('id'));
		}
	}
	if (typeof input == 'object') {
		if (input.tag = 'input') {
			input.addClass('form-control');
		} else {
			var list = input.find({'type':'input'});
			for (var i=0, el; el=list[i]; i++) {
				el.addClass('form-control');
			}
		}
	}
	if (input.type == 'checkbox' || input.type == 'radio') {
		label.inner = [input, label.inner[0]];
		this.body.append(e.div(label, { classes: ['form-group'] }));
	} else {
		this.body.append(e.div([ label, input ], { classes: ['form-group'] }));
	}
};

Template.prototype.setHorizontal = function (bool) {
	if (bool) {
		this.body.addClass('form-horizontal');
	} else {
		this.body.removeClass('form-horizontal');
	}
};

Template.prototype.setInline = function (bool) {
	if (bool) {
		this.body.addClass('form-inline');
	} else {
		this.body.removeClass('form-inline');
	}
};

Template.prototype.setNavbar = function (bool, direction) {
	defaults(direction, 'left');
	if (bool) {
		this.body.addClass([ 'navbar-form', 'navbar-'+direction ]);
	} else {
		this.body.removeClass([ 'navbar-form', 'navbar-left', 'navbar-right' ]);
	}
};

var form = new Template();
form.body = e.form({attrs: {role: 'form'}});
exports.Template = form;
<commit_msg>Well that's annoying...<commit_after>var Template = require('../index.js').Template;
var e = require('element.js').e;
var uuid = require('node-uuid');

Template.prototype.addFI = function (label, input) {
	if (typeof label == 'object') {
		if (typeof label.attr('for') == 'undefined') {
			if (typeof input.attr('id') == 'undefined') {
				var id = uuid.v4();
				label.attr('for',id);
				input.attr('id',id);
			} else {
				label.attr('for',input.attr('id'));
			}
		}
	} else {
		label = e.label(label);
		if (typeof input.attr('id') == 'undefined') {
			var id = uuid.v4();
			label.attr('for',id);
			input.attr('id',id);
		} else {
			label.attr('for',input.attr('id'));
		}
	}
	if (typeof input == 'object') {
		if (input.tag == 'input') {
			input.addClass('form-control');
		} else {
			var list = input.find({'type':'input'});
			for (var i=0, el; el=list[i]; i++) {
				el.addClass('form-control');
			}
		}
	}
	if (input.type == 'checkbox' || input.type == 'radio') {
		label.inner = [input, label.inner[0]];
		this.body.append(e.div(label, { classes: ['form-group'] }));
	} else {
		this.body.append(e.div([ label, input ], { classes: ['form-group'] }));
	}
};

Template.prototype.setHorizontal = function (bool) {
	if (bool) {
		this.body.addClass('form-horizontal');
	} else {
		this.body.removeClass('form-horizontal');
	}
};

Template.prototype.setInline = function (bool) {
	if (bool) {
		this.body.addClass('form-inline');
	} else {
		this.body.removeClass('form-inline');
	}
};

Template.prototype.setNavbar = function (bool, direction) {
	defaults(direction, 'left');
	if (bool) {
		this.body.addClass([ 'navbar-form', 'navbar-'+direction ]);
	} else {
		this.body.removeClass([ 'navbar-form', 'navbar-left', 'navbar-right' ]);
	}
};

var form = new Template();
form.body = e.form({attrs: {role: 'form'}});
exports.Template = form;
<|endoftext|>