cockpit/pkg/kubernetes/scripts/projects.js

1412 lines
62 KiB
JavaScript

/*
* This file is part of Cockpit.
*
* Copyright (C) 2015 Red Hat, Inc.
*
* Cockpit is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* Cockpit is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
*/
(function() {
var angular = require('angular');
require('angular-route');
require('angular-dialog.js');
require('./kube-client');
require('./listing');
require('./policy');
require('../views/projects-page.html');
require('../views/project-page.html');
require('../views/user-page.html');
require('../views/group-page.html');
require('../views/project-panel.html');
require('../views/project-body.html');
require('../views/user-body.html');
require('../views/group-panel.html');
require('../views/user-panel.html');
require('../views/project-listing.html');
require('../views/project-modify.html');
require('../views/project-modify.html');
require('../views/project-delete.html');
require('../views/add-group-dialog.html');
require('../views/user-group-add.html');
require('../views/user-group-remove.html');
require('../views/group-delete.html');
require('../views/add-user-dialog.html');
require('../views/user-modify.html');
require('../views/user-add-membership.html');
require('../views/user-remove-membership.html');
require('../views/user-delete.html');
require('../views/add-member-role-dialog.html');
require('../views/remove-role-dialog.html');
require('../views/add-role-dialog.html');
function toName(object) {
if (object && typeof object == "object")
return object.metadata.name;
else
return object;
}
angular.module('registry.projects', [
'ngRoute',
'ui.cockpit',
'kubeClient',
'kubernetes.listing',
'registry.policy',
])
.config(['$routeProvider',
function($routeProvider) {
$routeProvider
.when('/projects/:namespace?', {
controller: 'ProjectsCtrl',
templateUrl: function(params) {
if (!params['namespace'])
return 'views/projects-page.html';
else
return 'views/project-page.html';
}
})
.when('/users/:user', {
controller: 'UserCtrl',
templateUrl: function(params) {
return 'views/user-page.html';
}
})
.when('/groups/:group', {
controller: 'GroupCtrl',
templateUrl: function(params) {
return 'views/group-page.html';
}
});
}
])
.controller('ProjectsCtrl', [
'$scope',
'$routeParams',
'$location',
'kubeSelect',
'kubeLoader',
'projectData',
'projectActions',
'ListingState',
'roleActions',
'projectPolicy',
function($scope, $routeParams, $location, select, loader, projectData, projectAction, ListingState, roleAction, projectPolicy) {
loader.watch("users", $scope);
loader.watch("groups", $scope);
projectPolicy.watch($scope);
var namespace = $routeParams["namespace"] || "";
$scope.projName = namespace;
if (namespace) {
$scope.listing = new ListingState($scope);
$scope.project = function() {
return select().kind("Project")
.name(namespace)
.one();
};
} else {
$scope.listing = new ListingState($scope);
$scope.projects = function() {
return select().kind("Project");
};
}
$scope.$on("activate", function(ev, id) {
ev.preventDefault();
$location.path(id);
});
angular.extend($scope, projectData);
angular.extend($scope, roleAction);
angular.extend($scope, projectAction);
$scope.users = function() {
return select().kind("User");
};
$scope.groups = function() {
return select().kind("Group");
};
}
])
.controller('UserCtrl', [
'$scope',
'$routeParams',
'$location',
'kubeSelect',
'kubeLoader',
'projectData',
'projectActions',
'roleActions',
'ListingState',
'projectPolicy',
function($scope, $routeParams, $location, select, loader, projectData, projectAction, roleActions, ListingState, projectPolicy) {
loader.watch("users", $scope);
loader.watch("groups", $scope);
projectPolicy.watch($scope);
var user = $routeParams["user"] || "";
$scope.userName = user;
if (user) {
$scope.user = function() {
return select().kind("User")
.name(user)
.one();
};
$scope.listing = new ListingState($scope);
$scope.$on("activate", function(ev, id) {
ev.preventDefault();
$location.path(id);
});
} else {
$scope.listing = new ListingState($scope);
$location.path("/projects");
}
$scope.projects = function() {
return select().kind("Project");
};
$scope.groups = function() {
return select().kind("Group");
};
$scope.users = function() {
return select().kind("User");
};
angular.extend($scope, projectData);
angular.extend($scope, projectAction);
angular.extend($scope, roleActions);
}
])
.controller('GroupCtrl', [
'$scope',
'$routeParams',
'$location',
'kubeSelect',
'kubeLoader',
'projectData',
'projectActions',
'roleActions',
'ListingState',
'projectPolicy',
function($scope, $routeParams, $location, select, loader, projectData, projectAction, roleActions, ListingState, projectPolicy) {
loader.watch("users", $scope);
loader.watch("groups", $scope);
projectPolicy.watch($scope);
var group = $routeParams["group"] || "";
$scope.groupName = group;
if (group) {
$scope.group = function() {
return select().kind("Group")
.name(group)
.one();
};
$scope.listing = new ListingState($scope);
$scope.$on("activate", function(ev, id) {
ev.preventDefault();
$location.path(id);
});
} else {
$scope.listing = new ListingState($scope);
$location.path("/projects");
}
$scope.projects = function() {
return select().kind("Project");
};
$scope.groups = function() {
return select().kind("Group");
};
$scope.users = function() {
return select().kind("User");
};
angular.extend($scope, projectData);
angular.extend($scope, projectAction);
angular.extend($scope, roleActions);
}
])
.factory("projectData", [
'$q',
'kubeSelect',
'kubeLoader',
'projectPolicy',
function($q, select, loader, policy) {
var registryRoles = [{ ocRole: "registry-admin", displayRole :"Admin" },
{ ocRole:"registry-editor", displayRole :"Push" },
{ ocRole:"registry-viewer", displayRole :"Pull" }];
function getRegistryRolesMap() {
return registryRoles;
}
function getDisplayRole(ocRole) {
var i;
var displayRole;
for (i = registryRoles.length - 1; i >= 0; i--) {
if (registryRoles[i].ocRole === ocRole) {
displayRole = registryRoles[i].displayRole;
break;
}
}
return displayRole;
}
function getOcRolesList() {
var ocRoles = [];
angular.forEach(registryRoles, function(r) {
ocRoles.push(r.ocRole);
});
return ocRoles;
}
function getAllRoles(member, project) {
if (!member && !project)
return [];
var projectName = toName(project);
var roleBinds = subjectRoleBindings(member, projectName);
var meta;
var ret = [];
angular.forEach(roleBinds, function(roleBind) {
meta = roleBind.metadata || { };
if (meta.name)
ret.push(meta.name);
});
return ret;
}
function getRegistryRoles(member, project) {
if (!member && !project)
return [];
var projectName = toName(project);
var roleBinds = subjectRoleBindings(member, projectName);
var ocRegistryRoles = getOcRolesList();
var roles = [];
var meta;
angular.forEach(roleBinds, function(roleBind) {
meta = roleBind.metadata || { };
if (meta.name && ocRegistryRoles.indexOf(meta.name) !== -1) {
if (roles.indexOf(getDisplayRole(meta.name) === -1))
roles.push(getDisplayRole(meta.name));
}
});
return roles;
}
function isRegistryRole(member, displayRole, project) {
var oc_roles = getRegistryRoles(member, project);
if (oc_roles.indexOf(displayRole) !== -1) {
return true;
}
return false;
}
function hasRegistryRole(member, project) {
var oc_roles = getRegistryRoles(member, project);
if (oc_roles.length === 0) {
return false;
}
return true;
}
function isRoles(member, namespace) {
var oc_roles = getAllRoles(member, namespace);
if (oc_roles.length === 0) {
return false;
}
return true;
}
function getProjectsWithMember(projects, member) {
if (!projects && !member)
return [];
var projList = [];
if (member) {
angular.forEach(projects, function(project) {
if (project && subjectIsMember(member, project.metadata.name))
projList.push(project);
});
}
return projList;
}
function getGroupsWithMember(groups, member) {
if (!groups && !member)
return [];
var grpList = [];
if (member) {
angular.forEach(groups, function(group) {
if (group && group.users && group.users.indexOf(member) != -1)
grpList.push(group);
});
}
return grpList;
}
function getMembershipOfUser(projects, groups, user) {
var members = [];
var userProjects = getProjectsWithMember(projects, user);
angular.forEach(userProjects, function(project) {
members.push(project.metadata.name);
});
var userGroups = getGroupsWithMember(groups, user);
angular.forEach(userGroups, function(group) {
members.push(group.metadata.name);
});
return members;
}
/*
* To use this you would have a user or group, and do:
*
* rolebindings = select().kind("RoleBindings").containsSubject(user_name);
* rolebindings = select().kind("RoleBindings").containsSubject(user_object);
* rolebindings = select().kind("RoleBindings").containsSubject(group_object);
*/
select.register({
name: "containsSubject",
digests: function(arg) {
var meta, i, len, subjects;
var ret = [];
if (typeof arg == "string") {
ret.push(arg);
} else if (arg.kind == "User" || arg.kind == "Group") {
meta = arg.metadata || { };
ret.push(meta.name + ":" + arg.kind);
} else if (arg.kind == "RoleBinding") {
subjects = arg.subjects || [];
for (i = 0, len = subjects.length; i < len; i++) {
ret.push(subjects[i].name);
ret.push(subjects[i].name + ":" + subjects[i].kind);
}
}
return ret;
}
});
function subjectRoleBindings(subject, namespace) {
return select().kind("RoleBinding")
.namespace(namespace)
.containsSubject(subject);
}
function subjectIsMember(subject, namespace) {
if (!subject || !namespace)
return null;
namespace = toName(namespace);
return !!subjectRoleBindings(subject, namespace).one();
}
function formatMembers(members, kind) {
var mlist = "";
var i;
if (!members || members.length === 0)
return mlist;
if (members.length <= 3) {
for (i = members.length - 1; i >= 0; i--) {
if (i > 0)
mlist += ",";
mlist += members[i];
}
} else {
if (kind === "Groups") {
mlist = members.length + " " + kind;
} else if (kind === "Users") {
mlist = members.length + " " + kind;
}
}
return mlist;
}
var sharedVerb = "get";
var sharedResource = "imagestreams/layers";
var sharedRole = "registry-viewer";
var sharedKind = "Group";
var anonymousGroup = "system:unauthenticated";
var sharedGroup = "system:authenticated";
var registryAdmin = "registry-admin";
function shareImages(project, accessPolicy) {
var anonSubject = {
kind: sharedKind,
name: anonymousGroup,
};
var sharedSubject = {
kind: sharedKind,
name: sharedGroup,
};
if (accessPolicy === "anonymous") {
return policy.addToRole(project, sharedRole, anonSubject)
.then(function() {
return policy.addToRole(project, sharedRole, sharedSubject);
});
} else if (accessPolicy === "shared") {
return policy.removeFromRole(project, sharedRole, anonSubject)
.then(function() {
return policy.addToRole(project, sharedRole, sharedSubject);
});
} else {
return policy.removeFromRole(project, sharedRole, anonSubject)
.then(function() {
return policy.removeFromRole(project, sharedRole, sharedSubject);
});
}
}
function sharedImages(project) {
if (!project)
return null;
var response = policy.whoCan(project, sharedVerb, sharedResource);
if (!response)
return null;
var projState = {};
projState[anonymousGroup] = null;
projState[sharedGroup] = null;
var i, len;
var groups = response.groups || [];
for (i = 0, len = groups.length; i < len; i++) {
if (projState.hasOwnProperty(groups[i]))
projState[groups[i]] = true;
}
if (projState[anonymousGroup])
return "anonymous";
else if (projState[sharedGroup])
return "shared";
return "private";
}
function makeRegistryAdmin(project, currentUser) {
var subject = {
kind: 'User',
name: toName(currentUser),
};
// if system:admin then return
if (currentUser && currentUser.groups &&
currentUser.groups.indexOf("system:cluster-admins") !== -1) {
return $q.when({ });
}
var oc_roles = getRegistryRoles(currentUser, project);
if (oc_roles.indexOf(registryAdmin) !== -1) {
// for templates with registryAdmin
// if registryAdmin role exists then return
return $q.when({ });
}
return policy.addToRole(project, registryAdmin, subject);
}
function isSameUser(currUser, userName) {
return currUser ? toName(currUser) === toName(userName) : false;
}
return {
subjectRoleBindings: subjectRoleBindings,
subjectIsMember: subjectIsMember,
formatMembers: formatMembers,
shareImages: shareImages,
sharedImages: sharedImages,
getAllRoles: getAllRoles,
isRegistryRole: isRegistryRole,
isRoles: isRoles,
getRegistryRolesMap: getRegistryRolesMap,
getRegistryRoles: getRegistryRoles,
getGroupsWithMember: getGroupsWithMember,
getProjectsWithMember: getProjectsWithMember,
getMembershipOfUser: getMembershipOfUser,
isSameUser: isSameUser,
makeRegistryAdmin: makeRegistryAdmin,
hasRegistryRole: hasRegistryRole,
};
}
])
.directive('projectPanel', [
'kubeLoader',
'kubeSelect',
'projectData',
'roleActions',
function(loader, select, projectData, roleActions) {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attrs) {
var tab = 'main';
scope.tab = function(name, ev) {
if (ev) {
tab = name;
ev.stopPropagation();
}
return tab === name;
};
var currProject = scope.id;
angular.extend(scope, projectData);
angular.extend(scope, roleActions);
loader.load("Project", null, currProject);
scope.project = function() {
return select().kind("Project")
.name(currProject)
.one();
};
},
templateUrl: "views/project-panel.html"
};
}
])
.directive('projectBody', [
'projectData',
function(data) {
return {
restrict: 'A',
templateUrl: 'views/project-body.html',
link: function(scope, element, attrs) {
scope.sharedImages = data.sharedImages;
},
};
}
])
.directive('userBody', [
function() {
return {
restrict: 'A',
templateUrl: 'views/user-body.html',
link: function(scope, element, attrs) {
},
};
}
])
.directive('groupPanel', [
'kubeLoader',
'kubeSelect',
'projectData',
function(loader, select, projectData) {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attrs) {
var tab = 'main';
scope.tab = function(name, ev) {
if (ev) {
tab = name;
ev.stopPropagation();
}
return tab === name;
};
var currGroup = scope.id;
loader.load("Groups");
scope.group = function() {
return select().kind("Group")
.name(currGroup)
.one();
};
scope.projects = function() {
return select().kind("Project");
};
angular.extend(scope, projectData);
},
templateUrl: "views/group-panel.html"
};
}
])
.directive('userPanel', [
'kubeLoader',
'kubeSelect',
'projectData',
'projectActions',
function(loader, select, projectData, projectAction) {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attrs) {
var tab = 'main';
scope.tab = function(name, ev) {
if (ev) {
tab = name;
ev.stopPropagation();
}
return tab === name;
};
var currUser = scope.id;
loader.load("Users");
angular.extend(scope, projectData);
angular.extend(scope, projectAction);
scope.user = function() {
return select().kind("User")
.name(currUser)
.one();
};
scope.groups = function() {
return select().kind("Group");
};
scope.projects = function() {
return select().kind("Project");
};
},
templateUrl: "views/user-panel.html"
};
}
])
.directive('projectListing',
function() {
return {
restrict: 'A',
templateUrl: 'views/project-listing.html'
};
}
)
.factory('projectActions', [
'$modal',
'projectData',
function($modal, projectData) {
function createProject(currentUser) {
return $modal.open({
controller: 'ProjectModifyCtrl',
templateUrl: 'views/project-modify.html',
resolve: {
dialogData: function() {
return { currUser: currentUser };
}
},
}).result;
}
function modifyProject(project) {
return $modal.open({
animation: false,
controller: 'ProjectModifyCtrl',
templateUrl: 'views/project-modify.html',
resolve: {
dialogData: function() {
return { project: project };
}
},
}).result;
}
function removeProject(project) {
return $modal.open({
animation: false,
controller: 'ProjectModifyCtrl',
templateUrl: 'views/project-delete.html',
resolve: {
dialogData: function() {
return { project: project };
}
},
}).result;
}
function createGroup() {
return $modal.open({
controller: 'GroupNewCtrl',
templateUrl: 'views/add-group-dialog.html',
});
}
function addUserToGroup(groupObj) {
return $modal.open({
controller: 'GroupChangeCtrl',
templateUrl: 'views/user-group-add.html',
resolve:{
fields: function() {
return { group: groupObj };
}
}
});
}
function removeUserFromGroup(user, groupObj) {
return $modal.open({
controller: 'GroupChangeCtrl',
templateUrl: 'views/user-group-remove.html',
resolve:{
fields: function() {
return { group: groupObj, user: user };
}
}
});
}
function removeGroup(projects, groupObj) {
return $modal.open({
controller: 'GroupChangeCtrl',
templateUrl: 'views/group-delete.html',
resolve:{
fields: function() {
var members = projectData.getProjectsWithMember(projects, groupObj.metadata.name);
return { group: groupObj, projects: projects, members: members };
}
}
});
}
function createUser() {
return $modal.open({
controller: 'UserNewCtrl',
templateUrl: 'views/add-user-dialog.html',
});
}
function modifyUser(userObj) {
return $modal.open({
animation: false,
controller: 'UserChangeCtrl',
templateUrl: 'views/user-modify.html',
resolve: {
fields: function() {
return { user: userObj };
}
},
}).result;
}
function addMemberToParent(memberObj) {
return $modal.open({
controller: 'UserChangeCtrl',
templateUrl: 'views/user-add-membership.html',
resolve:{
fields: function() {
return { memberObj: memberObj };
}
}
});
}
function removeMemberFromParent(memberObj, parentObj) {
return $modal.open({
controller: 'UserChangeCtrl',
templateUrl: 'views/user-remove-membership.html',
resolve:{
fields: function() {
return { parentObj: parentObj, memberObj: memberObj };
}
}
});
}
function removeUser(projects, groups, userObj) {
return $modal.open({
controller: 'UserChangeCtrl',
templateUrl: 'views/user-delete.html',
resolve:{
fields: function() {
var members = projectData.getMembershipOfUser(projects, groups, userObj.metadata.name);
return { user: userObj, projects: projects, groups: groups,
members: members };
}
}
});
}
return {
createProject: createProject,
modifyProject: modifyProject,
createGroup: createGroup,
createUser: createUser,
removeProject: removeProject,
removeUser: removeUser,
modifyUser: modifyUser,
addMemberToParent: addMemberToParent,
removeMemberFromParent: removeMemberFromParent,
removeGroup: removeGroup,
addUserToGroup: addUserToGroup,
removeUserFromGroup: removeUserFromGroup,
};
}
])
.factory('roleActions', [
'$modal',
function($modal) {
function addMember(project) {
return $modal.open({
controller: 'MemberNewCtrl',
templateUrl: 'views/add-member-role-dialog.html',
resolve: {
fields: function() {
return { namespace: toName(project) };
}
},
});
}
function changeRole(member, roleMp, roles, project) {
return $modal.open({
controller: 'ChangeRoleCtrl',
templateUrl: function() {
if (roles.indexOf(roleMp.displayRole) >= 0) {
return 'views/remove-role-dialog.html';
} else {
return 'views/add-role-dialog.html';
}
},
resolve: {
fields: function() {
return { member: member, ocRole: roleMp.ocRole,
displayRole: roleMp.displayRole, roles: roles,
namespace: toName(project) };
}
},
});
}
return {
addMember: addMember,
changeRole: changeRole,
};
}
])
.controller('ChangeRoleCtrl', [
'$q',
'$scope',
'projectPolicy',
'kubeLoader',
'kubeSelect',
'fields',
function($q, $scope, projectPolicy, loader, kselect, fields) {
$scope.fields = fields;
var namespace = $scope.fields.namespace;
$scope.performCreate = function performCreate() {
var role = $scope.fields.ocRole;
var memberObj = $scope.fields.member;
var subject = {
kind: memberObj.kind,
name: memberObj.metadata.name,
};
return projectPolicy.addToRole(namespace, role, subject);
};
$scope.performRemove = function performRemove() {
var role = $scope.fields.ocRole;
var memberObj = $scope.fields.member;
var subject = {
kind: memberObj.kind,
name: memberObj.metadata.name,
};
return projectPolicy.removeFromRole(namespace, role, subject);
};
}
])
.controller('MemberNewCtrl', [
'$q',
'$scope',
'projectData',
'projectPolicy',
'kubeLoader',
'kubeSelect',
'fields',
'gettextCatalog',
function($q, $scope, projectData, projectPolicy, loader, kselect, fields, gettextCatalog) {
const _ = gettextCatalog.getString.bind(gettextCatalog);
var selectMember = _("Select Member");
var NAME_RE = /^[a-z0-9_.]([-a-z0-9@._:]*[a-z0-9._:])?$/;
var selectRole = _("Select Role");
loader.watch("User", $scope);
loader.watch("Group", $scope);
$scope.selected = {
member: selectMember,
getMembers: getAllMembers,
displayRole: selectRole,
roles: projectData.getRegistryRolesMap(),
kind: "",
ocRole: "",
};
$scope.itemTracker = function(item) {
return item.kind + "/" + item.metadata.name;
};
var namespace = fields.namespace;
/*
* This function is called during Angular rendering. Make sure we
* use the same array over and over again, so angular doesn't
* try to digest again.
*/
function getAllMembers() {
var users = kselect().kind("User");
var groups = kselect().kind("Group");
var members = [];
angular.forEach(users, function(user) {
members.push(user);
});
angular.forEach(groups, function(group) {
members.push(group);
});
return members;
}
function validate(memberName, role) {
var defer = $q.defer();
var ex;
if (memberName !== undefined) {
if (!memberName)
ex = new Error("The member name cannot be empty.");
else if (memberName === selectMember)
ex = new Error("Please select a valid Member.");
else if (!NAME_RE.test(memberName))
ex = new Error("The member name contains invalid characters. Only letters, numbers, spaces and the following symbols are allowed: , = @ . _");
if (ex) {
ex.target = "#add_member_group";
defer.reject(ex);
}
}
if (!role || role === selectRole) {
ex = new Error("Please select a valid Role.");
ex.target = "#add_role";
defer.reject(ex);
}
if (!ex) {
defer.resolve();
}
return defer.promise;
}
$scope.performCreate = function performCreate() {
var role = $scope.selected.ocRole;
var memberName = $scope.selected.memberName;
var member = $scope.selected.member;
var memberObj, kind;
if (memberName && memberName === member) {
// dropdown value selected
memberObj = $scope.selected.memberObj;
memberName = memberObj.metadata.name;
kind = memberObj.kind;
} else if (memberName && member === selectMember) {
// input field has value
kind = "User";
} else if (!memberName && member === selectMember) {
// nothing selected
memberName = selectMember;
kind = null;
}
return validate(memberName, role).then(function() {
var subject = {
kind: kind,
name: memberName,
};
return projectPolicy.addToRole(namespace, role, subject);
});
};
}
])
.controller('ProjectModifyCtrl', [
'$q',
'$scope',
'kubeSelect',
"dialogData",
"projectData",
'$location',
'$timeout',
"kubeMethods",
"gettextCatalog",
function($q, $scope, kselect, dialogData, projectData, $location, $timeout, methods, gettextCatalog) {
var project = dialogData.project || { };
var meta = project.metadata || { };
var annotations = meta.annotations || { };
const _ = gettextCatalog.getString.bind(gettextCatalog);
var DISPLAY = "openshift.io/display-name";
var DESCRIPTION = "openshift.io/description";
var fields = {
name: meta.name || "",
display: annotations[DISPLAY] || "",
description: annotations[DESCRIPTION] || "",
access: null,
};
/*
* This data may not be available yet, so continue to ask until it is.
* The called function takes care of not making duplicate requests.
*/
var timr;
function updateShared() {
timr = null;
if (fields.access === null)
fields.access = projectData.sharedImages(meta.name);
if (fields.access === null)
timr = $timeout(updateShared, 500);
}
updateShared();
$scope.$on("$destroy", function() {
if (timr !== null)
$timeout.cancel(timr);
});
angular.extend($scope, projectData);
$scope.fields = fields;
$scope.labels = {
access: {
"private": _("Private: Allow only specific users or groups to pull images"),
"shared": _("Shared: Allow any authenticated user to pull images"),
"anonymous" : _("Anonymous: Allow all unauthenticated users to pull images"),
}
};
$scope.performDelete = function performDelete(project) {
var promise = methods.delete(project)
.then(function() {
$location.path("/projects");
}, function(ex) {
return $q.reject(ex);
});
return promise;
};
$scope.performCreate = function performCreate() {
var name = fields.name.trim();
var request = {
kind: "ProjectRequest",
apiVersion:"v1",
metadata:{ name: name, },
displayName: fields.display.trim(),
description: fields.description.trim()
};
return methods.check(request, { "metadata.name": "#project-new-name" })
.then(function() {
return methods.create(request);
})
.then(function() {
return projectData.shareImages(name, fields.access);
})
.then(function() {
return projectData.makeRegistryAdmin(name, dialogData.currUser);
});
};
$scope.performModify = function performModify() {
var anno = { };
var data = { metadata: { annotations: anno } };
var value = fields.display.trim();
if (value !== annotations[DISPLAY])
anno[DISPLAY] = value;
value = fields.description.trim();
if (value !== annotations[DESCRIPTION])
anno[DESCRIPTION] = value;
return methods.check(data, { })
.then(function() {
return $q.all([
methods.patch(project, data),
projectData.shareImages(project, fields.access)
]);
});
};
angular.extend($scope, dialogData);
}
])
.controller('UserNewCtrl', [
'$q',
'$scope',
"kubeMethods",
function($q, $scope, methods) {
var fields = {
name: "",
identities: ""
};
$scope.fields = fields;
$scope.performCreate = function performCreate() {
var identities = [];
if (fields.identities.trim() !== "")
identities = [fields.identities.trim()];
var user = {
"kind": "User",
"apiVersion": "v1",
"metadata": {
"name": fields.name.trim()
},
"identities": identities
};
return methods.check(user, { "metadata.name": "#user_name" })
.then(function() {
return methods.create(user);
});
};
}
])
.factory('memberActions', [
"kubeMethods",
function(methods) {
function removeUserFromGroup(user, group) {
var userName = toName(user);
var users = group.users || [];
var index = users.indexOf(userName);
if (index >= 0)
users.splice(index, 1);
var patchData = { "users": users };
return methods.patch(group, patchData);
}
function addUserToGroup(user, group) {
var userName = toName(user);
var users = group.users || [];
var index = users.indexOf(userName);
if (index == -1)
users.push(userName);
var patchData = { "users": users };
return methods.patch(group, patchData);
}
return {
removeUserFromGroup: removeUserFromGroup,
addUserToGroup: addUserToGroup,
};
}
])
.controller('UserChangeCtrl', [
'$q',
'$scope',
'kubeSelect',
'kubeLoader',
"kubeMethods",
'projectData',
'projectPolicy',
'$location',
'memberActions',
"fields",
"gettextCatalog",
function($q, $scope, kselect, loader, methods, projectData, projectPolicy, $location, memberActions, fields, gettextCatalog) {
const _ = gettextCatalog.getString.bind(gettextCatalog);
loader.watch("Group", $scope);
loader.watch("Project", $scope);
function getMembers() {
var members = [];
var groups = getGroups();
var projects = getProjects();
angular.forEach(groups, function(group) {
members.push(group);
});
angular.forEach(projects, function(project) {
members.push(project);
});
return members;
}
function getProjects() {
return kselect().kind("Project");
}
function getGroups() {
return kselect().kind("Group");
}
$scope.itemTracker = function(item) {
return item.kind + "/" + item.metadata.name;
};
$scope.selected = {
member: _("Select Member"),
getMembers: getMembers,
roles: projectData.getRegistryRolesMap,
role: _("Select Role"),
};
angular.extend($scope, projectData);
$scope.fields = fields;
if (fields.user && fields.user.identities)
$scope.fields.identities = fields.user.identities.toString();
else
$scope.fields.identities = '';
$scope.performModify = function performModify() {
var identities = [];
var user = $scope.fields.user;
var data = { "identities": identities };
if (fields.identities.trim() !== "") {
var idList = fields.identities.trim().split(",");
identities.push.apply(identities, idList);
}
return methods.check(data, { })
.then(function() {
return $q.all([
methods.patch(user, data),
]);
});
};
$scope.performDelete = function performDelete(user) {
var chain = $q.when();
chain = removeMemberFromParents(user);
var promise = chain.then(function() {
$location.path("/projects");
}, function(ex) {
if (ex.code === 404) {
loader.handle(user, true, "User");
$location.path("/projects");
} else {
return $q.reject(ex);
}
});
return promise;
};
function removeMemberFromParents(member) {
var chain = $q.when();
var groups = projectData.getGroupsWithMember(getGroups(), member.metadata.name);
angular.forEach(groups, function(g) {
chain = chain.then(function() {
return memberActions.removeUserFromGroup(member, g);
});
});
var projects = projectData.getProjectsWithMember(getProjects(), member.metadata.name);
angular.forEach(projects, function(project) {
var subjectRoleBindings = projectData.subjectRoleBindings(member.metadata.name, project.metadata.name);
var subject = {
kind: member.kind,
name: member.metadata.name,
};
chain = chain.then(function() {
return projectPolicy.removeMemberFromProject(
project.metadata.name, subjectRoleBindings, subject);
});
});
chain = chain.then(function() {
return methods.delete(member);
});
return chain;
}
$scope.addMemberToParent = function addMemberToParent() {
if ($scope.selected.parentObj.kind === "Project") {
var project = $scope.selected.parentObj.metadata.name;
var memberObj = $scope.fields.memberObj;
var role = $scope.selected.ocRole;
var subject = {
kind: memberObj.kind,
name: memberObj.metadata.name,
};
return projectPolicy.addToRole(project, role, subject);
} else if ($scope.selected.parentObj.kind === "Group") {
return memberActions.addUserToGroup($scope.fields.memberObj, $scope.selected.parentObj);
}
};
$scope.removeMemberFromParent = function removeMemberFromParent() {
if ($scope.fields.parentObj.kind === "Group") {
return memberActions.removeUserFromGroup($scope.fields.memberObj, $scope.fields.parentObj);
} else {
// Project
var member = $scope.fields.memberObj;
var project = $scope.fields.parentObj.metadata.name;
var subjectRoleBindings = projectData.subjectRoleBindings(member.metadata.name, project);
var subject = {
kind: member.kind,
name: member.metadata.name,
};
return projectPolicy.removeMemberFromProject(project, subjectRoleBindings, subject);
}
};
}
])
.controller('GroupChangeCtrl', [
'$q',
'$scope',
'kubeLoader',
'kubeSelect',
"kubeMethods",
'projectData',
'memberActions',
'projectPolicy',
'$location',
"fields",
'gettextCatalog',
function($q, $scope, loader, kselect, methods, projectData, memberActions, projectPolicy, $location, fields, gettextCatalog) {
const _ = gettextCatalog.getString.bind(gettextCatalog);
loader.watch("User", $scope);
loader.watch("Project", $scope);
function getUsers() {
return kselect().kind("User");
}
function getProjects() {
return kselect().kind("Project");
}
$scope.select = {
member: _("Select Member"),
getMembers: getUsers,
};
angular.extend($scope, projectData);
$scope.fields = fields;
$scope.fields.grpProjects = projectData.getProjectsWithMember(getProjects(), fields.group.metadata.name);
function removeMemberFromParents(member) {
var chain = $q.when();
var projects = projectData.getProjectsWithMember(getProjects(), member.metadata.name);
angular.forEach(projects, function(project) {
var subjectRoleBindings = projectData.subjectRoleBindings(member.metadata.name, project.metadata.name);
var subject = {
kind: member.kind,
name: member.metadata.name,
};
chain = chain.then(function() {
return projectPolicy.removeMemberFromProject(
project.metadata.name, subjectRoleBindings, subject);
});
});
chain = chain.then(function() {
return methods.delete(member);
});
return chain;
}
$scope.performDelete = function performDelete(group) {
var chain = $q.when();
chain = removeMemberFromParents(group);
var promise = chain.then(function() {
$location.path("/projects");
}, function(ex) {
if (ex.code === 404) {
$location.path("/projects");
} else {
return $q.reject(ex);
}
});
return promise;
};
$scope.addUserToGroup = function addUserToGroup() {
return memberActions.addUserToGroup($scope.select.member, $scope.fields.group);
};
$scope.removeUserFromGroup = function removeUserFromGroup() {
return memberActions.removeUserFromGroup($scope.fields.user, $scope.fields.group);
};
}
])
.controller('GroupNewCtrl', [
'$q',
'$scope',
"kubeMethods",
function($q, $scope, methods) {
var fields = {
name: ""
};
$scope.fields = fields;
$scope.performCreate = function performCreate() {
var group = {
"kind": "Group",
"apiVersion": "v1",
"metadata": {
"name": fields.name.trim()
}
};
return methods.check(group, { "metadata.name": "#group_name" })
.then(function() {
return methods.create(group);
});
};
}
]);
}());