Merge pull request #3088 from quay/joseph.schorr/QUAY-940/url-join-libn

Change to using a lib to build URLs
This commit is contained in:
Joseph Schorr 2018-05-22 14:05:21 -04:00 committed by GitHub
commit 2e403633b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 85 additions and 318 deletions

View file

@ -84,7 +84,7 @@ angular.module('quay').directive('entitySearch', function () {
$scope.checkLazyLoad = function() {
if (!$scope.namespace || !$scope.thisUser || !$scope.requiresLazyLoading ||
$scope.isLazyLoading || !$scope.userRequestedLazyLoading) {
return;
return;
}
$scope.isLazyLoading = true;
@ -229,15 +229,20 @@ angular.module('quay').directive('entitySearch', function () {
name: 'entities' + $rootScope.__entity_search_counter,
remote: {
url: '/api/v1/entities/%QUERY',
replace: function (url, uriEncodedQuery) {
replace: function (query_url, uriEncodedQuery) {
$scope.lazyLoad();
var namespace = $scope.namespace || '';
url = url.replace('%QUERY', uriEncodedQuery);
url += '?namespace=' + encodeURIComponent(namespace);
var url = UtilService.getRestUrl(query_url.replace('%QUERY', uriEncodedQuery));
url.setQueryParameter('namespace', namespace);
if ($scope.isOrganization && isSupported('team')) {
url += '&includeTeams=true'
url.setQueryParameter('includeTeams', true);
}
if (isSupported('org')) {
url += '&includeOrgs=true'
url.setQueryParameter('includeOrgs', true);
}
return url;
},

View file

@ -1,76 +0,0 @@
/**
* An element which displays a small flag representing the given location, as well as a ping
* latency gauge for that location.
*/
angular.module('quay').directive('locationView', function () {
var directiveDefinitionObject = {
priority: 0,
templateUrl: '/static/directives/location-view.html',
replace: false,
transclude: true,
restrict: 'C',
scope: {
'location': '=location'
},
controller: function($rootScope, $scope, $element, $http, PingService) {
var LOCATIONS = {
'local_us': { 'country': 'US', 'data': 'quay-registry.s3.amazonaws.com', 'title': 'United States' },
'local_eu': { 'country': 'EU', 'data': 'quay-registry-eu.s3-eu-west-1.amazonaws.com', 'title': 'Europe' },
's3_us_east_1': { 'country': 'US', 'data': 'quay-registry.s3.amazonaws.com', 'title': 'United States (East)' },
's3_us_west_1': { 'country': 'US', 'data': 'quay-registry-cali.s3.amazonaws.com', 'title': 'United States (West)' },
's3_eu_west_1': { 'country': 'EU', 'data': 'quay-registry-eu.s3-eu-west-1.amazonaws.com', 'title': 'Europe' },
's3_ap_southeast_1': { 'country': 'SG', 'data': 'quay-registry-singapore.s3-ap-southeast-1.amazonaws.com', 'title': 'Singapore' },
's3_ap_southeast_2': { 'country': 'AU', 'data': 'quay-registry-sydney.s3-ap-southeast-2.amazonaws.com', 'title': 'Australia' },
// 's3_ap_northeast-1': { 'country': 'JP', 'data': 's3-ap-northeast-1.amazonaws.com', 'title': 'Japan' },
// 's3_sa_east1': { 'country': 'BR', 'data': 's3-east-1.amazonaws.com', 'title': 'Sao Paulo' }
};
$scope.locationPing = null;
$scope.getLocationTooltip = function(location, ping) {
var tip = $scope.getLocationTitle(location) + '<br>';
if (ping == null) {
tip += '(Loading)';
} else if (ping < 0) {
tip += '<br><b>Note: Could not contact server</b>';
} else {
tip += 'Estimated Ping: ' + (ping ? ping + 'ms' : '(Loading)');
}
return tip;
};
$scope.getLocationTitle = function(location) {
if (!LOCATIONS[location]) {
return '(Unknown)';
}
return 'Image data is located in ' + LOCATIONS[location]['title'];
};
$scope.getLocationImage = function(location) {
if (!LOCATIONS[location]) {
return 'unknown.png';
}
return LOCATIONS[location]['country'] + '.png';
};
$scope.getLocationPing = function(location) {
var url = 'https://' + LOCATIONS[location]['data'] + '/okay.txt';
PingService.pingUrl($scope, url, function(ping, success, count) {
if (count == 3 || !success) {
$scope.locationPing = success ? ping : -1;
}
});
};
$scope.$watch('location', function(location) {
if (!location) { return; }
$scope.getLocationPing(location);
});
}
};
return directiveDefinitionObject;
});

View file

@ -1,5 +1,5 @@
import { LogUsageChart } from '../../graphing';
import { parse } from 'path';
/**
* Element which displays usage logs for the given entity.
@ -383,8 +383,8 @@ angular.module('quay').directive('logsView', function () {
url = UtilService.getRestUrl('superuser', suffix)
}
url += '?starttime=' + encodeURIComponent(getDateString($scope.options.logStartDate));
url += '&endtime=' + encodeURIComponent(getDateString($scope.options.logEndDate));
url.setQueryParameter('starttime', getDateString($scope.options.logStartDate));
url.setQueryParameter('endtime', getDateString($scope.options.logEndDate));
return url;
};
@ -405,7 +405,7 @@ angular.module('quay').directive('logsView', function () {
$scope.chartLoading = true;
var aggregateUrl = getUrl('aggregatelogs')
var aggregateUrl = getUrl('aggregatelogs').toString();
var loadAggregate = Restangular.one(aggregateUrl);
loadAggregate.customGET().then(function(resp) {
$scope.chart = new LogUsageChart(logKinds);
@ -430,12 +430,10 @@ angular.module('quay').directive('logsView', function () {
$scope.loading = true;
var logsUrl = getUrl('logs');
if ($scope.nextPageToken) {
logsUrl = logsUrl + '&next_page=' + encodeURIComponent($scope.nextPageToken);
}
var url = getUrl('logs');
url.setQueryParameter('next_page', $scope.nextPageToken);
var loadLogs = Restangular.one(logsUrl);
var loadLogs = Restangular.one(url.toString());
loadLogs.customGET().then(function(resp) {
resp.logs.forEach(function(log) {
$scope.logs.push(log);

View file

@ -1,76 +0,0 @@
/**
* An element which displays a repository search box.
*/
angular.module('quay').directive('repoSearch', function () {
var number = 0;
var directiveDefinitionObject = {
priority: 0,
templateUrl: '/static/directives/repo-search.html',
replace: false,
transclude: false,
restrict: 'C',
scope: {
},
controller: function($scope, $element, $location, UserService, Restangular, UtilService) {
var searchToken = 0;
$scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
++searchToken;
}, true);
var repoHound = new Bloodhound({
name: 'repositories',
remote: {
url: '/api/v1/find/repository?query=%QUERY',
replace: function (url, uriEncodedQuery) {
url = url.replace('%QUERY', uriEncodedQuery);
url += '&cb=' + searchToken;
return url;
},
filter: function(data) {
var datums = [];
for (var i = 0; i < data.repositories.length; ++i) {
var repo = data.repositories[i];
datums.push({
'value': repo.name,
'tokens': [repo.name, repo.namespace],
'repo': repo
});
}
return datums;
}
},
datumTokenizer: function(d) {
return Bloodhound.tokenizers.whitespace(d.val);
},
queryTokenizer: Bloodhound.tokenizers.whitespace
});
repoHound.initialize();
var element = $($element[0].childNodes[0]);
element.typeahead({ 'highlight': true }, {
source: repoHound.ttAdapter(),
templates: {
'suggestion': function (datum) {
template = '<div class="repo-mini-listing">';
template += '<i class="fa fa-hdd-o fa-lg"></i>'
template += '<span class="name">' + datum.repo.namespace +'/' + datum.repo.name + '</span>'
if (datum.repo.description) {
template += '<span class="description">' + UtilService.getFirstMarkdownLineAsText(datum.repo.description) + '</span>'
}
template += '</div>'
return template;
}
}
});
element.on('typeahead:selected', function (e, datum) {
element.typeahead('val', '');
$scope.$apply(function() {
$location.path('/repository/' + datum.repo.namespace + '/' + datum.repo.name);
});
});
}
};
return directiveDefinitionObject;
});

View file

@ -1,3 +1,5 @@
var urlParseURL = require('url-parse');
/**
* Service which exposes the server-defined API as a nice set of helper methods and automatic
* callbacks. Any method defined on the server is exposed here as an equivalent method. Also
@ -44,7 +46,7 @@ angular.module('quay').factory('ApiService', ['Restangular', '$q', 'UtilService'
// Build the path, adjusted with the inline parameters.
var used = {};
var url = '';
var urlPath = '';
for (var i = 0; i < path.length; ++i) {
var c = path[i];
if (c == '{') {
@ -56,29 +58,29 @@ angular.module('quay').factory('ApiService', ['Restangular', '$q', 'UtilService'
}
used[varName] = true;
url += parameters[varName];
urlPath += encodeURI(parameters[varName]);
i = end;
continue;
}
url += c;
urlPath += c;
}
// Append any query parameters.
var isFirst = true;
var url = new urlParseURL(urlPath, '/');
url.query = {};
for (var paramName in parameters) {
if (!parameters.hasOwnProperty(paramName)) { continue; }
if (used[paramName]) { continue; }
var value = parameters[paramName];
if (value != null) {
url += isFirst ? '?' : '&';
url += paramName + '=' + encodeURIComponent(value)
isFirst = false;
url.query[paramName] = value
}
}
return url;
return url.toString();
};
var getGenericOperationName = function(userOperationName) {

View file

@ -1,99 +0,0 @@
/**
* Service which pings an endpoint URL and estimates the latency to it.
*/
angular.module('quay').factory('PingService', [function() {
var pingService = {};
var pingCache = {};
var invokeCallback = function($scope, pings, callback) {
if (pings[0] == -1) {
setTimeout(function() {
$scope.$apply(function() {
callback(-1, false, -1);
});
}, 0);
return;
}
var sum = 0;
for (var i = 0; i < pings.length; ++i) {
sum += pings[i];
}
// Report the average ping.
setTimeout(function() {
$scope.$apply(function() {
callback(Math.floor(sum / pings.length), true, pings.length);
});
}, 0);
};
var reportPingResult = function($scope, url, ping, callback) {
// Lookup the cached ping data, if any.
var cached = pingCache[url];
if (!cached) {
cached = pingCache[url] = {
'pings': []
};
}
// If an error occurred, report it and done.
if (ping < 0) {
cached['pings'] = [-1];
invokeCallback($scope, [-1], callback);
return;
}
// Otherwise, add the current ping and determine the average.
cached['pings'].push(ping);
// Invoke the callback.
invokeCallback($scope, cached['pings'], callback);
// Schedule another check if we've done less than three.
if (cached['pings'].length < 3) {
setTimeout(function() {
pingUrlInternal($scope, url, callback);
}, 1000);
}
};
var pingUrlInternal = function($scope, url, callback) {
var path = url + '?cb=' + (Math.random() * 100);
var start = new Date();
var xhr = new XMLHttpRequest();
xhr.onerror = function() {
reportPingResult($scope, url, -1, callback);
};
xhr.onreadystatechange = function () {
if (xhr.readyState === xhr.HEADERS_RECEIVED) {
if (xhr.status != 200) {
reportPingResult($scope, url, -1, callback);
return;
}
var ping = (new Date() - start);
reportPingResult($scope, url, ping, callback);
}
};
xhr.open("GET", path);
xhr.send(null);
};
pingService.pingUrl = function($scope, url, callback) {
if (pingCache[url]) {
invokeCallback($scope, pingCache[url]['pings'], callback);
return;
}
// Note: We do each in a callback after 1s to prevent it running when other code
// runs (which can skew the results).
setTimeout(function() {
pingUrlInternal($scope, url, callback);
}, 1000);
};
return pingService;
}]);

View file

@ -29,7 +29,7 @@ angular.module('quay').factory('RolesService', ['UtilService', 'Restangular', 'A
var namespace = repository.namespace;
var name = repository.name;
var url = UtilService.getRestUrl('repository', namespace, name, 'permissions', entityKind, entityName);
return Restangular.one(url);
return Restangular.one(url.toString());
};
roleService.deleteRepositoryRole = function(repository, entityKind, entityName, callback) {

View file

@ -23,11 +23,13 @@ angular.module('quay').factory('TriggerService', ['UtilService', '$sanitize', 'K
var redirect_uri = KeyService['githubRedirectUri'] + '/trigger/' +
namespace + '/' + repository;
var authorize_url = KeyService['githubTriggerAuthorizeUrl'];
var client_id = KeyService['githubTriggerClientId'];
return authorize_url + 'client_id=' + client_id +
'&scope=repo,user:email&redirect_uri=' + redirect_uri;
var authorize_url = new UtilService.UrlBuilder(KeyService['githubTriggerAuthorizeUrl']);
authorize_url.setQueryParameter('client_id', client_id);
authorize_url.setQueryParameter('scope', 'repo,user:email');
authorize_url.setQueryParameter('redirect_uri', redirect_uri);
return authorize_url.toString();
},
'is_external': true,
'is_enabled': function() {
@ -81,10 +83,14 @@ angular.module('quay').factory('TriggerService', ['UtilService', '$sanitize', 'K
'run_parameters': [branch_tag],
'get_redirect_url': function(namespace, repository) {
var redirect_uri = KeyService['gitlabRedirectUri'] + '/trigger';
var authorize_url = KeyService['gitlabTriggerAuthorizeUrl'];
var client_id = KeyService['gitlabTriggerClientId'];
return authorize_url + 'client_id=' + client_id + '&redirect_uri=' + redirect_uri + '&response_type=code&state=repo:' + namespace + '/' + repository;
var authorize_url = new UtilService.UrlBuilder(KeyService['gitlabTriggerAuthorizeUrl']);
authorize_url.setQueryParameter('client_id', client_id);
authorize_url.setQueryParameter('state', 'repo:' + namespace + '/' + repository);
authorize_url.setQueryParameter('redirect_uri', redirect_uri);
authorize_url.setQueryParameter('response_type', 'code');
return authorize_url.toString();
},
'is_external': false,
'is_enabled': function() {

View file

@ -1,3 +1,23 @@
var urlParseURL = require('url-parse');
var UrlBuilder = function(initial_url) {
this.url = urlParseURL(initial_url || '', '/');
};
UrlBuilder.prototype.setQueryParameter = function(paramName, paramValue) {
if (paramValue == null) {
return;
}
this.url.query = this.url.query || {};
this.url.query[paramName] = paramValue;
};
UrlBuilder.prototype.toString = function() {
return this.url.toString();
};
/**
* Service which exposes various utility methods.
*/
@ -98,19 +118,23 @@ angular.module('quay').factory('UtilService', ['$sanitize', 'markdownConverter',
};
utilService.getRestUrl = function(args) {
var url = '';
var path = '';
for (var i = 0; i < arguments.length; ++i) {
if (i > 0) {
url += '/';
path += '/';
}
url += encodeURI(arguments[i])
path += encodeURI(arguments[i])
}
return url;
return new UrlBuilder(path);
};
utilService.textToSafeHtml = function(text) {
return $sanitize(utilService.escapeHtmlString(text));
};
utilService.UrlBuilder = UrlBuilder;
return utilService;
}]);