UNPKG

appcenter-cli

Version:

Command line tool for Visual Studio App Center

339 lines (338 loc) 19.4 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const commandline_1 = require("../../../util/commandline"); const interaction_1 = require("../../../util/interaction"); const util_1 = require("util"); const _ = require("lodash"); const Os = require("os"); const list_of_users_helper_1 = require("../../../util/misc/list-of-users-helper"); const org_users_helper_1 = require("../lib/org-users-helper"); const debug = require("debug")("appcenter-cli:commands:orgs:collaborators:update"); const pLimit = require("p-limit"); let OrgCollaboratorsUpdateCommand = class OrgCollaboratorsUpdateCommand extends commandline_1.Command { run(client) { return __awaiter(this, void 0, void 0, function* () { // validate that string and file properties are not specified simultaneously this.validateParameters(); // loading user lists and lists of org users and org invitations const collaboratorsToAddPromise = list_of_users_helper_1.getUsersList(this.collaboratorsToAdd, this.collaboratorsToAddFile, debug); const collaboratorsToDeletePromise = list_of_users_helper_1.getUsersList(this.collaboratorsToDelete, this.collaboratorsToDeleteFile, debug); const collaboratorsToMakeAdminsPromise = list_of_users_helper_1.getUsersList(this.collaboratorsToMakeAdmins, this.collaboratorsToMakeAdminsFile, debug); const adminsToMakeCollaboratorsPromise = list_of_users_helper_1.getUsersList(this.adminsToMakeCollaborators, this.adminsToMakeCollaboratorsFile, debug); const usersInvitedToOrgPromise = this.getUsersInvitedToOrg(client); const usersJoinedOrgPromise = org_users_helper_1.getOrgUsers(client, this.name, debug); // showing spinner while prerequisites are being loaded const [collaboratorsToAdd, collaboratorsToDelete, collaboratorsToMakeAdmins, adminsToMakeCollaborators, usersInvitedToOrg, usersJoinedOrg,] = yield interaction_1.out.progress("Loading prerequisites...", Promise.all([ collaboratorsToAddPromise, collaboratorsToDeletePromise, collaboratorsToMakeAdminsPromise, adminsToMakeCollaboratorsPromise, usersInvitedToOrgPromise, usersJoinedOrgPromise, ])); let addedCollaborators; let deletedCollaborators; if (collaboratorsToAdd.length || collaboratorsToDelete.length) { const joinedUserEmailsToUserObject = this.toUserEmailMap(usersJoinedOrg); const userJoinedOrgEmails = Array.from(joinedUserEmailsToUserObject.keys()); addedCollaborators = yield interaction_1.out.progress("Adding collaborators...", this.addCollaborators(client, collaboratorsToAdd, usersInvitedToOrg, userJoinedOrgEmails)); // updating list of invited users addedCollaborators.forEach((collaborator) => { if (usersInvitedToOrg.indexOf(collaborator) === -1) { usersInvitedToOrg.push(collaborator); } }); deletedCollaborators = yield interaction_1.out.progress("Deleting collaborators...", this.deleteCollaborators(client, collaboratorsToDelete, usersInvitedToOrg, joinedUserEmailsToUserObject)); } else { addedCollaborators = []; deletedCollaborators = []; } let toAdmins; let toCollaborators; if (collaboratorsToMakeAdmins.length || adminsToMakeCollaborators.length) { // just deleted org users should be excluded from role changing const joinedUserEmailsToUserObject = this.toUserEmailMap(usersJoinedOrg.filter((user) => deletedCollaborators.indexOf(user.email) === -1)); toAdmins = yield interaction_1.out.progress("Changing role to admins...", this.changeUsersRole(client, collaboratorsToMakeAdmins, joinedUserEmailsToUserObject, "admin")); // updating roles after setting admins Array.from(joinedUserEmailsToUserObject.values()) .filter((user) => collaboratorsToMakeAdmins.indexOf(user.email) > -1) .forEach((user) => (user.role = "admin")); toCollaborators = yield interaction_1.out.progress("Changing role to collaborator...", this.changeUsersRole(client, adminsToMakeCollaborators, joinedUserEmailsToUserObject, "collaborator")); } else { toAdmins = []; toCollaborators = []; } interaction_1.out.text((result) => { const stringArray = []; if (result.addedCollaborators.length) { stringArray.push(`Successfully added ${result.addedCollaborators.length} collaborators to organization`); } if (result.deletedCollaborators.length) { stringArray.push(`Successfully deleted ${result.deletedCollaborators.length} collaborators from organization`); } if (result.toAdmins.length) { stringArray.push(`Successfully changed roles for ${result.toAdmins.length} collaborators to "admin"`); } if (result.toCollaborators.length) { stringArray.push(`Successfully changed roles for ${result.toCollaborators.length} admins to "collaborator"`); } return stringArray.join(Os.EOL); }, { addedCollaborators, deletedCollaborators, toAdmins, toCollaborators }); return commandline_1.success(); }); } validateParameters() { if (!(this.collaboratorsToAdd || this.collaboratorsToAddFile || this.collaboratorsToDelete || this.collaboratorsToDeleteFile || this.collaboratorsToMakeAdmins || this.collaboratorsToMakeAdminsFile || this.adminsToMakeCollaborators || this.adminsToMakeCollaboratorsFile)) { throw commandline_1.failure(commandline_1.ErrorCodes.InvalidParameter, "nothing to update"); } if (this.collaboratorsToAdd && this.collaboratorsToAddFile) { throw commandline_1.failure(commandline_1.ErrorCodes.InvalidParameter, "parameters '--add-collaborators' and '--add-collaborators-file' are mutually exclusive"); } if (this.collaboratorsToDelete && this.collaboratorsToDeleteFile) { throw commandline_1.failure(commandline_1.ErrorCodes.InvalidParameter, "parameters '--delete-collaborators' and '--delete-collaborators-file' are mutually exclusive"); } if (this.collaboratorsToMakeAdmins && this.collaboratorsToMakeAdminsFile) { throw commandline_1.failure(commandline_1.ErrorCodes.InvalidParameter, "parameters '--make-admins' and '--make-admins-file' are mutually exclusive"); } if (this.adminsToMakeCollaborators && this.adminsToMakeCollaboratorsFile) { throw commandline_1.failure(commandline_1.ErrorCodes.InvalidParameter, "parameters '--make-collaborators' and '--make-collaborators-file' are mutually exclusive"); } } getUsersInvitedToOrg(client) { var _a; return __awaiter(this, void 0, void 0, function* () { try { const result = yield client.orgInvitations.listPending(this.name); return result.map((invitation) => invitation.email); } catch (error) { if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) { throw commandline_1.failure(commandline_1.ErrorCodes.InvalidParameter, `organization ${this.name} doesn't exist`); } else { debug(`Failed to get list of user invitations for organization ${this.name} - ${util_1.inspect(error)}`); throw commandline_1.failure(commandline_1.ErrorCodes.Exception, `failed to get list of user invitations for organization ${this.name}`); } } }); } getLimiter() { return pLimit(10); } addCollaborators(client, collaborators, usersInvitedToOrg, usersJoinedOrg) { return __awaiter(this, void 0, void 0, function* () { const limiter = this.getLimiter(); const filteredCollaborators = _.difference(collaborators, usersJoinedOrg); // no need to add users already joined org yield Promise.all(filteredCollaborators.map((collaborator) => limiter(() => usersInvitedToOrg.some((invited) => invited === collaborator) ? this.resendInvitationToUser(client, collaborator) : this.sendInvitationToUser(client, collaborator)))); return filteredCollaborators; }); } sendInvitationToUser(client, collaborator) { var _a; return __awaiter(this, void 0, void 0, function* () { try { yield client.orgInvitations.create(this.name, collaborator); } catch (error) { if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) { throw commandline_1.failure(commandline_1.ErrorCodes.InvalidParameter, `organization ${this.name} doesn't exist`); } else { debug(`Failed to send invitation for ${collaborator} to organization ${this.name} - ${util_1.inspect(error)}`); throw commandline_1.failure(commandline_1.ErrorCodes.Exception, `failed to send invitation for ${collaborator} to organization ${this.name}`); } } }); } resendInvitationToUser(client, collaborator) { var _a; return __awaiter(this, void 0, void 0, function* () { try { yield client.orgInvitations.sendNewInvitation(this.name, collaborator); } catch (error) { if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) { throw commandline_1.failure(commandline_1.ErrorCodes.InvalidParameter, `organization ${this.name} doesn't exist`); } else { debug(`Failed to re-send invitation for ${collaborator} to organization ${this.name} - ${util_1.inspect(error)}`); throw commandline_1.failure(commandline_1.ErrorCodes.Exception, `failed to re-send invitation for ${collaborator} to organization ${this.name}`); } } }); } deleteCollaborators(client, collaborators, usersInvitedToOrg, joinedUserEmailsToUserObject) { return __awaiter(this, void 0, void 0, function* () { const limiter = this.getLimiter(); const userActions = []; const collaboratorsForDeletion = []; for (const collaborator of collaborators) { if (joinedUserEmailsToUserObject.has(collaborator)) { // user has already joined the org, deleting them userActions.push(limiter(() => this.deleteUserFromOrganization(client, joinedUserEmailsToUserObject.get(collaborator).name))); collaboratorsForDeletion.push(collaborator); } else if (usersInvitedToOrg.indexOf(collaborator) > -1) { // user was invited to the org, cancel invite userActions.push(limiter(() => this.cancelUserInvitation(client, collaborator))); collaboratorsForDeletion.push(collaborator); } // otherwise nothing to do } yield Promise.all(userActions); return collaboratorsForDeletion; }); } cancelUserInvitation(client, collaborator) { var _a; return __awaiter(this, void 0, void 0, function* () { try { yield client.orgInvitations.delete(this.name, collaborator); } catch (error) { if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) { throw commandline_1.failure(commandline_1.ErrorCodes.InvalidParameter, `organization ${this.name} doesn't exist`); } else { debug(`Failed to cancel invitation for ${collaborator} to organization ${this.name} - ${util_1.inspect(error)}`); throw commandline_1.failure(commandline_1.ErrorCodes.Exception, `failed to cancel invitation for ${collaborator} to organization ${this.name}`); } } }); } deleteUserFromOrganization(client, collaboratorName) { var _a; return __awaiter(this, void 0, void 0, function* () { try { yield client.users.removeFromOrg(this.name, collaboratorName); } catch (error) { if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) { throw commandline_1.failure(commandline_1.ErrorCodes.InvalidParameter, `organization ${this.name} doesn't exist`); } else { debug(`Failed to delete user ${collaboratorName} from organization ${this.name} - ${util_1.inspect(error)}`); throw commandline_1.failure(commandline_1.ErrorCodes.Exception, `failed to delete user ${collaboratorName} from organization ${this.name}`); } } }); } changeUsersRole(client, collaborators, userJoinedOrgToRole, role) { return __awaiter(this, void 0, void 0, function* () { const limiter = this.getLimiter(); // no need to change role for non-collaborators and collaborators with target role const filteredCollaboratorsNames = collaborators .filter((collaborator) => userJoinedOrgToRole.has(collaborator) && userJoinedOrgToRole.get(collaborator).role !== role) .map((collaborator) => userJoinedOrgToRole.get(collaborator).name); yield Promise.all(filteredCollaboratorsNames.map((collaboratorName) => limiter(() => this.changeUserRole(client, collaboratorName, role)))); return filteredCollaboratorsNames; }); } changeUserRole(client, collaboratorName, role) { var _a; return __awaiter(this, void 0, void 0, function* () { try { yield client.users.updateOrgRole(this.name, collaboratorName, { role, }); } catch (error) { if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) { throw commandline_1.failure(commandline_1.ErrorCodes.InvalidParameter, `organization ${this.name} doesn't exist`); } else { debug(`Failed to change role of ${collaboratorName} to ${role} - ${util_1.inspect(error)}`); throw commandline_1.failure(commandline_1.ErrorCodes.Exception, `failed to change role of ${collaboratorName} to ${role}`); } } }); } toUserEmailMap(users) { return new Map(users.map((user) => [user.email, user])); } }; __decorate([ commandline_1.help("Name of the organization"), commandline_1.shortName("n"), commandline_1.longName("name"), commandline_1.required, commandline_1.hasArg ], OrgCollaboratorsUpdateCommand.prototype, "name", void 0); __decorate([ commandline_1.help("List of collaborators to add"), commandline_1.shortName("c"), commandline_1.longName("add-collaborators"), commandline_1.hasArg ], OrgCollaboratorsUpdateCommand.prototype, "collaboratorsToAdd", void 0); __decorate([ commandline_1.help("Path to the list of collaborators to add"), commandline_1.shortName("C"), commandline_1.longName("add-collaborators-file"), commandline_1.hasArg ], OrgCollaboratorsUpdateCommand.prototype, "collaboratorsToAddFile", void 0); __decorate([ commandline_1.help("List of collaborators to delete"), commandline_1.shortName("d"), commandline_1.longName("delete-collaborators"), commandline_1.hasArg ], OrgCollaboratorsUpdateCommand.prototype, "collaboratorsToDelete", void 0); __decorate([ commandline_1.help("Path to the list of collaborators to delete"), commandline_1.shortName("D"), commandline_1.longName("delete-collaborators-file"), commandline_1.hasArg ], OrgCollaboratorsUpdateCommand.prototype, "collaboratorsToDeleteFile", void 0); __decorate([ commandline_1.help("List of collaborators to make admins"), commandline_1.shortName("a"), commandline_1.longName("make-admins"), commandline_1.hasArg ], OrgCollaboratorsUpdateCommand.prototype, "collaboratorsToMakeAdmins", void 0); __decorate([ commandline_1.help("Path to the list of collaborators to make admins"), commandline_1.shortName("A"), commandline_1.longName("make-admins-file"), commandline_1.hasArg ], OrgCollaboratorsUpdateCommand.prototype, "collaboratorsToMakeAdminsFile", void 0); __decorate([ commandline_1.help("List of admins to make collaborators"), commandline_1.shortName("m"), commandline_1.longName("make-collaborators"), commandline_1.hasArg ], OrgCollaboratorsUpdateCommand.prototype, "adminsToMakeCollaborators", void 0); __decorate([ commandline_1.help("Path to the list of admins to make collaborators"), commandline_1.shortName("M"), commandline_1.longName("make-collaborators-file"), commandline_1.hasArg ], OrgCollaboratorsUpdateCommand.prototype, "adminsToMakeCollaboratorsFile", void 0); OrgCollaboratorsUpdateCommand = __decorate([ commandline_1.help("Update list of organization collaborators") ], OrgCollaboratorsUpdateCommand); exports.default = OrgCollaboratorsUpdateCommand;