Merge remote-tracking branch 'origin/master' into tagyourit
Conflicts: endpoints/api.py static/js/app.js static/partials/view-repo.html test/data/test.db test/specs.py test/test_api_usage.py
This commit is contained in:
commit
302bfb27ae
123 changed files with 16314 additions and 3789 deletions
|
@ -638,10 +638,8 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
|||
$rootScope.description = jQuery(getFirstTextLine(repo.description)).text() ||
|
||||
'Visualization of images and tags for ' + kind + ' Docker repository: ' + qualifiedRepoName;
|
||||
|
||||
// If the repository is marked as building, start monitoring it for changes.
|
||||
if (repo.is_building) {
|
||||
startBuildInfoTimer(repo);
|
||||
}
|
||||
// Load the builds for this repository. If none are active it will cancel the poll.
|
||||
startBuildInfoTimer(repo);
|
||||
|
||||
$('#copyClipboard').clipboardCopy();
|
||||
});
|
||||
|
@ -672,15 +670,19 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
|||
};
|
||||
|
||||
ApiService.getRepoBuilds(null, params, true).then(function(resp) {
|
||||
// Build a filtered list of the builds that are currently running.
|
||||
var runningBuilds = [];
|
||||
for (var i = 0; i < resp.builds.length; ++i) {
|
||||
var build = resp.builds[i];
|
||||
if (build.status != 'complete') {
|
||||
if (build['phase'] != 'complete' && build['phase'] != 'error') {
|
||||
runningBuilds.push(build);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.buildsInfo = runningBuilds;
|
||||
var existingBuilds = $scope.runningBuilds || [];
|
||||
$scope.runningBuilds = runningBuilds;
|
||||
$scope.buildHistory = resp.builds;
|
||||
|
||||
if (!runningBuilds.length) {
|
||||
// Cancel the build timer.
|
||||
cancelBuildInfoTimer();
|
||||
|
@ -688,8 +690,10 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
|||
// Mark the repo as no longer building.
|
||||
$scope.repo.is_building = false;
|
||||
|
||||
// Reload the repo information.
|
||||
loadViewInfo();
|
||||
// Reload the repo information if all of the builds recently finished.
|
||||
if (existingBuilds.length > 0) {
|
||||
loadViewInfo();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -798,9 +802,23 @@ function BuildPackageCtrl($scope, Restangular, ApiService, $routeParams, $rootSc
|
|||
// itself (should) be the Dockerfile.
|
||||
if (zipFiles && Object.keys(zipFiles).length) {
|
||||
// Load the dockerfile contents.
|
||||
var dockerfile = zip.file('Dockerfile');
|
||||
var dockerfilePath = 'Dockerfile';
|
||||
if ($scope.repobuild['job_config']) {
|
||||
var dockerfileFolder = ($scope.repobuild['job_config']['build_subdir'] || '');
|
||||
if (dockerfileFolder[0] == '/') {
|
||||
dockerfileFolder = dockerfileFolder.substr(1);
|
||||
}
|
||||
if (dockerfileFolder && dockerfileFolder[dockerfileFolder.length - 1] != '/') {
|
||||
dockerfileFolder += '/';
|
||||
}
|
||||
|
||||
dockerfilePath = dockerfileFolder + 'Dockerfile';
|
||||
}
|
||||
|
||||
var dockerfile = zip.file(dockerfilePath);
|
||||
if (dockerfile) {
|
||||
$scope.dockerFileContents = dockerfile.asText();
|
||||
$scope.dockerFilePath = dockerfilePath;
|
||||
}
|
||||
|
||||
// Build the zip file tree.
|
||||
|
@ -815,21 +833,17 @@ function BuildPackageCtrl($scope, Restangular, ApiService, $routeParams, $rootSc
|
|||
});
|
||||
} else {
|
||||
$scope.dockerFileContents = response;
|
||||
$scope.dockerFilePath = 'Dockerfile';
|
||||
}
|
||||
|
||||
$scope.loaded = true;
|
||||
};
|
||||
|
||||
var downloadBuildPack = function() {
|
||||
var downloadBuildPack = function(url) {
|
||||
$scope.downloadProgress = 0;
|
||||
$scope.downloading = true;
|
||||
|
||||
ApiService.getRepoBuildArchiveUrl(null, params).then(function(resp) {
|
||||
startDownload(resp['url']);
|
||||
}, function() {
|
||||
$scope.downloading = false;
|
||||
$scope.downloadError = true;
|
||||
});
|
||||
startDownload(url);
|
||||
};
|
||||
|
||||
var startDownload = function(url) {
|
||||
|
@ -880,7 +894,7 @@ function BuildPackageCtrl($scope, Restangular, ApiService, $routeParams, $rootSc
|
|||
'name': name
|
||||
};
|
||||
|
||||
downloadBuildPack();
|
||||
downloadBuildPack(resp['archive_url']);
|
||||
return resp;
|
||||
});
|
||||
};
|
||||
|
@ -888,7 +902,8 @@ function BuildPackageCtrl($scope, Restangular, ApiService, $routeParams, $rootSc
|
|||
getBuildInfo();
|
||||
}
|
||||
|
||||
function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $location, $interval, $sanitize, ansi2html) {
|
||||
function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $location, $interval, $sanitize,
|
||||
ansi2html, AngularViewArray) {
|
||||
var namespace = $routeParams.namespace;
|
||||
var name = $routeParams.name;
|
||||
var pollTimerHandle = null;
|
||||
|
@ -904,7 +919,7 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
}
|
||||
});
|
||||
|
||||
$scope.builds = [];
|
||||
$scope.builds = null;
|
||||
$scope.polling = false;
|
||||
|
||||
$scope.buildDialogShowCounter = 0;
|
||||
|
@ -914,12 +929,16 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
};
|
||||
|
||||
$scope.handleBuildStarted = function(newBuild) {
|
||||
$scope.builds.push(newBuild);
|
||||
$scope.builds.unshift(newBuild);
|
||||
$scope.setCurrentBuild(newBuild['id'], true);
|
||||
};
|
||||
|
||||
$scope.adjustLogHeight = function() {
|
||||
$('.build-logs').height($(window).height() - 415);
|
||||
var triggerOffset = 0;
|
||||
if ($scope.currentBuild && $scope.currentBuild.trigger) {
|
||||
triggerOffset = 85;
|
||||
}
|
||||
$('.build-logs').height($(window).height() - 415 - triggerOffset);
|
||||
};
|
||||
|
||||
$scope.askRestartBuild = function(build) {
|
||||
|
@ -929,8 +948,14 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
$scope.restartBuild = function(build) {
|
||||
$('#confirmRestartBuildModal').modal('hide');
|
||||
|
||||
var subdirectory = '';
|
||||
if (build['job_config']) {
|
||||
subdirectory = build['job_config']['build_subdir'] || '';
|
||||
}
|
||||
|
||||
var data = {
|
||||
'file_id': build['resource_key']
|
||||
'file_id': build['resource_key'],
|
||||
'subdirectory': subdirectory
|
||||
};
|
||||
|
||||
var params = {
|
||||
|
@ -938,26 +963,18 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
};
|
||||
|
||||
ApiService.requestRepoBuild(data, params).then(function(newBuild) {
|
||||
$scope.builds.push(newBuild);
|
||||
$scope.builds.unshift(newBuild);
|
||||
$scope.setCurrentBuild(newBuild['id'], true);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.hasLogs = function(container) {
|
||||
return ((container.logs && container.logs.length) || (container._logs && container._logs.length));
|
||||
return container.logs.hasEntries;
|
||||
};
|
||||
|
||||
$scope.toggleLogs = function(container) {
|
||||
if (container._logs) {
|
||||
container.logs = container._logs;
|
||||
container._logs = null;
|
||||
} else {
|
||||
container._logs = container.logs;
|
||||
container.logs = null;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.setCurrentBuild = function(buildId, opt_updateURL) {
|
||||
if (!$scope.builds) { return; }
|
||||
|
||||
// Find the build.
|
||||
for (var i = 0; i < $scope.builds.length; ++i) {
|
||||
if ($scope.builds[i].id == buildId) {
|
||||
|
@ -1042,17 +1059,13 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
var entry = logs[i];
|
||||
var type = entry['type'] || 'entry';
|
||||
if (type == 'command' || type == 'phase' || type == 'error') {
|
||||
entry['_logs'] = [];
|
||||
entry['logs'] = AngularViewArray.create();
|
||||
entry['index'] = startIndex + i;
|
||||
|
||||
$scope.logEntries.push(entry);
|
||||
$scope.currentParentEntry = entry;
|
||||
$scope.currentParentEntry = entry;
|
||||
} else if ($scope.currentParentEntry) {
|
||||
if ($scope.currentParentEntry['logs']) {
|
||||
$scope.currentParentEntry['logs'].push(entry);
|
||||
} else {
|
||||
$scope.currentParentEntry['_logs'].push(entry);
|
||||
}
|
||||
$scope.currentParentEntry['logs'].push(entry);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1120,7 +1133,7 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
if ($location.search().current) {
|
||||
$scope.setCurrentBuild($location.search().current, false);
|
||||
} else if ($scope.builds.length > 0) {
|
||||
$scope.setCurrentBuild($scope.builds[$scope.builds.length - 1].id, true);
|
||||
$scope.setCurrentBuild($scope.builds[0].id, true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -1128,7 +1141,7 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
fetchRepository();
|
||||
}
|
||||
|
||||
function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope) {
|
||||
function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams, $rootScope, $location) {
|
||||
var namespace = $routeParams.namespace;
|
||||
var name = $routeParams.name;
|
||||
|
||||
|
@ -1138,6 +1151,33 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
|
||||
$scope.permissionCache = {};
|
||||
|
||||
$scope.githubRedirectUri = KeyService.githubRedirectUri;
|
||||
$scope.githubClientId = KeyService.githubClientId;
|
||||
|
||||
$scope.getBadgeFormat = function(format, repo) {
|
||||
if (!repo) { return; }
|
||||
|
||||
var imageUrl = 'https://quay.io/repository/' + namespace + '/' + name + '/status';
|
||||
if (!$scope.repo.is_public) {
|
||||
imageUrl += '?token=' + $scope.repo.status_token;
|
||||
}
|
||||
|
||||
var linkUrl = 'https://quay.io/repository/' + namespace + '/' + name;
|
||||
|
||||
switch (format) {
|
||||
case 'svg':
|
||||
return imageUrl;
|
||||
|
||||
case 'md':
|
||||
return '[](' + linkUrl + ')';
|
||||
|
||||
case 'asciidoc':
|
||||
return 'image:' + imageUrl + '["Docker Repository on Quay.io", link="' + linkUrl + '"]';
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
$scope.buildEntityForPermission = function(name, permission, kind) {
|
||||
var key = name + ':' + kind;
|
||||
if ($scope.permissionCache[key]) {
|
||||
|
@ -1196,7 +1236,7 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
};
|
||||
|
||||
var permissionPost = Restangular.one(getRestUrl('repository', namespace, name, 'permissions', kind, entityName));
|
||||
permissionPost.customPOST(permission).then(function(result) {
|
||||
permissionPost.customPUT(permission).then(function(result) {
|
||||
$scope.permissions[kind][entityName] = result;
|
||||
}, function(result) {
|
||||
$('#cannotchangeModal').modal({});
|
||||
|
@ -1358,6 +1398,130 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
});
|
||||
};
|
||||
|
||||
$scope.showBuild = function(buildInfo) {
|
||||
$location.path('/repository/' + namespace + '/' + name + '/build');
|
||||
$location.search('current', buildInfo.id);
|
||||
};
|
||||
|
||||
$scope.loadTriggerBuildHistory = function(trigger) {
|
||||
trigger.$loadingHistory = true;
|
||||
|
||||
var params = {
|
||||
'repository': namespace + '/' + name,
|
||||
'trigger_uuid': trigger.id,
|
||||
'limit': 3
|
||||
};
|
||||
|
||||
ApiService.listTriggerRecentBuilds(null, params).then(function(resp) {
|
||||
trigger.$builds = resp['builds'];
|
||||
trigger.$loadingHistory = false;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.loadTriggers = function() {
|
||||
var params = {
|
||||
'repository': namespace + '/' + name
|
||||
};
|
||||
|
||||
$scope.triggersResource = ApiService.listBuildTriggersAsResource(params).get(function(resp) {
|
||||
$scope.triggers = resp.triggers;
|
||||
|
||||
// Check to see if we need to setup any trigger.
|
||||
var newTriggerId = $routeParams.new_trigger;
|
||||
if (newTriggerId) {
|
||||
for (var i = 0; i < $scope.triggers.length; ++i) {
|
||||
var trigger = $scope.triggers[i];
|
||||
if (trigger['id'] == newTriggerId && !trigger['is_active']) {
|
||||
$scope.setupTrigger(trigger);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $scope.triggers;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.setupTrigger = function(trigger) {
|
||||
$scope.triggerSetupReady = false;
|
||||
$scope.currentSetupTrigger = trigger;
|
||||
$('#setupTriggerModal').modal({});
|
||||
$('#setupTriggerModal').on('hidden.bs.modal', function () {
|
||||
$scope.$apply(function() {
|
||||
$scope.cancelSetupTrigger();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.finishSetupTrigger = function(trigger) {
|
||||
$('#setupTriggerModal').modal('hide');
|
||||
$scope.currentSetupTrigger = null;
|
||||
|
||||
var params = {
|
||||
'repository': namespace + '/' + name,
|
||||
'trigger_uuid': trigger.id
|
||||
};
|
||||
|
||||
ApiService.activateBuildTrigger(trigger['config'], params).then(function(resp) {
|
||||
trigger['is_active'] = true;
|
||||
}, function(resp) {
|
||||
$scope.triggers.splice($scope.triggers.indexOf(trigger), 1);
|
||||
bootbox.dialog({
|
||||
"message": resp['data']['message'] || 'The build trigger setup could not be completed',
|
||||
"title": "Could not activate build trigger",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cancelSetupTrigger = function() {
|
||||
if (!$scope.currentSetupTrigger) { return; }
|
||||
|
||||
$('#setupTriggerModal').modal('hide');
|
||||
$scope.deleteTrigger($scope.currentSetupTrigger);
|
||||
$scope.currentSetupTrigger = null;
|
||||
};
|
||||
|
||||
$scope.startTrigger = function(trigger) {
|
||||
var params = {
|
||||
'repository': namespace + '/' + name,
|
||||
'trigger_uuid': trigger.id
|
||||
};
|
||||
|
||||
ApiService.manuallyStartBuildTrigger(null, params).then(function(resp) {
|
||||
window.console.log(resp);
|
||||
var url = '/repository/' + namespace + '/' + name + '/build?current=' + resp['id'];
|
||||
document.location = url;
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp['message'] || 'The build could not be started',
|
||||
"title": "Could not start build",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deleteTrigger = function(trigger) {
|
||||
var params = {
|
||||
'repository': namespace + '/' + name,
|
||||
'trigger_uuid': trigger.id
|
||||
};
|
||||
|
||||
ApiService.deleteBuildTrigger(null, params).then(function(resp) {
|
||||
$scope.triggers.splice($scope.triggers.indexOf(trigger), 1);
|
||||
});
|
||||
};
|
||||
|
||||
var fetchTokens = function() {
|
||||
var params = {
|
||||
'repository': namespace + '/' + name
|
||||
|
@ -1421,7 +1585,6 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
|
|||
}
|
||||
|
||||
UserService.updateUserIn($scope, function(user) {
|
||||
$scope.askForPassword = user.askForPassword;
|
||||
$scope.cuser = jQuery.extend({}, user);
|
||||
|
||||
for (var i = 0; i < $scope.cuser.logins.length; i++) {
|
||||
|
@ -1447,12 +1610,42 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
|
|||
$scope.org = {};
|
||||
$scope.githubRedirectUri = KeyService.githubRedirectUri;
|
||||
$scope.githubClientId = KeyService.githubClientId;
|
||||
$scope.authorizedApps = null;
|
||||
|
||||
$('.form-change').popover();
|
||||
|
||||
$scope.logsShown = 0;
|
||||
$scope.invoicesShown = 0;
|
||||
|
||||
$scope.loadAuthedApps = function() {
|
||||
if ($scope.authorizedApps) { return; }
|
||||
|
||||
ApiService.listUserAuthorizations().then(function(resp) {
|
||||
$scope.authorizedApps = resp['authorizations'];
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deleteAccess = function(accessTokenInfo) {
|
||||
var params = {
|
||||
'access_token_uuid': accessTokenInfo['uuid']
|
||||
};
|
||||
|
||||
ApiService.deleteUserAuthorization(null, params).then(function(resp) {
|
||||
$scope.authorizedApps.splice($scope.authorizedApps.indexOf(accessTokenInfo), 1);
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.message || 'Could not revoke authorization',
|
||||
"title": "Cannot revoke authorization",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.loadLogs = function() {
|
||||
if (!$scope.hasPaidBusinessPlan) { return; }
|
||||
$scope.logsShown++;
|
||||
|
@ -1518,7 +1711,8 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
|
|||
$scope.sentEmail = $scope.cuser.email;
|
||||
|
||||
// Reset the form.
|
||||
$scope.cuser.repeatEmail = '';
|
||||
delete $scope.cuser['repeatEmail'];
|
||||
|
||||
$scope.changeEmailForm.$setPristine();
|
||||
}, function(result) {
|
||||
$scope.updatingUser = false;
|
||||
|
@ -1540,8 +1734,9 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
|
|||
$scope.changePasswordSuccess = true;
|
||||
|
||||
// Reset the form
|
||||
$scope.cuser.password = '';
|
||||
$scope.cuser.repeatPassword = '';
|
||||
delete $scope.cuser['password']
|
||||
delete $scope.cuser['repeatPassword']
|
||||
|
||||
$scope.changePasswordForm.$setPristine();
|
||||
|
||||
// Reload the user.
|
||||
|
@ -1614,6 +1809,16 @@ function ImageViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService, I
|
|||
}, 10);
|
||||
};
|
||||
|
||||
var fetchRepository = function() {
|
||||
var params = {
|
||||
'repository': namespace + '/' + name
|
||||
};
|
||||
|
||||
ApiService.getRepoAsResource(params).get(function(repo) {
|
||||
$scope.repo = repo;
|
||||
});
|
||||
};
|
||||
|
||||
var fetchImage = function() {
|
||||
var params = {
|
||||
'repository': namespace + '/' + name,
|
||||
|
@ -1621,10 +1826,13 @@ function ImageViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService, I
|
|||
};
|
||||
|
||||
$scope.image = ApiService.getImageAsResource(params).get(function(image) {
|
||||
$scope.repo = {
|
||||
'name': name,
|
||||
'namespace': namespace
|
||||
};
|
||||
if (!$scope.repo) {
|
||||
$scope.repo = {
|
||||
'name': name,
|
||||
'namespace': namespace,
|
||||
'is_public': true
|
||||
};
|
||||
}
|
||||
|
||||
$rootScope.title = 'View Image - ' + image.id;
|
||||
$rootScope.description = 'Viewing docker image ' + image.id + ' under repository ' + namespace + '/' + name +
|
||||
|
@ -1665,6 +1873,9 @@ function ImageViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService, I
|
|||
});
|
||||
};
|
||||
|
||||
// Fetch the repository.
|
||||
fetchRepository();
|
||||
|
||||
// Fetch the image.
|
||||
fetchImage();
|
||||
}
|
||||
|
@ -1673,13 +1884,16 @@ function V1Ctrl($scope, $location, UserService) {
|
|||
UserService.updateUserIn($scope);
|
||||
}
|
||||
|
||||
function NewRepoCtrl($scope, $location, $http, $timeout, UserService, ApiService, PlanService) {
|
||||
function NewRepoCtrl($scope, $location, $http, $timeout, UserService, ApiService, PlanService, KeyService) {
|
||||
UserService.updateUserIn($scope);
|
||||
|
||||
$scope.githubRedirectUri = KeyService.githubRedirectUri;
|
||||
$scope.githubClientId = KeyService.githubClientId;
|
||||
|
||||
$scope.repo = {
|
||||
'is_public': 1,
|
||||
'description': '',
|
||||
'initialize': false
|
||||
'initialize': ''
|
||||
};
|
||||
|
||||
// Watch the namespace on the repo. If it changes, we update the plan and the public/private
|
||||
|
@ -1691,37 +1905,14 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, ApiService
|
|||
|
||||
var isUserNamespace = (namespace == $scope.user.username);
|
||||
|
||||
$scope.checkingPlan = true;
|
||||
$scope.planRequired = null;
|
||||
$scope.isUserNamespace = isUserNamespace;
|
||||
|
||||
if (isUserNamespace) {
|
||||
// Load the user's subscription information in case they want to create a private
|
||||
// repository.
|
||||
ApiService.getUserPrivateCount().then(function(resp) {
|
||||
if (resp.privateCount + 1 > resp.reposAllowed) {
|
||||
PlanService.getMinimumPlan(resp.privateCount + 1, false, function(minimum) {
|
||||
$scope.planRequired = minimum;
|
||||
});
|
||||
}
|
||||
// Determine whether private repositories are allowed for the namespace.
|
||||
checkPrivateAllowed();
|
||||
|
||||
$scope.checkingPlan = false;
|
||||
}, function() {
|
||||
$scope.planRequired = {};
|
||||
$scope.checkingPlan = false;
|
||||
});
|
||||
} else {
|
||||
ApiService.getOrganizationPrivateAllowed(null, {'orgname': namespace}).then(function(resp) {
|
||||
$scope.planRequired = resp.privateAllowed ? null : {};
|
||||
$scope.checkingPlan = false;
|
||||
}, function() {
|
||||
$scope.planRequired = {};
|
||||
$scope.checkingPlan = false;
|
||||
});
|
||||
|
||||
// Auto-set to private repo.
|
||||
$scope.repo.is_public = '0';
|
||||
}
|
||||
// Default to private repos for organizations.
|
||||
$scope.repo.is_public = isUserNamespace ? '1' : '0';
|
||||
});
|
||||
|
||||
$scope.changeNamespace = function(namespace) {
|
||||
|
@ -1771,12 +1962,20 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, ApiService
|
|||
$scope.creating = false;
|
||||
$scope.created = created;
|
||||
|
||||
// Repository created. Start the upload process if applicable.
|
||||
if ($scope.repo.initialize) {
|
||||
// Start the upload process if applicable.
|
||||
if ($scope.repo.initialize == 'dockerfile' || $scope.repo.initialize == 'zipfile') {
|
||||
$scope.createdForBuild = created;
|
||||
return;
|
||||
}
|
||||
|
||||
// Conduct the Github redirect if applicable.
|
||||
if ($scope.repo.initialize == 'github') {
|
||||
window.location = 'https://github.com/login/oauth/authorize?client_id=' + $scope.githubClientId +
|
||||
'&scope=repo,user:email&redirect_uri=' + $scope.githubRedirectUri + '/trigger/' +
|
||||
repo.namespace + '/' + repo.name;
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, redirect to the repo page.
|
||||
$location.path('/repository/' + created.namespace + '/' + created.name);
|
||||
}, function(result) {
|
||||
|
@ -1800,7 +1999,35 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, ApiService
|
|||
}
|
||||
};
|
||||
|
||||
PlanService.changePlan($scope, null, $scope.planRequired.stripeId, callbacks);
|
||||
var namespace = $scope.isUserNamespace ? null : $scope.repo.namespace;
|
||||
PlanService.changePlan($scope, namespace, $scope.planRequired.stripeId, callbacks);
|
||||
};
|
||||
|
||||
var checkPrivateAllowed = function() {
|
||||
if (!$scope.repo || !$scope.repo.namespace) { return; }
|
||||
|
||||
$scope.checkingPlan = true;
|
||||
|
||||
var isUserNamespace = $scope.isUserNamespace;
|
||||
ApiService.getPrivateAllowed(isUserNamespace ? null : $scope.repo.namespace).then(function(resp) {
|
||||
$scope.checkingPlan = false;
|
||||
|
||||
if (resp['privateAllowed']) {
|
||||
$scope.planRequired = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (resp['privateCount'] == null) {
|
||||
// Organization where we are not the admin.
|
||||
$scope.planRequired = {};
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, lookup the matching plan.
|
||||
PlanService.getMinimumPlan(resp['privateCount'] + 1, !isUserNamespace, function(minimum) {
|
||||
$scope.planRequired = minimum;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var subscribedToPlan = function(sub) {
|
||||
|
@ -1810,16 +2037,7 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, ApiService
|
|||
PlanService.getPlan(sub.plan, function(subscribedPlan) {
|
||||
$scope.subscribedPlan = subscribedPlan;
|
||||
$scope.planRequired = null;
|
||||
|
||||
// Check to see if the current plan allows for an additional private repository to
|
||||
// be created.
|
||||
var privateAllowed = $scope.subscription.usedPrivateRepos < $scope.subscribedPlan.privateRepos;
|
||||
if (!privateAllowed) {
|
||||
// If not, find the minimum repository that does.
|
||||
PlanService.getMinimumPlan($scope.subscription.usedPrivateRepos + 1, !$scope.isUserNamespace, function(minimum) {
|
||||
$scope.planRequired = minimum;
|
||||
});
|
||||
}
|
||||
checkPrivateAllowed();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -1933,12 +2151,17 @@ function OrgAdminCtrl($rootScope, $scope, $timeout, Restangular, $routeParams, U
|
|||
$scope.invoiceLoading = true;
|
||||
$scope.logsShown = 0;
|
||||
$scope.invoicesShown = 0;
|
||||
$scope.applicationsShown = 0;
|
||||
$scope.changingOrganization = false;
|
||||
|
||||
$scope.loadLogs = function() {
|
||||
$scope.logsShown++;
|
||||
};
|
||||
|
||||
$scope.loadApplications = function() {
|
||||
$scope.applicationsShown++;
|
||||
};
|
||||
|
||||
$scope.loadInvoices = function() {
|
||||
$scope.invoicesShown++;
|
||||
};
|
||||
|
@ -2223,4 +2446,132 @@ function OrgMemberLogsCtrl($scope, $routeParams, $rootScope, $timeout, Restangul
|
|||
// Load the org info and the member info.
|
||||
loadOrganization();
|
||||
loadMemberInfo();
|
||||
}
|
||||
|
||||
|
||||
function ManageApplicationCtrl($scope, $routeParams, $rootScope, $location, $timeout, ApiService) {
|
||||
var orgname = $routeParams.orgname;
|
||||
var clientId = $routeParams.clientid;
|
||||
|
||||
$scope.updating = false;
|
||||
|
||||
$scope.askResetClientSecret = function() {
|
||||
$('#resetSecretModal').modal({});
|
||||
};
|
||||
|
||||
$scope.askDelete = function() {
|
||||
$('#deleteAppModal').modal({});
|
||||
};
|
||||
|
||||
$scope.deleteApplication = function() {
|
||||
var params = {
|
||||
'orgname': orgname,
|
||||
'client_id': clientId
|
||||
};
|
||||
|
||||
$('#deleteAppModal').modal('hide');
|
||||
|
||||
ApiService.deleteOrganizationApplication(null, params).then(function(resp) {
|
||||
$timeout(function() {
|
||||
$location.path('/organization/' + orgname + '/admin');
|
||||
}, 500);
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.message || 'Could not delete application',
|
||||
"title": "Cannot delete application",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.updateApplication = function() {
|
||||
$scope.updating = true;
|
||||
var params = {
|
||||
'orgname': orgname,
|
||||
'client_id': clientId
|
||||
};
|
||||
|
||||
if (!$scope.application['description']) {
|
||||
delete $scope.application['description'];
|
||||
}
|
||||
|
||||
if (!$scope.application['gravatar_email']) {
|
||||
delete $scope.application['gravatar_email'];
|
||||
}
|
||||
|
||||
ApiService.updateOrganizationApplication($scope.application, params).then(function(resp) {
|
||||
$scope.application = resp;
|
||||
$scope.updating = false;
|
||||
}, function(resp) {
|
||||
$scope.updating = false;
|
||||
bootbox.dialog({
|
||||
"message": resp.message || 'Could not update application',
|
||||
"title": "Cannot update application",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.resetClientSecret = function() {
|
||||
var params = {
|
||||
'orgname': orgname,
|
||||
'client_id': clientId
|
||||
};
|
||||
|
||||
$('#resetSecretModal').modal('hide');
|
||||
|
||||
ApiService.resetOrganizationApplicationClientSecret(null, params).then(function(resp) {
|
||||
$scope.application = resp;
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.message || 'Could not reset client secret',
|
||||
"title": "Cannot reset client secret",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var loadOrganization = function() {
|
||||
$scope.orgResource = ApiService.getOrganizationAsResource({'orgname': orgname}).get(function(org) {
|
||||
$scope.organization = org;
|
||||
return org;
|
||||
});
|
||||
};
|
||||
|
||||
var loadApplicationInfo = function() {
|
||||
var params = {
|
||||
'orgname': orgname,
|
||||
'client_id': clientId
|
||||
};
|
||||
|
||||
$scope.appResource = ApiService.getOrganizationApplicationAsResource(params).get(function(resp) {
|
||||
$scope.application = resp;
|
||||
|
||||
$rootScope.title = 'Manage Application ' + $scope.application.name + ' (' + $scope.orgname + ')';
|
||||
$rootScope.description = 'Manage the details of application ' + $scope.application.name +
|
||||
' under organization ' + $scope.orgname;
|
||||
|
||||
return resp;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Load the organization and application info.
|
||||
loadOrganization();
|
||||
loadApplicationInfo();
|
||||
}
|
Reference in a new issue