-
Notifications
You must be signed in to change notification settings - Fork 69
/
permissionSetAssignment.ts
145 lines (126 loc) · 4.67 KB
/
permissionSetAssignment.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
* Copyright (c) 2020, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import { EOL } from 'node:os';
import { mapKeys, upperFirst } from '@salesforce/kit';
import type { Optional } from '@salesforce/ts-types';
import type { QueryResult, Record } from '@jsforce/jsforce-node';
import { Logger } from '../logger/logger';
import { Messages } from '../messages';
import { SfError } from '../sfError';
import { Org } from './org';
Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages('@salesforce/core', 'permissionSetAssignment');
/**
* Map of fields name for a permission set assignment
*/
export type PermissionSetAssignmentFields = {
assigneeId: string;
permissionSetId: string;
};
/**
* A class for assigning a Salesforce User to one or more permission sets.
*/
export class PermissionSetAssignment {
private logger: Logger;
private org: Org;
private constructor(org: Org, logger: Logger) {
this.logger = logger;
this.org = org;
}
/**
* Creates a new instance of PermissionSetAssignment.
*
* @param org The target org for the assignment.
*/
public static async init(org: Org): Promise<PermissionSetAssignment> {
if (!org) {
throw messages.createError('orgRequired');
}
return new PermissionSetAssignment(org, await Logger.child('PermissionSetAssignment'));
}
/**
* Assigns a user to one or more permission sets.
*
* @param id A user id
* @param permSetString An array of permission set names.
*/
public async create(id: string, permSetString: string): Promise<PermissionSetAssignmentFields> {
if (!id) {
throw messages.createError('userIdRequired');
}
if (!permSetString) {
throw messages.createError('permSetRequired');
}
const { nsPrefix, permSetName } = this.parsePermissionSetString(permSetString);
let query = `SELECT Id FROM PermissionSet WHERE Name='${permSetName}'`;
if (nsPrefix) {
query += ` AND NamespacePrefix='${nsPrefix}'`;
}
const result: QueryResult<Record> = await this.org.getConnection().query<Record>(query);
const permissionSetId = result?.records[0]?.Id;
if (!permissionSetId) {
if (nsPrefix) {
throw messages.createError('assignCommandPermissionSetNotFoundForNSError', [permSetName, nsPrefix]);
} else {
throw messages.createError('assignCommandPermissionSetNotFoundError', [permSetName]);
}
}
const assignment: PermissionSetAssignmentFields = {
assigneeId: id,
permissionSetId,
};
const createResponse = await this.org
.getConnection()
.sobject('PermissionSetAssignment')
.create(mapKeys(assignment, (value: unknown, key: string) => upperFirst(key)));
if (createResponse.success === false) {
if (!createResponse.errors?.length) {
throw messages.createError('notSuccessfulButNoErrorsReported');
}
const message = [messages.getMessage('errorsEncounteredCreatingAssignment')]
.concat(
(createResponse.errors ?? []).map((error) => {
// note: the types for jsforce SaveError don't have "string[]" error,
// but there was a UT for that at https://github.com/forcedotcom/sfdx-core/blob/7412d103703cfe2df2211546fcf2e6d93a689bc0/test/unit/org/permissionSetAssignmentTest.ts#L146
// which could either be hallucination or a real response we've seen, so I'm preserving that behavior.
if (typeof error === 'string') return error;
return error.fields ? `${error.message} on fields ${error.fields.join(',')}` : error.message;
})
)
.join(EOL);
throw new SfError(message, 'errorsEncounteredCreatingAssignment');
} else {
return assignment;
}
}
/**
* Parses a permission set name based on if it has a namespace or not.
*
* @param permSetString The permission set string.
*/
private parsePermissionSetString(permSetString: string): {
nsPrefix: Optional<string>;
permSetName: Optional<string>;
} {
const nsPrefixMatch = RegExp(/(\w+(?=__))(__)(.*)/).exec(permSetString);
let nsPrefix: Optional<string>;
let permSetName: Optional<string>;
if (nsPrefixMatch) {
try {
nsPrefix = nsPrefixMatch[1];
permSetName = nsPrefixMatch[3];
this.logger.debug(`Using namespacePrefix ${nsPrefix} for permission set ${permSetName}`);
} catch (e) {
// Don't fail if we parse wrong.
this.logger.debug(e);
}
} else {
permSetName = permSetString;
}
return { nsPrefix, permSetName };
}
}