diff --git a/package.json b/package.json index b28fa45e..ff8c7297 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "dependencies": { "@oclif/config": "^1.17.0", "@salesforce/command": "^3.0.4", - "@salesforce/core": "^2.14.2", + "@salesforce/core": "^2.15.2", "tslib": "^1" }, "devDependencies": { diff --git a/src/commands/force/user/create.ts b/src/commands/force/user/create.ts index 2096a1cc..48c6593e 100644 --- a/src/commands/force/user/create.ts +++ b/src/commands/force/user/create.ts @@ -18,7 +18,7 @@ import { User, UserFields, } from '@salesforce/core'; -import { get, Dictionary } from '@salesforce/ts-types'; +import { get, Dictionary, isArray } from '@salesforce/ts-types'; import { flags, FlagsConfig, SfdxCommand } from '@salesforce/command'; Messages.importMessagesDirectory(__dirname); @@ -54,36 +54,48 @@ export class UserCreateCommand extends SfdxCommand { public org: Org; private user: User; - private successes: SuccessMsg[]; - private failures: FailureMsg[]; + private successes: SuccessMsg[] = []; + private failures: FailureMsg[] = []; public async run(): Promise { this.logger = await Logger.child(this.constructor.name); const defaultUserFields: DefaultUserFields = await DefaultUserFields.create({ templateUser: this.org.getUsername(), }); - const user: User = await User.create({ org: this.org }); + this.user = await User.create({ org: this.org }); // merge defaults with provided values with cli > file > defaults const fields: UserFields & Dictionary = await this.aggregateFields(defaultUserFields.getFields()); + // because fields is type UserFields & Dictionary we can access these + const permsets = fields['permsets']; + const generatepassword: string = fields['generatepassword']; + + // extract the fields and then delete, createUser doesn't expect a permsets or generatepassword + delete fields['permsets']; + delete fields['generatepassword']; + delete fields['generatePassword']; try { - await user.createUser(fields); + await this.user.createUser(fields); } catch (e) { await this.catchCreateUser(e, fields); } - // because fields is type UserFields & Dictionary we can access these - const permsets: string = fields['permsets']; - const generatepassword: string = fields['generatepassword']; - // Assign permission sets to the created user if (permsets) { try { - await this.user.assignPermissionSets(fields.id, permsets.trim().split(',')); + // permsets can be passed from cli args or file we need to create an array of permset names either way it's passed + let permsetArray: string[]; + if (!isArray(permsets)) { + permsetArray = [permsets]; + } else { + permsetArray = permsets as string[]; + } + + await this.user.assignPermissionSets(fields.id, permsetArray); this.successes.push({ name: 'Permission Set Assignment', - value: permsets.trim(), + value: permsetArray.join(','), }); } catch (err) { this.failures.push({ @@ -94,7 +106,7 @@ export class UserCreateCommand extends SfdxCommand { } // Generate and set a password if specified - if (generatepassword === 'true') { + if (generatepassword === 'true' || generatepassword) { try { const password = User.generatePasswordUtf8(); await this.user.assignPassword(await AuthInfo.create({ username: fields.username }), password); @@ -158,6 +170,22 @@ export class UserCreateCommand extends SfdxCommand { }); } + // check if "profileName" was passed, this needs to become a profileId before calling User.create + if (defaultFields['profileName']) { + const name: string = defaultFields['profileName'] || 'Standard User'; + this.logger.debug(`Querying org for profile name [${name}]`); + const profileQuery = `SELECT id FROM profile WHERE name='${name}'`; + const response = await this.org.getConnection().query(profileQuery); + defaultFields.profileId = get(response, 'records[0].Id') as string; + delete defaultFields['profileName']; + } + + // the file schema is camelCase while the cli arg is no capitialization + if (defaultFields['generatePassword'] || defaultFields['generatepassword']) { + // standardize on 'generatepassword' + defaultFields['generatepassword'] = 'true'; + } + return defaultFields; } @@ -170,7 +198,9 @@ export class UserCreateCommand extends SfdxCommand { fields.username, ]); - if (this.failures) { + // we initialize to be an empty array to be able to push onto it + // so we need to check that the size is greater than 0 to know we had a failure + if (this.failures.length > 0) { this.ux.styledHeader('Partial Success'); this.ux.log(userCreatedSuccessMsg); this.ux.log(''); diff --git a/test/commands/user/create.test.ts b/test/commands/user/create.test.ts index bddb70e3..c0071a18 100644 --- a/test/commands/user/create.test.ts +++ b/test/commands/user/create.test.ts @@ -103,7 +103,6 @@ describe('force:user:create', () => { alias: 'testAlias', email: 'me@my.org', emailEncodingKey: 'UTF-8', - generatepassword: 'false', id: '0052D0000043PawWWR', languageLocaleKey: 'en_US', lastName: 'User', diff --git a/test/commands/user/password/generate.test.ts b/test/commands/user/password/generate.test.ts index bf483c89..ca0dc373 100644 --- a/test/commands/user/password/generate.test.ts +++ b/test/commands/user/password/generate.test.ts @@ -84,7 +84,7 @@ describe('force:user:password:generate', () => { .stdout() .command(['force:user:password:generate', '--json']) - .it('should throw the correct errror with warning message', (ctx) => { + .it('should throw the correct error with warning message', (ctx) => { const result = JSON.parse(ctx.stdout); expect(result.message).to.equal(messages.getMessage('noSelfSetError')); expect(result.status).to.equal(1); diff --git a/yarn.lock b/yarn.lock index 7c9f680f..f9ba1979 100644 --- a/yarn.lock +++ b/yarn.lock @@ -527,7 +527,7 @@ chalk "^2.4.2" cli-ux "^4.9.3" -"@salesforce/core@^2.14.2", "@salesforce/core@^2.6.0": +"@salesforce/core@^2.15.2", "@salesforce/core@^2.6.0": version "2.15.2" resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-2.15.2.tgz#7e2b0ac6c1d67f850a461e007298d1381b37c07a" integrity sha512-PCP9HdGEl4us8X66tOfwlTOGFRju8m7ezqfBlH7nRzmKw57i2l0LhXBEZ+DPwEBtAwa9wlvd9FhMmlhUYhm/EQ==