<commit_before>function TreeCtrl($scope, WMSSources) {

    var refreshTree = function() {
        $scope.wms_list = WMSSources.list();
    };
    $scope.itemData = function(layer) {
        if(!layer.name) {
            return layer.layers;
        }
        return layer;
    };
    $scope.addCapabilities = function(url) {
        WMSSources.add({url: url});
    };

    $scope.$on('wms_capabilities.load_complete', refreshTree);
    $scope.$on('wms_capabilities.added', refreshTree);
}

function MapproxySourceListCtrl($scope, MapproxySources) {

    var refreshList = function() {
        $scope.mapproxy_sources = MapproxySources.list();
    }

    $scope.editSource = function(source) {
        MapproxySources.current(source, true);
    };
    $scope.removeSource = function(source) {
        MapproxySources.remove(source);
    };

    $scope.$on('sources.load_complete', refreshList);
    $scope.$on('sources.added', refreshList);
    $scope.$on('sources.updated', refreshList);
    $scope.$on('sources.deleted', refreshList);
}

function MapproxySourceFormCtrl($scope, MapproxySources, WMSSources) {
    $scope.openDialog = function(callback, new_data) {
        if(angular.isUndefined($scope.source.req) ||
           angular.isUndefined($scope.source.req.url) ||
           angular.isUndefined($scope.source.req.layers) ||
           $scope.source.req.layers.length == 0) {
            callback(true);
        } else  {
            $('#confirm_url_change_dialog').dialog({
                resizeable: false,
                width: 400,
                height: 200,
                model: true,
                buttons: {
                    "Change url": function() {
                        $(this).dialog("close");
                        $scope.source.req.layers = undefined;
                        $scope.$apply();
                        callback(true);
                    },
                    "Keep url": function() {
                        $(this).dialog("close");
                        callback(false);
                    }
                }
            });
        }
    };
    $scope.addSource = function(event) {
        event.preventDefault();
        $scope.source = clearData($scope.source)
        MapproxySources.add($scope.source);
        $scope.resetForm();
    };
    $scope.resetForm = function(event) {
        if(!angular.isUndefined(event)) {
            event.preventDefault();
        }
        $scope.source = {'type': 'wms'};
        $scope.source_form.$setPristine();
        MapproxySources.current($scope.source, false)
    };
    $scope.addLayerManual = function(event) {
        event.preventDefault();
        var new_layer = $scope.custom.layer_manual;
        if(!angular.isArray($scope.source.req.layers)) {
            $scope.source.req.layers = [new_layer];
        } else {
            $scope.source.req.layers.push(new_layer);
        }
        $scope.custom.layer_manual = undefined;
    };
    $scope.layerTitle = function(layer) {
        return WMSSources.layerTitle($scope.source.req.url, layer);
    };

    //must defined here if this controller should own all subelements of custom/source
    $scope.custom = {};
    $scope.source = {'type': 'wms'};

    MapproxySources.current($scope.source, false)

    $scope.$on('sources.current', function() {
        $scope.source = MapproxySources.current();
    });
}

function MapproxyCacheListCtrl($scope, MapproxyCaches) {

    var refreshList = function() {
        $scope.mapproxy_caches = MapproxyCaches.list();
    }

    $scope.editCache = function(cache) {
        MapproxyCaches.current(cache, true);
    };
    $scope.removeCache = function(cache) {
        MapproxyCaches.remove(cache);
    };

    $scope.$on('caches.load_complete', refreshList);
    $scope.$on('caches.added', refreshList);
    $scope.$on('caches.updated', refreshList);
    $scope.$on('caches.deleted', refreshList);
}

function MapproxyCacheFormCtrl($scope, MapproxySources, MapproxyCaches, MapproxyGrids) {

    var refreshGrids = function() {
        $scope.available_grids = MapproxyGrids.list();
    };

    $scope.addCache = function(event) {
        event.preventDefault();
        $scope.cache = clearData($scope.cache);
        MapproxyCaches.add($scope.cache);
        $scope.resetForm();
    };
    $scope.resetForm = function(event) {
        if(!angular.isUndefined(event)) {
            event.preventDefault();
        }
        $scope.cache = {'meta_size': [null, null]};
        $scope.cache_form.$setPristine();
        MapproxyCaches.current($scope.cache, false);
    };
    $scope.showName = function(_id) {
        return MapproxySources.byId(_id).name;
    };

    $scope.cache = {'meta_size': [null, null]};
    MapproxyCaches.current($scope.cache, false);

    $scope.$on('caches.current', function() {
        $scope.cache = MapproxyCaches.current();
        if(angular.isUndefined($scope.cache.meta_size)) {
            $scope.cache.meta_size = [null, null];
        }
    });

    $scope.$on('grids.load_complete', refreshGrids);
    $scope.$on('grids.added', refreshGrids);
    $scope.$on('grids.updated', refreshGrids);
    $scope.$on('grids.deleted', refreshGrids);

}

function MapproxyGridListCtrl($scope, MapproxyGrids) {

    var refreshList = function() {
        $scope.mapproxy_grids = MapproxyGrids.list();
    };

    $scope.editGrid = function(grid) {
        MapproxyGrids.current(grid, true);
    };
    $scope.removeGrid = function(grid) {
        MapproxyCaches.remove(grid);
    };

    $scope.$on('grids.load_complete', refreshList);
    $scope.$on('grids.added', refreshList);
    $scope.$on('grids.updated', refreshList);
    $scope.$on('grids.deleted', refreshList);
}

function MapproxyGridFormCtrl($scope, MapproxyGrids) {

    $scope.addGrid = function(event) {
        event.preventDefault();
        MapproxyGrids.add(clearData($scope.grid));
        $scope.resetForm();
    };
    $scope.resetForm = function(event) {
        if(angular.isDefined(event)) {
            event.preventDefault();
        }
        $scope.grid = {'bbox': [null, null, null, null]};
        $scope.grid_form.$setPristine();
        MapproxyGrids.current($scope.grid, false);
    };

    $scope.grid = {'bbox': [null, null, null, null]};
    MapproxyGrids.current($scope.grid, false);

    $scope.$on('grids.current', function() {
        $scope.grid = MapproxyGrids.current();
        if(angular.isUndefined($scope.grid.bbox)) {
            $scope.grid.bbox = [null, null, null, null];
        }
    });
}

function MapproxyLayerListCtrl($scope, MapproxyLayers) {

    var refreshTree = function() {
        $scope.mapproxy_layers = MapproxyLayers.tree();
    };
    var added = function() {
        $scope.mapproxy_layers.push(MapproxyLayers.last());
    };
    $scope.editLayer = function(layer) {
        MapproxyLayers.current(layer, true);
    };
    $scope.removeLayer = function(layer) {
        MapproxyLayers.remove(layer);
    };
    $scope.updateLayerTree = function() {
        MapproxyLayers.updateStructure($scope.mapproxy_layers);
    };

    $scope.$on('layers.load_complete', refreshTree);
    $scope.$on('layers.added', added);
    $scope.$on('layers.updated', refreshTree);
    $scope.$on('layers.deleted', refreshTree);
}

function MapproxyLayerFormCtrl($scope, MapproxySources, MapproxyCaches, MapproxyLayers) {

    $scope.addLayer = function() {
        $scope.layer = clearData($scope.layer)
        MapproxyLayers.add(angular.copy($scope.layer));
        $scope.resetForm();
    };
    $scope.resetForm = function() {
        $scope.layer = {};
        $scope.layer_form.$setPristine();
        MapproxyLayers.current($scope.layer, false);
    };
    $scope.layerTitle = function(name) {
        var layer = MapproxyLayers.byName(name);
        if(angular.isDefined(layer)) {
            return layer.title;
        }
    };
    $scope.showName = function(_id) {
        return MapproxySources.byId(_id) ? MapproxySources.byId(_id).name : MapproxyCaches.byId(_id).name;
    };

    $scope.layer = {};
    MapproxyLayers.current($scope.layer, false);

    $scope.$on('layers.current', function() {
        $scope.layer = MapproxyLayers.current();
    });
}

function MapproxySourceNoticeCtrl($scope, MapproxySources) {
    //define all watch results
    $scope.invalid_image_settings = false;
    $scope.high_number_of_concurrent_requests = false;
    var checkImageSettings = function() {
        //ensure all variables to check for are defined!
        if(angular.isDefined($scope.watch_source.req) &&
           angular.isDefined($scope.watch_source.supported_formats) &&
           $scope.watch_source.req.transparent == true) {
            var found = false;
            var non_transparent_formats = ['JPEG', 'GIF'];
            angular.forEach($scope.watch_source.supported_formats, function(format) {
                if (!found) {
                    found = -1 != non_transparent_formats.indexOf(format);
                }
                $scope.invalid_image_settings = found;
            })
        } else {
            $scope.invalid_image_settings = false;
        }
    };

    var checkConcurrentRequests = function() {
        if(angular.isDefined($scope.watch_source.concurrent_requests) &&
           $scope.watch_source.concurrent_requests > 4) {
            $scope.high_number_of_concurrent_requests = true;
        } else {
            $scope.high_number_of_concurrent_requests = false;
        }
    }

    $scope.$watch('watch_source', function(newVal, oldVal, scope) {
        checkImageSettings();
        checkConcurrentRequests();
    }, true);

    $scope.$on('sources.current', function() {
        $scope.watch_source = MapproxySources.current();
    });
}

function MapproxyConfigCtrl($scope, $http) {

    $scope.mapproxy_yaml = undefined;

    $scope.getConfig = function() {
        $http.get('/conf/base/yaml').success(function(result) {
            $scope.mapproxy_yaml = result;
        });
    };
}<commit_msg>Reload layers from server after delete<commit_after>function TreeCtrl($scope, WMSSources) {

    var refreshTree = function() {
        $scope.wms_list = WMSSources.list();
    };
    $scope.itemData = function(layer) {
        if(!layer.name) {
            return layer.layers;
        }
        return layer;
    };
    $scope.addCapabilities = function(url) {
        WMSSources.add({url: url});
    };

    $scope.$on('wms_capabilities.load_complete', refreshTree);
    $scope.$on('wms_capabilities.added', refreshTree);
}

function MapproxySourceListCtrl($scope, MapproxySources) {

    var refreshList = function() {
        $scope.mapproxy_sources = MapproxySources.list();
    }

    $scope.editSource = function(source) {
        MapproxySources.current(source, true);
    };
    $scope.removeSource = function(source) {
        MapproxySources.remove(source);
    };

    $scope.$on('sources.load_complete', refreshList);
    $scope.$on('sources.added', refreshList);
    $scope.$on('sources.updated', refreshList);
    $scope.$on('sources.deleted', refreshList);
}

function MapproxySourceFormCtrl($scope, MapproxySources, WMSSources) {
    $scope.openDialog = function(callback, new_data) {
        if(angular.isUndefined($scope.source.req) ||
           angular.isUndefined($scope.source.req.url) ||
           angular.isUndefined($scope.source.req.layers) ||
           $scope.source.req.layers.length == 0) {
            callback(true);
        } else  {
            $('#confirm_url_change_dialog').dialog({
                resizeable: false,
                width: 400,
                height: 200,
                model: true,
                buttons: {
                    "Change url": function() {
                        $(this).dialog("close");
                        $scope.source.req.layers = undefined;
                        $scope.$apply();
                        callback(true);
                    },
                    "Keep url": function() {
                        $(this).dialog("close");
                        callback(false);
                    }
                }
            });
        }
    };
    $scope.addSource = function(event) {
        event.preventDefault();
        $scope.source = clearData($scope.source)
        MapproxySources.add($scope.source);
        $scope.resetForm();
    };
    $scope.resetForm = function(event) {
        if(!angular.isUndefined(event)) {
            event.preventDefault();
        }
        $scope.source = {'type': 'wms'};
        $scope.source_form.$setPristine();
        MapproxySources.current($scope.source, false)
    };
    $scope.addLayerManual = function(event) {
        event.preventDefault();
        var new_layer = $scope.custom.layer_manual;
        if(!angular.isArray($scope.source.req.layers)) {
            $scope.source.req.layers = [new_layer];
        } else {
            $scope.source.req.layers.push(new_layer);
        }
        $scope.custom.layer_manual = undefined;
    };
    $scope.layerTitle = function(layer) {
        return WMSSources.layerTitle($scope.source.req.url, layer);
    };

    //must defined here if this controller should own all subelements of custom/source
    $scope.custom = {};
    $scope.source = {'type': 'wms'};

    MapproxySources.current($scope.source, false)

    $scope.$on('sources.current', function() {
        $scope.source = MapproxySources.current();
    });
}

function MapproxyCacheListCtrl($scope, MapproxyCaches) {

    var refreshList = function() {
        $scope.mapproxy_caches = MapproxyCaches.list();
    }

    $scope.editCache = function(cache) {
        MapproxyCaches.current(cache, true);
    };
    $scope.removeCache = function(cache) {
        MapproxyCaches.remove(cache);
    };

    $scope.$on('caches.load_complete', refreshList);
    $scope.$on('caches.added', refreshList);
    $scope.$on('caches.updated', refreshList);
    $scope.$on('caches.deleted', refreshList);
}

function MapproxyCacheFormCtrl($scope, MapproxySources, MapproxyCaches, MapproxyGrids) {

    var refreshGrids = function() {
        $scope.available_grids = MapproxyGrids.list();
    };

    $scope.addCache = function(event) {
        event.preventDefault();
        $scope.cache = clearData($scope.cache);
        MapproxyCaches.add($scope.cache);
        $scope.resetForm();
    };
    $scope.resetForm = function(event) {
        if(!angular.isUndefined(event)) {
            event.preventDefault();
        }
        $scope.cache = {'meta_size': [null, null]};
        $scope.cache_form.$setPristine();
        MapproxyCaches.current($scope.cache, false);
    };
    $scope.showName = function(_id) {
        return MapproxySources.byId(_id).name;
    };

    $scope.cache = {'meta_size': [null, null]};
    MapproxyCaches.current($scope.cache, false);

    $scope.$on('caches.current', function() {
        $scope.cache = MapproxyCaches.current();
        if(angular.isUndefined($scope.cache.meta_size)) {
            $scope.cache.meta_size = [null, null];
        }
    });

    $scope.$on('grids.load_complete', refreshGrids);
    $scope.$on('grids.added', refreshGrids);
    $scope.$on('grids.updated', refreshGrids);
    $scope.$on('grids.deleted', refreshGrids);

}

function MapproxyGridListCtrl($scope, MapproxyGrids) {

    var refreshList = function() {
        $scope.mapproxy_grids = MapproxyGrids.list();
    };

    $scope.editGrid = function(grid) {
        MapproxyGrids.current(grid, true);
    };
    $scope.removeGrid = function(grid) {
        MapproxyCaches.remove(grid);
    };

    $scope.$on('grids.load_complete', refreshList);
    $scope.$on('grids.added', refreshList);
    $scope.$on('grids.updated', refreshList);
    $scope.$on('grids.deleted', refreshList);
}

function MapproxyGridFormCtrl($scope, MapproxyGrids) {

    $scope.addGrid = function(event) {
        event.preventDefault();
        MapproxyGrids.add(clearData($scope.grid));
        $scope.resetForm();
    };
    $scope.resetForm = function(event) {
        if(angular.isDefined(event)) {
            event.preventDefault();
        }
        $scope.grid = {'bbox': [null, null, null, null]};
        $scope.grid_form.$setPristine();
        MapproxyGrids.current($scope.grid, false);
    };

    $scope.grid = {'bbox': [null, null, null, null]};
    MapproxyGrids.current($scope.grid, false);

    $scope.$on('grids.current', function() {
        $scope.grid = MapproxyGrids.current();
        if(angular.isUndefined($scope.grid.bbox)) {
            $scope.grid.bbox = [null, null, null, null];
        }
    });
}

function MapproxyLayerListCtrl($scope, MapproxyLayers) {

    var refreshTree = function() {
        $scope.mapproxy_layers = MapproxyLayers.tree();
    };
    var added = function() {
        $scope.mapproxy_layers.push(MapproxyLayers.last());
    };
    $scope.editLayer = function(layer) {
        MapproxyLayers.current(layer, true);
    };
    $scope.removeLayer = function(layer) {
        MapproxyLayers.remove(layer);
    };
    $scope.updateLayerTree = function() {
        MapproxyLayers.updateStructure($scope.mapproxy_layers);
    };

    $scope.$on('layers.load_complete', refreshTree);
    $scope.$on('layers.added', added);
    $scope.$on('layers.updated', refreshTree);
    $scope.$on('layers.deleted', MapproxyLayers.refresh);
}

function MapproxyLayerFormCtrl($scope, MapproxySources, MapproxyCaches, MapproxyLayers) {

    $scope.addLayer = function() {
        $scope.layer = clearData($scope.layer)
        MapproxyLayers.add(angular.copy($scope.layer));
        $scope.resetForm();
    };
    $scope.resetForm = function() {
        $scope.layer = {};
        $scope.layer_form.$setPristine();
        MapproxyLayers.current($scope.layer, false);
    };
    $scope.layerTitle = function(name) {
        var layer = MapproxyLayers.byName(name);
        if(angular.isDefined(layer)) {
            return layer.title;
        }
    };
    $scope.showName = function(_id) {
        return MapproxySources.byId(_id) ? MapproxySources.byId(_id).name : MapproxyCaches.byId(_id).name;
    };

    $scope.layer = {};
    MapproxyLayers.current($scope.layer, false);

    $scope.$on('layers.current', function() {
        $scope.layer = MapproxyLayers.current();
    });
}

function MapproxySourceNoticeCtrl($scope, MapproxySources) {
    //define all watch results
    $scope.invalid_image_settings = false;
    $scope.high_number_of_concurrent_requests = false;
    var checkImageSettings = function() {
        //ensure all variables to check for are defined!
        if(angular.isDefined($scope.watch_source.req) &&
           angular.isDefined($scope.watch_source.supported_formats) &&
           $scope.watch_source.req.transparent == true) {
            var found = false;
            var non_transparent_formats = ['JPEG', 'GIF'];
            angular.forEach($scope.watch_source.supported_formats, function(format) {
                if (!found) {
                    found = -1 != non_transparent_formats.indexOf(format);
                }
                $scope.invalid_image_settings = found;
            })
        } else {
            $scope.invalid_image_settings = false;
        }
    };

    var checkConcurrentRequests = function() {
        if(angular.isDefined($scope.watch_source.concurrent_requests) &&
           $scope.watch_source.concurrent_requests > 4) {
            $scope.high_number_of_concurrent_requests = true;
        } else {
            $scope.high_number_of_concurrent_requests = false;
        }
    }

    $scope.$watch('watch_source', function(newVal, oldVal, scope) {
        checkImageSettings();
        checkConcurrentRequests();
    }, true);

    $scope.$on('sources.current', function() {
        $scope.watch_source = MapproxySources.current();
    });
}

function MapproxyConfigCtrl($scope, $http) {

    $scope.mapproxy_yaml = undefined;

    $scope.getConfig = function() {
        $http.get('/conf/base/yaml').success(function(result) {
            $scope.mapproxy_yaml = result;
        });
    };
}<|endoftext|>


<commit_before>"use strict";

//Load dependencies
var async = require("async");
var applicationStorage = process.require("core/applicationStorage.js");
var mythicDungeonModel = process.require("mythicDungeons/mythicDungeonModel.js");
var realmModel = process.require("realms/realmModel.js");

module.exports.getRanking = function (req, res, next) {

    var logger = applicationStorage.logger;
    logger.info("%s %s %s %s %s", req.headers['x-forwarded-for'] || req.connection.remoteAddress, req.method, req.path, JSON.stringify(req.params), JSON.stringify(req.query));

    var criteria = {};

    if (req.query && req.query.affixes) {
        criteria.affixes = req.query.affixes.split('#');
    }

    if (req.query && req.query.dungeon) {
        criteria.dungeon = req.query.dungeon;
    }

    var limit;
    if (req.query && req.query.limit) {
        limit = parseInt(req.query.limit, 10);

        if (limit < 0) {
            limit = 50;
        }

        if (limit > 50) {
            limit = 50;
        }

    } else {
        limit = 50;
    }

    var skip = 0;
    if (req.query && req.query.page) {

        var page = parseInt(req.query.page, 10);
        if (!isNaN(page)) {
            if (page >= 1) {
                page--;
            }
            if (page < 0) {
                page = 0;
            }
            skip = page * limit;
        }

    }

    async.waterfall([
            function (callback) {
                if (req.query && req.query.region) {
                    var localeArray = req.query.region.split('#');
                    if (localeArray.length == 2) {
                        realmModel.find({
                            "bnet.locale": localeArray[0],
                            "bnet.timezone": {$regex: "^" + localeArray[1], $options: "i"}
                        }, {name: 1}, function (error, realms) {
                            if (realms.length > 0) {
                                criteria["$or"] = [];
                                realms.forEach(function (realm) {
                                    criteria['$or'].push({realms: realm.name});
                                });
                                callback();
                            } else {
                                callback();
                            }
                        });
                    } else {
                        criteria.region = req.query.region;
                        callback();
                    }
                } else {
                    callback();
                }
            },
            function (callback) {
                if (req.query && req.query.region && req.query.realm) {
                    realmModel.findOne({
                        region: req.query.region,
                        name: req.query.realm
                    }, {connected_realms: 1,region:1}, function (error, realm) {
                        if (realm) {
                            criteria.region = realm.region;

                            criteria["$or"] = [];
                            realm.connected_realms.forEach(function (realmName) {
                                criteria['$or'].push({realms: realmName});
                            });
                            callback();

                        } else {
                            callback();
                        }
                    });
                } else {
                    callback();
                }
            },
            function (callback) {
                mythicDungeonModel.find(req.params.extension, criteria, limit, skip, function (error, runs) {
                    callback(error, runs);
                });
            }

        ],
        function (error, runs) {
            if (error) {
                logger.error(error.message);
                res.status(500).send(error.message);
            } else if (runs && runs.length > 0) {
                res.json(runs);
            } else {
                next();
            }
        }
    );
};<commit_msg>Fix subregion issue<commit_after>"use strict";

//Load dependencies
var async = require("async");
var applicationStorage = process.require("core/applicationStorage.js");
var mythicDungeonModel = process.require("mythicDungeons/mythicDungeonModel.js");
var realmModel = process.require("realms/realmModel.js");

module.exports.getRanking = function (req, res, next) {

    var logger = applicationStorage.logger;
    logger.info("%s %s %s %s %s", req.headers['x-forwarded-for'] || req.connection.remoteAddress, req.method, req.path, JSON.stringify(req.params), JSON.stringify(req.query));

    var criteria = {};

    if (req.query && req.query.affixes) {
        criteria.affixes = req.query.affixes.split('#');
    }

    if (req.query && req.query.dungeon) {
        criteria.dungeon = req.query.dungeon;
    }

    var limit;
    if (req.query && req.query.limit) {
        limit = parseInt(req.query.limit, 10);

        if (limit < 0) {
            limit = 50;
        }

        if (limit > 50) {
            limit = 50;
        }

    } else {
        limit = 50;
    }

    var skip = 0;
    if (req.query && req.query.page) {

        var page = parseInt(req.query.page, 10);
        if (!isNaN(page)) {
            if (page >= 1) {
                page--;
            }
            if (page < 0) {
                page = 0;
            }
            skip = page * limit;
        }

    }

    async.waterfall([
            function (callback) {
                if (req.query && req.query.region) {
                    var localeArray = req.query.region.split('#');
                    if (localeArray.length == 2) {
                        realmModel.find({
                            "bnet.locale": localeArray[0],
                            "bnet.timezone": {$regex: "^" + localeArray[1], $options: "i"}
                        }, {name: 1}, function (error, realms) {
                            if (realms.length > 0) {
                                criteria["$or"] = [];
                                realms.forEach(function (realm) {
                                    criteria['$or'].push({realms: realm.name});
                                });
                                callback();
                            } else {
                                callback();
                            }
                        });
                    } else {
                        criteria.region = req.query.region;
                        callback();
                    }
                } else {
                    callback();
                }
            },
            function (callback) {
                if (req.query && req.query.region && req.query.realm) {
                    realmModel.findOne({
                        region: req.query.region,
                        name: req.query.realm
                    }, {connected_realms: 1,region:1}, function (error, realm) {
                        if (realm) {
                            criteria["$or"] = [];
                            realm.connected_realms.forEach(function (realmName) {
                                criteria['$or'].push({region:realm.region,realms: realmName});
                            });
                            callback();

                        } else {
                            callback();
                        }
                    });
                } else {
                    callback();
                }
            },
            function (callback) {
                mythicDungeonModel.find(req.params.extension, criteria, limit, skip, function (error, runs) {
                    callback(error, runs);
                });
            }

        ],
        function (error, runs) {
            if (error) {
                logger.error(error.message);
                res.status(500).send(error.message);
            } else if (runs && runs.length > 0) {
                res.json(runs);
            } else {
                next();
            }
        }
    );
};<|endoftext|>


<commit_before>/**
 * Created by jcorbett on 2/2/14.
 */

angular.module('slickApp')
    .config(['$routeProvider', 'NavigationServiceProvider', function ($routeProvider, nav) {
        $routeProvider
            .when('/build-report/:project/:release/:build*', {
                templateUrl: 'static/resources/pages/testrungroup/view-testrungroup.html',
                controller: 'ViewBuildReportCtrl'
            });
    }])
    .controller('ViewBuildReportCtrl', ['$scope', 'Restangular', 'NavigationService', '$routeParams', '$timeout', function ($scope, rest, nav, $routeParams, $timeout) {
        $scope.replaceOnStatus = replaceOnStatus;
        $scope.testrungroup = {};
        $scope.testrunList = {};
        $scope.editbutton = {
            href: "result-list/" + $routeParams['project'] + "/" + $routeParams['release'] + "/" + $routeParams['build'],
            name: "Broken and Failed Results"
        };

        $scope.parallelSummaryData = new google.visualization.DataTable();
        $scope.parallelSummaryData.addColumn('string', 'Status');
        $scope.parallelSummaryData.addColumn('number', 'Results');

        $scope.parallelIndividualData = new google.visualization.DataTable();
        $scope.parallelIndividualData.addColumn('string', 'Testrun Name');

        $scope.summaryChartOptions = {
            chartArea: {left: '5%', top: '5%', width: '90%', height: '90%'},
            backgroundColor: "#000000",
            pieSliceBorderColor: "#000000",
            legend: 'none',
            colors: []
        };

        $scope.individualChartOptions = {
            chartArea: {left: '5%', top: '5%', width: '90%', height: '70%'},
            backgroundColor: "#000000",
            isStacked: true,
            legend: 'none',
            hAxis: {
                textStyle: {
                    color: '#ffffff'
                },
                slantedText: true
            },
            colors: []
        };

        var refresh_promise;

        $scope.getBuildReportData = function() {
            rest.one('build-report', $routeParams.project).one($routeParams.release, $routeParams.build).get().then(function (buildreport) {
                $scope.summaryChartOptions = {
                    chartArea: {left: '5%', top: '5%', width: '90%', height: '90%'},
                    backgroundColor: "#000000",
                    pieSliceBorderColor: "#000000",
                    legend: 'none',
                    colors: []
                };

                $scope.individualChartOptions = {
                    chartArea: {left: '5%', top: '5%', width: '90%', height: '70%'},
                    backgroundColor: "#000000",
                    isStacked: true,
                    legend: 'none',
                    hAxis: {
                        textStyle: {
                            color: '#ffffff'
                        },
                        slantedText: true
                    },
                    colors: []
                };
                $scope.testrungroup = buildreport;
                var testrungroup = buildreport;
                nav.setTitle(buildreport.name);

                $scope.parallelSummaryData = new google.visualization.DataTable();
                $scope.parallelSummaryData.addColumn('string', 'Status');
                $scope.parallelSummaryData.addColumn('number', 'Results');

                $scope.parallelIndividualData = new google.visualization.DataTable();
                $scope.parallelIndividualData.addColumn('string', 'Testrun Name');

                refresh_promise = $timeout($scope.getBuildReportData, 3000);
                _.each(testrungroup.groupSummary.statusListOrdered, function (status) {
                    $scope.parallelSummaryData.addRow([replaceOnStatus(status, " "), testrungroup.groupSummary.resultsByStatus[status]]);
                    var color = getStyle(replaceOnStatus(status, "") + "-element", "color");
                    $scope.summaryChartOptions.colors.push(color);
                    $scope.individualChartOptions.colors.push(color);

                    $scope.parallelIndividualData.addColumn('number', replaceOnStatus(status, " "))
                });

                _.each(testrungroup.testruns, function (testrun) {
                    var row = [testrun.project.name + " - " + testrun.name];
                    _.each(testrungroup.groupSummary.statusListOrdered, function (status) {
                        row.push(testrun.summary.resultsByStatus[status]);
                    });
                    $scope.parallelIndividualData.addRow(row);
                });

            }, function errorCallback() {
                refresh_promise = $timeout($scope.getBuildReportData, 3000);
            });
        };

        $scope.stopRefresh = function() {
            if (angular.isDefined(refresh_promise)) {
                $timeout.cancel(refresh_promise);
                refresh_promise = undefined;
            }
        };
        $scope.getBuildReportData();

        $scope.$on('$destroy', function() {
            $scope.stopRefresh();
        });
    }]);
<commit_msg>Add support for latest release/build or latest build in a specified release<commit_after>/**
 * Created by jcorbett on 2/2/14.
 */

angular.module('slickApp')
    .config(['$routeProvider', 'NavigationServiceProvider', function ($routeProvider, nav) {
        $routeProvider
            .when('/build-report/:project/:release/:build*', {
                templateUrl: 'static/resources/pages/testrungroup/view-testrungroup.html',
                controller: 'ViewBuildReportCtrl'
            })
            .when('/build-report/:project/:release', {
                templateUrl: 'static/resources/pages/testrungroup/view-testrungroup.html',
                controller: 'ViewBuildReportCtrl'
            });
    }])
    .controller('ViewBuildReportCtrl', ['$scope', 'Restangular', 'NavigationService', '$routeParams', '$timeout', function ($scope, rest, nav, $routeParams, $timeout) {
        $scope.replaceOnStatus = replaceOnStatus;
        $scope.testrungroup = {};
        $scope.testrunList = {};
        $scope.editbutton = {
            href: "result-list/" + $routeParams['project'] + "/" + $routeParams['release'] + "/" + $routeParams['build'],
            name: "Broken and Failed Results"
        };

        $scope.parallelSummaryData = new google.visualization.DataTable();
        $scope.parallelSummaryData.addColumn('string', 'Status');
        $scope.parallelSummaryData.addColumn('number', 'Results');

        $scope.parallelIndividualData = new google.visualization.DataTable();
        $scope.parallelIndividualData.addColumn('string', 'Testrun Name');

        $scope.summaryChartOptions = {
            chartArea: {left: '5%', top: '5%', width: '90%', height: '90%'},
            backgroundColor: "#000000",
            pieSliceBorderColor: "#000000",
            legend: 'none',
            colors: []
        };

        $scope.individualChartOptions = {
            chartArea: {left: '5%', top: '5%', width: '90%', height: '70%'},
            backgroundColor: "#000000",
            isStacked: true,
            legend: 'none',
            hAxis: {
                textStyle: {
                    color: '#ffffff'
                },
                slantedText: true
            },
            colors: []
        };

        var refresh_promise;

        $scope.getBuildReportData = function() {
            if ($routeParams.release === 'latest') {
                rest.one('projects', $routeParams['project']).get().then(function (project) {
                    var lastRelease = project.releases.length - 1;
                    $routeParams.release = project.releases[lastRelease]['name'];
                    var lastBuild = project.releases[lastRelease]['builds'].length - 1;
                    $routeParams.build = project.releases[lastRelease]['builds'][lastBuild]['name']
                });
            } else if ($routeParams.build === 'latest') {
                rest.one('projects', $routeParams['project']).get().then(function (project) {
                    var release = null;
                    for (var i = 0; i < project.releases.length; i++) {
                        if (project.releases[i]['name'] === $routeParams.release) {
                            release = project.releases[i];
                            break;
                        }
                    }
                    if (release !== null) {
                        var lastBuild = project.releases[i]['builds'].length - 1;
                        $routeParams.build = release['builds'][lastBuild]['name']
                    }
                });
            }
            rest.one('build-report', $routeParams.project).one($routeParams.release, $routeParams.build).get().then(function (buildreport) {
                $scope.summaryChartOptions = {
                    chartArea: {left: '5%', top: '5%', width: '90%', height: '90%'},
                    backgroundColor: "#000000",
                    pieSliceBorderColor: "#000000",
                    legend: 'none',
                    colors: []
                };

                $scope.individualChartOptions = {
                    chartArea: {left: '5%', top: '5%', width: '90%', height: '70%'},
                    backgroundColor: "#000000",
                    isStacked: true,
                    legend: 'none',
                    hAxis: {
                        textStyle: {
                            color: '#ffffff'
                        },
                        slantedText: true
                    },
                    colors: []
                };
                $scope.testrungroup = buildreport;
                var testrungroup = buildreport;
                if (buildreport.hasOwnProperty('name')) {
                    nav.setTitle(buildreport.name);

                    $scope.parallelSummaryData = new google.visualization.DataTable();
                    $scope.parallelSummaryData.addColumn('string', 'Status');
                    $scope.parallelSummaryData.addColumn('number', 'Results');

                    $scope.parallelIndividualData = new google.visualization.DataTable();
                    $scope.parallelIndividualData.addColumn('string', 'Testrun Name');

                    refresh_promise = $timeout($scope.getBuildReportData, 3000);
                    _.each(testrungroup.groupSummary.statusListOrdered, function (status) {
                        $scope.parallelSummaryData.addRow([replaceOnStatus(status, " "), testrungroup.groupSummary.resultsByStatus[status]]);
                        var color = getStyle(replaceOnStatus(status, "") + "-element", "color");
                        $scope.summaryChartOptions.colors.push(color);
                        $scope.individualChartOptions.colors.push(color);

                        $scope.parallelIndividualData.addColumn('number', replaceOnStatus(status, " "))
                    });

                    _.each(testrungroup.testruns, function (testrun) {
                        var row = [testrun.project.name + " - " + testrun.name];
                        _.each(testrungroup.groupSummary.statusListOrdered, function (status) {
                            row.push(testrun.summary.resultsByStatus[status]);
                        });
                        $scope.parallelIndividualData.addRow(row);
                    });
                } else {
                    refresh_promise = $timeout($scope.getBuildReportData, 500);
                }
            }, function errorCallback() {
                refresh_promise = $timeout($scope.getBuildReportData, 3000);
            });
        };

        $scope.stopRefresh = function() {
            if (angular.isDefined(refresh_promise)) {
                $timeout.cancel(refresh_promise);
                refresh_promise = undefined;
            }
        };
        $scope.getBuildReportData();

        $scope.$on('$destroy', function() {
            $scope.stopRefresh();
        });
    }]);
<|endoftext|>


<commit_before>define(function(require) {
  var Propuesta = require('frontend/models/Propuesta');

  return Backbone.Collection.extend({
    model: Propuesta,
    url: '/api/propuestas'
  });
});
<commit_msg>Change Propuestas collection (new endpoint)<commit_after>define(function(require) {
  var Propuesta = require('frontend/models/Propuesta');

  return Backbone.Collection.extend({
    model: Propuesta,
    url: '/api/publicaciones/propuestas'
  });
});
<|endoftext|>


<commit_before>(function () {
    'use strict';

    /**
     * Booking controller.
     */
    angular.module('timax.controllers.booking', ['angularModalService', 'timax.controllers.modals.confirmation', 'timax.controllers.modals.editBooking', 'timax.services.user', 'timax.services.booking', 'timax.services.socket', 'timax.filters.asDate', 'timax.services.pagination'])

        .controller('BookingController', function ($scope, authorizedUser, bookings, ModalService, userService, bookingService, paginationService, growl, socketService) {
            $scope.bookings = [];
            $scope.totalItems = 0;
            $scope.currentPage = 1;
            $scope.projects = [];
            $scope.opened = false;

            $scope.$on('socket:booking', function (ev, data) {
                var message = 'from ' + data.user + ' on project ' + data.project + '
';
                message = message + 'with description: ' + data.description + '
';

                growl.info(message, {title: 'New Booking'});
            });

            function initPagination(documents, totalPages, nextPage) {
                $scope.bookings = documents;
                $scope.totalItems = paginationService.calculateTotalItems(totalPages);
                if (nextPage !== undefined) {
                    $scope.currentPage = paginationService.initCurrentPage(nextPage);
                }
            }

            function initNewBooking() {
                $scope.newBooking = bookingService.createNewBooking();
                $scope.newBookingDate = new Date();
                $scope.newBookingStart = new Date(2015, 0, 1, 8, 30);
                $scope.newBookingEnd = new Date(2015, 0, 1, 18, 30);
            }

            $scope.pageChanged = function () {
                bookingService.getBookings($scope.currentPage).then(function (data) {
                    initPagination(data.documents, data.totalPages);
                });
            };

            $scope.openDatePicker = function ($event) {
                $event.preventDefault();
                $event.stopPropagation();
                $scope.opened = true;
            };

            $scope.saveNewBooking = function () {
                bookingService.saveNewBooking($scope.newBooking, $scope.newBookingDate, $scope.newBookingStart, $scope.newBookingEnd).then(function () {
                    $scope.pageChanged();
                    initNewBooking();
                });
            };

            $scope.canSeeUserRow = function () {
                return authorizedUser.role !== 'user';
            };

            $scope.canEditBooking = function () {
                return authorizedUser.role === 'admin' || authorizedUser.role === 'user';
            };

            $scope.canCreateBooking = function () {
                return authorizedUser.role === 'user';
            };

            $scope.editBooking = function (booking) {
                ModalService.showModal({
                    templateUrl: 'views/modals/editBooking.html',
                    controller: 'EditBookingController',
                    inputs: {
                        booking: booking
                    }
                }).then(function (modal) {
                    modal.element.modal();
                    modal.close.then(function (result) {
                        if (result) {
                            $scope.pageChanged();
                        }
                    });
                });
            };

            $scope.deleteBooking = function (booking) {
                ModalService.showModal({
                    templateUrl: 'views/modals/confirmation.html',
                    controller: 'ConfirmationController',
                    inputs: {
                        message: 'Do you really want to delete the booking?'
                    }
                }).then(function (modal) {
                    modal.element.modal();
                    modal.close.then(function (result) {
                        if (result) {
                            bookingService.deleteBooking(booking._id).then(function () {
                                $scope.pageChanged();
                            });
                        }
                    });
                });
            };

            // init
            initNewBooking();
            initPagination(bookings.documents, bookings.totalPages, bookings.nextPage);
            userService.getProjectsByUser(authorizedUser._id).then(function (projects) {
                $scope.projects = projects;
            });
        });
})();<commit_msg>nice formatted booking notification<commit_after>(function () {
    'use strict';

    /**
     * Booking controller.
     */
    angular.module('timax.controllers.booking', ['angularModalService', 'timax.controllers.modals.confirmation', 'timax.controllers.modals.editBooking', 'timax.services.user', 'timax.services.booking', 'timax.services.socket', 'timax.filters.asDate', 'timax.services.pagination'])

        .controller('BookingController', function ($scope, $filter, authorizedUser, bookings, ModalService, userService, bookingService, paginationService, growl, socketService) {
            $scope.bookings = [];
            $scope.totalItems = 0;
            $scope.currentPage = 1;
            $scope.projects = [];
            $scope.opened = false;

            function initPagination(documents, totalPages, nextPage) {
                $scope.bookings = documents;
                $scope.totalItems = paginationService.calculateTotalItems(totalPages);
                if (nextPage !== undefined) {
                    $scope.currentPage = paginationService.initCurrentPage(nextPage);
                }
            }

            function initNewBooking() {
                $scope.newBooking = bookingService.createNewBooking();
                $scope.newBookingDate = new Date();
                $scope.newBookingStart = new Date(2015, 0, 1, 8, 30);
                $scope.newBookingEnd = new Date(2015, 0, 1, 18, 30);
            }

            $scope.pageChanged = function () {
                bookingService.getBookings($scope.currentPage).then(function (data) {
                    initPagination(data.documents, data.totalPages);
                });
            };

            $scope.openDatePicker = function ($event) {
                $event.preventDefault();
                $event.stopPropagation();
                $scope.opened = true;
            };

            $scope.saveNewBooking = function () {
                bookingService.saveNewBooking($scope.newBooking, $scope.newBookingDate, $scope.newBookingStart, $scope.newBookingEnd).then(function () {
                    $scope.pageChanged();
                    initNewBooking();
                });
            };

            $scope.canSeeUserRow = function () {
                return authorizedUser.role !== 'user';
            };

            $scope.canEditBooking = function () {
                return authorizedUser.role === 'admin' || authorizedUser.role === 'user';
            };

            $scope.canCreateBooking = function () {
                return authorizedUser.role === 'user';
            };

            $scope.editBooking = function (booking) {
                ModalService.showModal({
                    templateUrl: 'views/modals/editBooking.html',
                    controller: 'EditBookingController',
                    inputs: {
                        booking: booking
                    }
                }).then(function (modal) {
                    modal.element.modal();
                    modal.close.then(function (result) {
                        if (result) {
                            $scope.pageChanged();
                        }
                    });
                });
            };

            $scope.deleteBooking = function (booking) {
                ModalService.showModal({
                    templateUrl: 'views/modals/confirmation.html',
                    controller: 'ConfirmationController',
                    inputs: {
                        message: 'Do you really want to delete the booking?'
                    }
                }).then(function (modal) {
                    modal.element.modal();
                    modal.close.then(function (result) {
                        if (result) {
                            bookingService.deleteBooking(booking._id).then(function () {
                                $scope.pageChanged();
                            });
                        }
                    });
                });
            };

            function formatDate(date) {
                var dateObj = $filter('asDate')(date);
                return $filter('date')(dateObj, 'dd.MM.yyyy HH:mm');
            }

            $scope.$on('socket:booking', function (ev, data) {
                var message = 'from ' + data.user + ' on project ' + data.project + '
';
                message = message + 'Description: ' + data.description + '
';
                message = message + 'Start: ' + formatDate(data.start) + '
';
                message = message + 'End: ' + formatDate(data.end) + '';

                growl.info(message, {title: 'New Booking'});
            });

            // init
            initNewBooking();
            initPagination(bookings.documents, bookings.totalPages, bookings.nextPage);
            userService.getProjectsByUser(authorizedUser._id).then(function (projects) {
                $scope.projects = projects;
            });
        });
})();<|endoftext|>


<commit_before>'use strict';

angular.module('deckApp')
  .factory('gceServerGroupService', function (settings, Restangular, $exceptionHandler, $q, accountService, mortService, gceInstanceTypeService) {

    // Two assumptions here:
    //   1) All GCE machine types are represented in the tree of choices.
    //   2) Each machine type appears in exactly one category.
    function determineInstanceCategoryFromInstanceType(command) {
      gceInstanceTypeService.getCategories().then(function(categories) {
        categories.forEach(function(category) {
          category.families.forEach(function(family) {
            family.instanceTypes.forEach(function(instanceType) {
              if (instanceType.name === command.instanceType) {
                command.viewState.instanceProfile = category.type;
              }
            });
          });
        });
      });
    }

    function buildNewServerGroupCommand(application) {
      // TODO(duftler): Load regions, zones, ...

    return {
      application: application.name,
      credentials: 'my-account-name',
      region: 'us-central1',
      capacity: {
        min: 0,
        max: 0,
        desired: 1
      },
      cooldown: 10,
      healthCheckType: 'EC2',
      healthCheckGracePeriod: 600,
      instanceMonitoring: false,
      ebsOptimized: false,
      selectedProvider: 'gce',
      iamRole: 'BaseIAMRole',       // should not be hard coded here

      terminationPolicies: ['Default'],
      vpcId: null,
      availabilityZones: [],
      keyPair: 'nf-test-keypair-a', // should not be hard coded here
      viewState: {
        instanceProfile: null,
        allImageSelection: null,
        useAllImageSelection: false,
        useSimpleCapacity: true,
        usePreferredZones: true,
        mode: 'create',
      },
    };
  }

    function buildServerGroupCommandFromExisting(application, serverGroup, mode, parseServerGroupName) {
      // TODO(duftler): Load regions, zones, ...

      mode = mode || 'clone';

      var serverGroupName = parseServerGroupName(serverGroup.name);

      var command = {
        application: application.name,
        stack: serverGroupName.stack,
        freeFormDetails: serverGroupName.freeFormDetails,
        credentials: serverGroup.account,
        cooldown: serverGroup.asg.defaultCooldown,
        healthCheckGracePeriod: serverGroup.asg.healthCheckGracePeriod,
        healthCheckType: serverGroup.asg.healthCheckType,
        terminationPolicies: serverGroup.asg.terminationPolicies,
        loadBalancers: serverGroup.asg.loadBalancerNames,
        region: serverGroup.region,
        capacity: {
          min: serverGroup.asg.minSize,
          max: serverGroup.asg.maxSize,
          desired: serverGroup.asg.desiredCapacity
        },
        zone: serverGroup.zones[0],
        availabilityZones: serverGroup.asg.availabilityZones,
        selectedProvider: 'gce',
        source: {
          account: serverGroup.account,
          region: serverGroup.region,
          zone: serverGroup.zones[0],
          serverGroupName: serverGroup.name
        },
        viewState: {
          allImageSelection: null,
          useAllImageSelection: false,
          useSimpleCapacity: serverGroup.asg.minSize === serverGroup.asg.maxSize,
          usePreferredZones: false,
          mode: mode,
        },
      };

      if (serverGroup.launchConfig) {
        angular.extend(command, {
          instanceType: serverGroup.launchConfig.instanceType,
          iamRole: serverGroup.launchConfig.iamInstanceProfile,
          keyPair: serverGroup.launchConfig.keyName,
          associatePublicIpAddress: serverGroup.launchConfig.associatePublicIpAddress,
          ramdiskId: serverGroup.launchConfig.ramdiskId,
          instanceMonitoring: serverGroup.launchConfig.instanceMonitoring && serverGroup.launchConfig.instanceMonitoring.enabled,
          ebsOptimized: serverGroup.launchConfig.ebsOptimized,
        });
        //command.viewState.imageId = serverGroup.launchConfig.imageId;
        command.viewState.imageId = 'debian-7-wheezy-v20141108';
        determineInstanceCategoryFromInstanceType(command);
      }

      return command;
    }

    return {
      buildNewServerGroupCommand: buildNewServerGroupCommand,
      buildServerGroupCommandFromExisting: buildServerGroupCommandFromExisting
    };
});

<commit_msg>Remove extraneous hard-coded testing value.<commit_after>'use strict';

angular.module('deckApp')
  .factory('gceServerGroupService', function (settings, Restangular, $exceptionHandler, $q, accountService, mortService, gceInstanceTypeService) {

    // Two assumptions here:
    //   1) All GCE machine types are represented in the tree of choices.
    //   2) Each machine type appears in exactly one category.
    function determineInstanceCategoryFromInstanceType(command) {
      gceInstanceTypeService.getCategories().then(function(categories) {
        categories.forEach(function(category) {
          category.families.forEach(function(family) {
            family.instanceTypes.forEach(function(instanceType) {
              if (instanceType.name === command.instanceType) {
                command.viewState.instanceProfile = category.type;
              }
            });
          });
        });
      });
    }

    function buildNewServerGroupCommand(application) {
      // TODO(duftler): Load regions, zones, ...

    return {
      application: application.name,
      credentials: 'my-account-name',
      region: 'us-central1',
      capacity: {
        min: 0,
        max: 0,
        desired: 1
      },
      cooldown: 10,
      healthCheckType: 'EC2',
      healthCheckGracePeriod: 600,
      instanceMonitoring: false,
      ebsOptimized: false,
      selectedProvider: 'gce',
      iamRole: 'BaseIAMRole',       // should not be hard coded here

      terminationPolicies: ['Default'],
      vpcId: null,
      availabilityZones: [],
      keyPair: 'nf-test-keypair-a', // should not be hard coded here
      viewState: {
        instanceProfile: null,
        allImageSelection: null,
        useAllImageSelection: false,
        useSimpleCapacity: true,
        usePreferredZones: true,
        mode: 'create',
      },
    };
  }

    function buildServerGroupCommandFromExisting(application, serverGroup, mode, parseServerGroupName) {
      // TODO(duftler): Load regions, zones, ...

      mode = mode || 'clone';

      var serverGroupName = parseServerGroupName(serverGroup.name);

      var command = {
        application: application.name,
        stack: serverGroupName.stack,
        freeFormDetails: serverGroupName.freeFormDetails,
        credentials: serverGroup.account,
        cooldown: serverGroup.asg.defaultCooldown,
        healthCheckGracePeriod: serverGroup.asg.healthCheckGracePeriod,
        healthCheckType: serverGroup.asg.healthCheckType,
        terminationPolicies: serverGroup.asg.terminationPolicies,
        loadBalancers: serverGroup.asg.loadBalancerNames,
        region: serverGroup.region,
        capacity: {
          min: serverGroup.asg.minSize,
          max: serverGroup.asg.maxSize,
          desired: serverGroup.asg.desiredCapacity
        },
        zone: serverGroup.zones[0],
        availabilityZones: serverGroup.asg.availabilityZones,
        selectedProvider: 'gce',
        source: {
          account: serverGroup.account,
          region: serverGroup.region,
          zone: serverGroup.zones[0],
          serverGroupName: serverGroup.name
        },
        viewState: {
          allImageSelection: null,
          useAllImageSelection: false,
          useSimpleCapacity: serverGroup.asg.minSize === serverGroup.asg.maxSize,
          usePreferredZones: false,
          mode: mode,
        },
      };

      if (serverGroup.launchConfig) {
        angular.extend(command, {
          instanceType: serverGroup.launchConfig.instanceType,
          iamRole: serverGroup.launchConfig.iamInstanceProfile,
          keyPair: serverGroup.launchConfig.keyName,
          associatePublicIpAddress: serverGroup.launchConfig.associatePublicIpAddress,
          ramdiskId: serverGroup.launchConfig.ramdiskId,
          instanceMonitoring: serverGroup.launchConfig.instanceMonitoring && serverGroup.launchConfig.instanceMonitoring.enabled,
          ebsOptimized: serverGroup.launchConfig.ebsOptimized,
        });
        command.viewState.imageId = serverGroup.launchConfig.imageId;
        determineInstanceCategoryFromInstanceType(command);
      }

      return command;
    }

    return {
      buildNewServerGroupCommand: buildNewServerGroupCommand,
      buildServerGroupCommandFromExisting: buildServerGroupCommandFromExisting
    };
});

<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';
import * as FeedbackActionCreators from './actions';
import styles from './index.module.scss';
import {
  FeedbackButton,
  AddFeedbackForm,
  LoadingIndicator,
 } from 'components';
import validation from './validation/index';
import { reduxForm } from 'redux-form';
import Footer from 'grommet-udacity/components/footer';
import Layer from 'grommet-udacity/components/layer';
import Box from 'grommet-udacity/components/box';
import Button from 'grommet-udacity/components/button';
import Menu from 'grommet-udacity/components/menu';
import Section from 'grommet-udacity/components/Section';
import { BASE_URL } from 'config';

export const addFeedbackFields = [
  'nameInput',
  'urlInput',
  'descriptionInput',
];

class FeedbackContainer extends Component {
  constructor() {
    super();
    this.handleToggleModal = this.handleToggleModal.bind(this);
    this.handleSubmitFeedback = this.handleSubmitFeedback.bind(this);
    this.handleClear = this.handleClear.bind(this);
  }
  componentWillReceiveProps({ fields, user, location }) {
    if(location && !fields.urlInput.value) {
      fields.urlInput.onChange(`${BASE_URL}${location.pathname}`);
    }
    if(location && !fields.nameInput.value) {
      if(user) {
        fields.nameInput.onChange(user.name);
      } else {
        fields.nameInput.onChange('Guest User');
      }
    }
  }
  handleToggleModal() {
    const {
      actions,
      isAddingFeedback,
    } = this.props;
    if (isAddingFeedback) {
      document.getElementById('app').classList.remove('no-scroll');
      this.handleClear();
    } else {
      document.getElementById('app').classList.add('no-scroll');
    }
    actions.toggleFeedbackModal();
  }
  handleSubmitFeedback() {
    const {
      user,
      actions,
      fields,
      authToken,
    } = this.props;
    if(user) {
      const data = {
        variables: {
          auth_token: authToken,
          feedback: {
            description: fields.descriptionInput.value,
            url: fields.urlInput.value,
          },
        },
      };
      actions.feedbackSubmissionInitiation();
      setTimeout(() => {
        this.props.submitFeedbackMutation(data)
          .then(() => {
            const message = 'Thank You for submitting feedback!' +
            '  We appreciate it greatly as it will help us to make this site better.';
            actions.feedbackSubmissionMessage(message);
          })
          .catch(err => {
            actions.feedbackSubmissionError(err);
          });
      }, 1000);
    } else {
      this.context.router.push('/login');
    }
  }
  handleClear() {
    const {
      resetForm,
    } = this.props;
    resetForm();
  }
  render() {
    const {
      user,
      location,
      isAddingFeedback,
      isSubmitting,
      hasFab,
      fields,
      resetForm,
      message,
    } = this.props;
    return (

        {isAddingFeedback ?
          <Layer
            onClose={this.handleToggleModal}
            a11yTitle={'Add Feedback'}
            closer
            align="right"
          >
            {isSubmitting &&
              <LoadingIndicator
                message="Submitting..."
                isLoading={isSubmitting}
              />
            }

              <Box pad={{ vertical: 'large', horizontal: 'small' }}>
                <AddFeedbackForm
                  {...fields}
                  user={user}
                  isSubmitting={isSubmitting}
                  message={message}
                  location={location}
                  onSubmitFeedback={this.handleSubmitFeedback}
                  onClear={resetForm}
                />
              </Box>

          </Layer>
        :

            <Menu direction="row">
              <Button
                className={styles.button}
                label="Add Feedback"
                primary
                onClick={this.handleToggleModal}
              />
            </Menu>
            {hasFab &&
              <FeedbackButton onClick={this.handleToggleModal}/>
            }

        }

    );
  }
}

FeedbackContainer.propTypes = {
  actions: PropTypes.object.isRequired,
  user: PropTypes.object.isRequired,
  location: PropTypes.object.isRequired,
  isAddingFeedback: PropTypes.bool.isRequired,
  onSubmitFeedback: PropTypes.func.isRequired,
  fields: PropTypes.object.isRequired,
  resetForm: PropTypes.func.isRequired,
  hasFab: PropTypes.bool.isRequired,
  submitFeedbackMutation: PropTypes.func.isRequired,
  isSubmitting: PropTypes.bool,
  message: PropTypes.string,
  authToken: PropTypes.string,
};

// mapStateToProps :: {State} -> {Props}
const mapStateToProps = (state) => ({
  isAddingFeedback: state.feedbackContainer.isAddingFeedback,
  isSubmitting: state.feedbackContainer.isSubmitting,
  message: state.feedbackContainer.message,
  user: state.app.user,
  authToken: state.app.authToken,
});

// mapDispatchToProps :: Dispatch -> {Action}
const mapDispatchToProps = (dispatch) => ({
  actions: bindActionCreators(
    FeedbackActionCreators,
    dispatch
  ),
});

const Container = reduxForm({
  form: 'addFeedback',
  fields: addFeedbackFields,
  validate: validation,
})(FeedbackContainer);

const createFeedbackMutation = gql`
  mutation createFeedback($feedback: FeedbackInput, $auth_token: String!){
  CreateFeedback(input:{feedback: $feedback, auth_token: $auth_token}){
    __typename
   }
  }
`;

const ContainerWithMutation = graphql(createFeedbackMutation, {
  props: ({ mutate }) => ({
    submitFeedbackMutation: mutate,
  }),
})(Container);

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(ContainerWithMutation);
<commit_msg>Fix: Remove leading forward slash for the feedback url<commit_after>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';
import * as FeedbackActionCreators from './actions';
import styles from './index.module.scss';
import {
  FeedbackButton,
  AddFeedbackForm,
  LoadingIndicator,
 } from 'components';
import validation from './validation/index';
import { reduxForm } from 'redux-form';
import Footer from 'grommet-udacity/components/footer';
import Layer from 'grommet-udacity/components/layer';
import Box from 'grommet-udacity/components/box';
import Button from 'grommet-udacity/components/button';
import Menu from 'grommet-udacity/components/menu';
import Section from 'grommet-udacity/components/Section';
import { BASE_URL } from 'config';

export const addFeedbackFields = [
  'nameInput',
  'urlInput',
  'descriptionInput',
];

class FeedbackContainer extends Component {
  constructor() {
    super();
    this.handleToggleModal = this.handleToggleModal.bind(this);
    this.handleSubmitFeedback = this.handleSubmitFeedback.bind(this);
    this.handleClear = this.handleClear.bind(this);
  }
  componentWillReceiveProps({ fields, user, location }) {
    if(location && !fields.urlInput.value) {
      const APPEND_LOCATION = location.pathname
                                .substring(1, (location.pathname.length));
      fields.urlInput.onChange(`${BASE_URL}${APPEND_LOCATION}`);
    }
    if(location && !fields.nameInput.value) {
      if(user) {
        fields.nameInput.onChange(user.name);
      } else {
        fields.nameInput.onChange('Guest User');
      }
    }
  }
  handleToggleModal() {
    const {
      actions,
      isAddingFeedback,
    } = this.props;
    if (isAddingFeedback) {
      document.getElementById('app').classList.remove('no-scroll');
      this.handleClear();
    } else {
      document.getElementById('app').classList.add('no-scroll');
    }
    actions.toggleFeedbackModal();
  }
  handleSubmitFeedback() {
    const {
      user,
      actions,
      fields,
      authToken,
    } = this.props;
    if(user) {
      const data = {
        variables: {
          auth_token: authToken,
          feedback: {
            description: fields.descriptionInput.value,
            url: fields.urlInput.value,
          },
        },
      };
      actions.feedbackSubmissionInitiation();
      setTimeout(() => {
        this.props.submitFeedbackMutation(data)
          .then(() => {
            const message = 'Thank You for submitting feedback!' +
            '  We appreciate it greatly as it will help us to make this site better.';
            actions.feedbackSubmissionMessage(message);
          })
          .catch(err => {
            actions.feedbackSubmissionError(err);
          });
      }, 1000);
    } else {
      this.context.router.push('/login');
    }
  }
  handleClear() {
    const {
      resetForm,
    } = this.props;
    resetForm();
  }
  render() {
    const {
      user,
      location,
      isAddingFeedback,
      isSubmitting,
      hasFab,
      fields,
      resetForm,
      message,
    } = this.props;
    return (

        {isAddingFeedback ?
          <Layer
            onClose={this.handleToggleModal}
            a11yTitle={'Add Feedback'}
            closer
            align="right"
          >
            {isSubmitting &&
              <LoadingIndicator
                message="Submitting..."
                isLoading={isSubmitting}
              />
            }

              <Box pad={{ vertical: 'large', horizontal: 'small' }}>
                <AddFeedbackForm
                  {...fields}
                  user={user}
                  isSubmitting={isSubmitting}
                  message={message}
                  location={location}
                  onSubmitFeedback={this.handleSubmitFeedback}
                  onClear={resetForm}
                />
              </Box>

          </Layer>
        :

            <Menu direction="row">
              <Button
                className={styles.button}
                label="Add Feedback"
                primary
                onClick={this.handleToggleModal}
              />
            </Menu>
            {hasFab &&
              <FeedbackButton onClick={this.handleToggleModal}/>
            }

        }

    );
  }
}

FeedbackContainer.propTypes = {
  actions: PropTypes.object.isRequired,
  user: PropTypes.object.isRequired,
  location: PropTypes.object.isRequired,
  isAddingFeedback: PropTypes.bool.isRequired,
  onSubmitFeedback: PropTypes.func.isRequired,
  fields: PropTypes.object.isRequired,
  resetForm: PropTypes.func.isRequired,
  hasFab: PropTypes.bool.isRequired,
  submitFeedbackMutation: PropTypes.func.isRequired,
  isSubmitting: PropTypes.bool,
  message: PropTypes.string,
  authToken: PropTypes.string,
};

// mapStateToProps :: {State} -> {Props}
const mapStateToProps = (state) => ({
  isAddingFeedback: state.feedbackContainer.isAddingFeedback,
  isSubmitting: state.feedbackContainer.isSubmitting,
  message: state.feedbackContainer.message,
  user: state.app.user,
  authToken: state.app.authToken,
});

// mapDispatchToProps :: Dispatch -> {Action}
const mapDispatchToProps = (dispatch) => ({
  actions: bindActionCreators(
    FeedbackActionCreators,
    dispatch
  ),
});

const Container = reduxForm({
  form: 'addFeedback',
  fields: addFeedbackFields,
  validate: validation,
})(FeedbackContainer);

const createFeedbackMutation = gql`
  mutation createFeedback($feedback: FeedbackInput, $auth_token: String!){
  CreateFeedback(input:{feedback: $feedback, auth_token: $auth_token}){
    __typename
   }
  }
`;

const ContainerWithMutation = graphql(createFeedbackMutation, {
  props: ({ mutate }) => ({
    submitFeedbackMutation: mutate,
  }),
})(Container);

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(ContainerWithMutation);
<|endoftext|>


<commit_before>// @flow

/* eslint-disable no-console */

import { table } from 'table';
import { red } from 'chalk';
import { path, pathOr, prop, forEach, map, join, compose, filter } from 'ramda';

import gql from '../gql';
import { runGQLQuery } from '../query';
import { exitNoConfig, exitGraphQLError } from '../exit';

import typeof Yargs from 'yargs';
import type { BaseArgs } from './index';

const tableConfig = {
  columns: {
    // $FlowIssue: Flow doesn't understand numbers as keys https://github.com/facebook/flow/issues/380
    0: {
      // eslint-disable-line quote-props
      alignment: 'left',
      minWidth: 15,
    },
    // $FlowIssue: Flow doesn't understand numbers as keys https://github.com/facebook/flow/issues/380
    1: {
      // eslint-disable-line quote-props
      alignment: 'left',
      minWidth: 15,
    },
  },
};

// Common filter
const onlyValues = ([, value]: [string, string]) => value != null && value !== '';

const name = 'info';
const description = 'Shows infos about sites or sitegroups';

export async function setup(yargs: Yargs): Promise<Object> {
  return yargs
    .usage(`$0 ${name} [site@branch] - ${description}`)
    .options({
      sitegroup: {
        demandOption: false,
        describe: 'Overrides the currently configured sitegroup (.amazeeio.yml)',
        type: 'string',
      },
    })
    .alias('s', 'sitegroup')
    .example(`$0 ${name}`, 'Shows information about the configured sitegroup')
    .example(
      `$0 ${name} mysite`,
      'Shows information about given site "mysite" (does only work with single branch)',
    )
    .example(
      `$0 ${name} mysite@prod`,
      'Shows information about given site "mysite" with branch "prod" (sitegroup as stated by config)',
    )
    .example(
      `$0 ${name} -s mysitegroup mysite`,
      'Shows information about given site "mysite" in given sitegroup "somesitegroup"',
    ).argv;
}

type SiteGroupInfoArgs = {
  sitegroup: string,
  clog?: typeof console.log,
};

export async function sitegroupInfo(args: SiteGroupInfoArgs): Promise<number> {
  const { sitegroup, clog = console.log } = args;

  const query = gql`
    query querySites($sitegroup: String!) {
      siteGroupByName(name: $sitegroup) {
        gitUrl
        siteGroupName
        slack
        client {
          clientName
        }
        sites {
          siteName
          siteBranch
        }
      }
    }
  `;

  const result = await runGQLQuery({
    query,
    port: 80,
    variables: { sitegroup },
  });

  const { errors } = result;
  if (errors != null) {
    return exitGraphQLError(clog, errors);
  }

  const sitegroupData = path(['data', 'siteGroupByName'])(result);

  if (sitegroupData == null) {
    clog(red(`No sitegroup '${sitegroup}' found`));
    return 1;
  }

  const sites = compose(
    map((edge) => {
      const { siteName, siteBranch } = prop(['node'], edge);
      return `${siteName}:${siteBranch}`;
    }),
    pathOr([], ['data', 'siteGroupByName', 'sites', 'edges']),
  )(result);

  const formatSlack = (slack) => {
    if (slack == null) {
      return '';
    }

    const webhook = path(['webhook'], slack);
    const channel = path(['channel'], slack);

    return `${channel} -> ${webhook}`;
  };

  const tableBody = [
    ['SiteGroup Name', path(['siteGroupName'], sitegroupData)],
    ['Git Url', path(['gitUrl'], sitegroupData)],
    ['Slack', formatSlack(path(['slack'], sitegroupData))],
    ['Sites', join(', ', sites)],
  ];

  const tableData = filter(onlyValues)(tableBody);

  clog(`I found following information for sitegroup '${sitegroup}':`);
  clog(table(tableData, tableConfig));

  return 0;
}

type SiteInfoArgs = {
  site: string,
  branch?: string,
  sitegroup: string,
  clog?: typeof console.log,
};

export async function siteInfo(args: SiteInfoArgs): Promise<number> {
  const { sitegroup, site, branch, clog = console.log } = args;

  // site[@branch]
  const siteBranchStr = `${site}${branch != null ? `@${branch}` : ''}`;

  const query = gql`
    query querySites($sitegroup: String!) {
      siteGroupByName(name: $sitegroup) {
        gitUrl
        sites(first: 1000) {
          edges {
            node {
              id
              siteHost
              siteName
              siteBranch
              siteEnvironment
              serverInfrastructure
              serverIdentifier
              serverNames
              webRoot
              drupalVersion
              SSLCertificateType
              FPMProfile
              domains
              redirectDomains
              redirects
              uid
              dbUser
              cron {
                type
                minute
              }
              customCron
              envVariables
              noPrefixenvVariables
              phpValues
              phpAdminFlags
              xdebug
              nginxSitespecific
              nginxSiteconfig
              solrEnabled
              redisEnabled
              sshKeys
              phpVersion
              redirectToHttps
              ensure
              upstreamURL
              apc
              basicAuth {
                username
              }
              fullJson
            }
          }
        }
      }
    }
  `;

  const result = await runGQLQuery({
    endpoint: 'http://api-develop-testhiera.appuio.amazeeio.review/graphql',
    port: 80,
    query,
    variables: { sitegroup },
  });

  const { errors } = result;
  if (errors != null) {
    return exitGraphQLError(clog, errors);
  }

  // There might be a case where I just have one site + branch,
  // so we will just filter for branch, if a branch was actually
  // given. If there are multiple matches, we will tell the user
  // anyways
  const matchesSiteAndBranch = ({ siteName, siteBranch }) => {
    if (branch != null && siteBranch !== branch) {
      return false;
    }
    return siteName === site;
  };

  const nodes = compose(
    filter(matchesSiteAndBranch),
    map(edge => prop('node', edge)),
    pathOr([], ['data', 'siteGroupByName', 'sites', 'edges']),
  )(result);

  if (nodes.length === 0) {
    clog(red(`No site '${site}' found in sitegroup '${sitegroup}'`));
    return 0;
  }

  // For the case if there was no branch name given to begin with
  if (nodes.length > 1) {
    clog(
      'I found multiple sites with the same name, but different branches, maybe try following parameter...',
    );
    forEach(({ siteName, siteBranch }) => clog(`-> ${siteName}@${siteBranch}`))(nodes);
    return 0;
  }

  clog(`I found following information for '${sitegroup} -> ${siteBranchStr}':`);

  // nodes only contains one element, extract it
  const [node] = nodes;

  const formatCron = (cron) => {
    if (cron == null) {
      return '';
    }

    return `Type: ${cron.type} - Minute: ${cron.minute}`;
  };

  const formatArray = (arr) => {
    if (arr == null) {
      return '';
    }

    return join(', ', arr);
  };

  // We want to list these fields from the node result
  const tableBody = [
    ['ID', path(['id'], node)],
    ['Site Name', path(['siteName'], node)],
    ['Site Branch', path(['siteBranch'], node)],
    ['Site Env', path(['siteEnvironment'], node)],
    ['User Id', path(['uid'], node)],
    ['Server Names', path(['serverNames'], node)],
    ['Webroot', path(['webRoot'], node)],
    ['Domains', formatArray(path(['domains'], node))],
    ['Redirect Domains', formatArray(path(['redirectDomains'], node))],
    ['SSL Certificate Type', path(['SSLCertificateType'], node)],
    ['Cron', formatCron(path(['cron'], node))],
    ['Solr Enabled', path(['solrEnabled'], node)],
  ];

  const tableData = filter(onlyValues)(tableBody);

  clog(table(tableData, tableConfig));

  return 0;
}

type Args = BaseArgs & {
  sitegroup: ?string,
};

export async function run(args: Args): Promise<number> {
  const { config, clog = console.log } = args;

  if (config == null) {
    return exitNoConfig(clog);
  }

  const [siteAndBranch] = args._.slice(1);
  const sitegroup = args.sitegroup || config.sitegroup;

  if (siteAndBranch == null) {
    return sitegroupInfo({ sitegroup, clog });
  }

  const [site, branch] = siteAndBranch.split('@');

  return siteInfo({
    site,
    branch,
    sitegroup,
    clog,
  });
}

export default {
  setup,
  name,
  description,
  run,
};
<commit_msg>Fix query for info<commit_after>// @flow

/* eslint-disable no-console */

import { table } from 'table';
import { red } from 'chalk';
import { path, pathOr, prop, forEach, map, join, compose, filter } from 'ramda';

import gql from '../gql';
import { runGQLQuery } from '../query';
import { exitNoConfig, exitGraphQLError } from '../exit';

import typeof Yargs from 'yargs';
import type { BaseArgs } from './index';

const tableConfig = {
  columns: {
    // $FlowIssue: Flow doesn't understand numbers as keys https://github.com/facebook/flow/issues/380
    0: {
      // eslint-disable-line quote-props
      alignment: 'left',
      minWidth: 15,
    },
    // $FlowIssue: Flow doesn't understand numbers as keys https://github.com/facebook/flow/issues/380
    1: {
      // eslint-disable-line quote-props
      alignment: 'left',
      minWidth: 15,
    },
  },
};

// Common filter
const onlyValues = ([, value]: [string, string]) => value != null && value !== '';

const name = 'info';
const description = 'Shows infos about sites or sitegroups';

export async function setup(yargs: Yargs): Promise<Object> {
  return yargs
    .usage(`$0 ${name} [site@branch] - ${description}`)
    .options({
      sitegroup: {
        demandOption: false,
        describe: 'Overrides the currently configured sitegroup (.amazeeio.yml)',
        type: 'string',
      },
    })
    .alias('s', 'sitegroup')
    .example(`$0 ${name}`, 'Shows information about the configured sitegroup')
    .example(
      `$0 ${name} mysite`,
      'Shows information about given site "mysite" (does only work with single branch)',
    )
    .example(
      `$0 ${name} mysite@prod`,
      'Shows information about given site "mysite" with branch "prod" (sitegroup as stated by config)',
    )
    .example(
      `$0 ${name} -s mysitegroup mysite`,
      'Shows information about given site "mysite" in given sitegroup "somesitegroup"',
    ).argv;
}

type SiteGroupInfoArgs = {
  sitegroup: string,
  clog?: typeof console.log,
};

export async function sitegroupInfo(args: SiteGroupInfoArgs): Promise<number> {
  const { sitegroup, clog = console.log } = args;

  const query = gql`
    query querySites($sitegroup: String!) {
      siteGroupByName(name: $sitegroup) {
        gitUrl
        siteGroupName
        slack {
          webhook
          channel
          informStart
          informChannel
        }
        client {
          clientName
        }
        sites {
          siteName
          siteBranch
        }
      }
    }
  `;

  const result = await runGQLQuery({
    query,
    port: 80,
    variables: { sitegroup },
  });

  const { errors } = result;
  if (errors != null) {
    return exitGraphQLError(clog, errors);
  }

  const sitegroupData = path(['data', 'siteGroupByName'])(result);

  if (sitegroupData == null) {
    clog(red(`No sitegroup '${sitegroup}' found`));
    return 1;
  }

  const sites = compose(
    map((edge) => {
      const { siteName, siteBranch } = prop(['node'], edge);
      return `${siteName}:${siteBranch}`;
    }),
    pathOr([], ['data', 'siteGroupByName', 'sites', 'edges']),
  )(result);

  const formatSlack = (slack) => {
    if (slack == null) {
      return '';
    }

    const webhook = path(['webhook'], slack);
    const channel = path(['channel'], slack);

    return `${channel} -> ${webhook}`;
  };

  const tableBody = [
    ['SiteGroup Name', path(['siteGroupName'], sitegroupData)],
    ['Git Url', path(['gitUrl'], sitegroupData)],
    ['Slack', formatSlack(path(['slack'], sitegroupData))],
    ['Sites', join(', ', sites)],
  ];

  const tableData = filter(onlyValues)(tableBody);

  clog(`I found following information for sitegroup '${sitegroup}':`);
  clog(table(tableData, tableConfig));

  return 0;
}

type SiteInfoArgs = {
  site: string,
  branch?: string,
  sitegroup: string,
  clog?: typeof console.log,
};

export async function siteInfo(args: SiteInfoArgs): Promise<number> {
  const { sitegroup, site, branch, clog = console.log } = args;

  // site[@branch]
  const siteBranchStr = `${site}${branch != null ? `@${branch}` : ''}`;

  const query = gql`
    query querySites($sitegroup: String!) {
      siteGroupByName(name: $sitegroup) {
        gitUrl
        sites(first: 1000) {
          edges {
            node {
              id
              siteHost
              siteName
              siteBranch
              siteEnvironment
              serverInfrastructure
              serverIdentifier
              serverNames
              webRoot
              drupalVersion
              SSLCertificateType
              FPMProfile
              domains
              redirectDomains
              redirects
              uid
              dbUser
              cron {
                type
                minute
              }
              customCron
              envVariables
              noPrefixenvVariables
              phpValues
              phpAdminFlags
              xdebug
              nginxSitespecific
              nginxSiteconfig
              solrEnabled
              redisEnabled
              sshKeys
              phpVersion
              redirectToHttps
              ensure
              upstreamURL
              apc
              basicAuth {
                username
              }
              fullJson
            }
          }
        }
      }
    }
  `;

  const result = await runGQLQuery({
    endpoint: 'http://api-develop-testhiera.appuio.amazeeio.review/graphql',
    port: 80,
    query,
    variables: { sitegroup },
  });

  const { errors } = result;
  if (errors != null) {
    return exitGraphQLError(clog, errors);
  }

  // There might be a case where I just have one site + branch,
  // so we will just filter for branch, if a branch was actually
  // given. If there are multiple matches, we will tell the user
  // anyways
  const matchesSiteAndBranch = ({ siteName, siteBranch }) => {
    if (branch != null && siteBranch !== branch) {
      return false;
    }
    return siteName === site;
  };

  const nodes = compose(
    filter(matchesSiteAndBranch),
    map(edge => prop('node', edge)),
    pathOr([], ['data', 'siteGroupByName', 'sites', 'edges']),
  )(result);

  if (nodes.length === 0) {
    clog(red(`No site '${site}' found in sitegroup '${sitegroup}'`));
    return 0;
  }

  // For the case if there was no branch name given to begin with
  if (nodes.length > 1) {
    clog(
      'I found multiple sites with the same name, but different branches, maybe try following parameter...',
    );
    forEach(({ siteName, siteBranch }) => clog(`-> ${siteName}@${siteBranch}`))(nodes);
    return 0;
  }

  clog(`I found following information for '${sitegroup} -> ${siteBranchStr}':`);

  // nodes only contains one element, extract it
  const [node] = nodes;

  const formatCron = (cron) => {
    if (cron == null) {
      return '';
    }

    return `Type: ${cron.type} - Minute: ${cron.minute}`;
  };

  const formatArray = (arr) => {
    if (arr == null) {
      return '';
    }

    return join(', ', arr);
  };

  // We want to list these fields from the node result
  const tableBody = [
    ['ID', path(['id'], node)],
    ['Site Name', path(['siteName'], node)],
    ['Site Branch', path(['siteBranch'], node)],
    ['Site Env', path(['siteEnvironment'], node)],
    ['User Id', path(['uid'], node)],
    ['Server Names', path(['serverNames'], node)],
    ['Webroot', path(['webRoot'], node)],
    ['Domains', formatArray(path(['domains'], node))],
    ['Redirect Domains', formatArray(path(['redirectDomains'], node))],
    ['SSL Certificate Type', path(['SSLCertificateType'], node)],
    ['Cron', formatCron(path(['cron'], node))],
    ['Solr Enabled', path(['solrEnabled'], node)],
  ];

  const tableData = filter(onlyValues)(tableBody);

  clog(table(tableData, tableConfig));

  return 0;
}

type Args = BaseArgs & {
  sitegroup: ?string,
};

export async function run(args: Args): Promise<number> {
  const { config, clog = console.log } = args;

  if (config == null) {
    return exitNoConfig(clog);
  }

  const [siteAndBranch] = args._.slice(1);
  const sitegroup = args.sitegroup || config.sitegroup;

  if (siteAndBranch == null) {
    return sitegroupInfo({ sitegroup, clog });
  }

  const [site, branch] = siteAndBranch.split('@');

  return siteInfo({
    site,
    branch,
    sitegroup,
    clog,
  });
}

export default {
  setup,
  name,
  description,
  run,
};
<|endoftext|>