quickbase-js 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -1107
- package/dist/auth/ticket.d.ts.map +1 -1
- package/dist/auth/ticket.js +4 -3
- package/dist/auth/ticket.js.map +1 -1
- package/dist/client/request.d.ts +4 -0
- package/dist/client/request.d.ts.map +1 -1
- package/dist/client/request.js +15 -3
- package/dist/client/request.js.map +1 -1
- package/dist/generated/client.d.ts +2 -0
- package/dist/generated/client.d.ts.map +1 -1
- package/dist/generated/client.js +134 -113
- package/dist/generated/client.js.map +1 -1
- package/dist/generated/types.d.ts +2700 -2256
- package/dist/generated/types.d.ts.map +1 -1
- package/dist/generated/types.js +0 -2
- package/dist/generated/types.js.map +1 -1
- package/dist/quickbase.esm.js +3 -3
- package/dist/quickbase.esm.js.map +3 -3
- package/dist/quickbase.min.js +3 -3
- package/dist/quickbase.min.js.map +3 -3
- package/package.json +16 -13
- package/src/auth/index.ts +55 -0
- package/src/auth/sso-token.ts +143 -0
- package/src/auth/temp-token.ts +160 -0
- package/src/auth/ticket.ts +329 -0
- package/src/auth/token-cache.ts +97 -0
- package/src/auth/types.ts +50 -0
- package/src/auth/user-token.ts +38 -0
- package/src/cli/schema.ts +512 -0
- package/src/client/index.ts +36 -0
- package/src/client/pagination.ts +337 -0
- package/src/client/request.ts +544 -0
- package/src/client/retry.ts +169 -0
- package/src/client/throttle.ts +105 -0
- package/src/core/config.ts +160 -0
- package/src/core/dates.ts +63 -0
- package/src/core/errors.ts +349 -0
- package/src/core/index.ts +50 -0
- package/src/core/logger.ts +113 -0
- package/src/core/schema.ts +213 -0
- package/src/core/transform.ts +295 -0
- package/src/core/types.ts +337 -0
- package/src/generated/client.ts +1785 -0
- package/src/generated/operations.json +672 -0
- package/src/generated/types.ts +4884 -0
- package/src/index.ts +259 -0
- package/src/xml/codepages.ts +119 -0
- package/src/xml/dbvars.ts +75 -0
- package/src/xml/errors.ts +133 -0
- package/src/xml/fields.ts +121 -0
- package/src/xml/groups.ts +560 -0
- package/src/xml/html.ts +152 -0
- package/src/xml/index.ts +1196 -0
- package/src/xml/metadata.ts +111 -0
- package/src/xml/records.ts +301 -0
- package/src/xml/request.ts +238 -0
- package/src/xml/roles.ts +321 -0
- package/src/xml/schema.ts +436 -0
- package/src/xml/transform.ts +381 -0
- package/src/xml/types.ts +602 -0
- package/src/xml/users.ts +221 -0
- package/src/xml/webhooks.ts +260 -0
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XML API Group Management
|
|
3
|
+
*
|
|
4
|
+
* Endpoints for managing groups and group memberships.
|
|
5
|
+
*
|
|
6
|
+
* XML-API: Remove this file when QuickBase discontinues the XML API.
|
|
7
|
+
* To find all XML API code, search for: XML-API
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
XmlCaller,
|
|
12
|
+
Group,
|
|
13
|
+
GroupUser,
|
|
14
|
+
GroupManager,
|
|
15
|
+
Subgroup,
|
|
16
|
+
CreateGroupResult,
|
|
17
|
+
GetUsersInGroupResult,
|
|
18
|
+
GetGroupRoleResult,
|
|
19
|
+
GrantedGroupsResult,
|
|
20
|
+
GrantedDBsForGroupResult,
|
|
21
|
+
} from './types.js';
|
|
22
|
+
import { checkError } from './errors.js';
|
|
23
|
+
import {
|
|
24
|
+
buildRequest,
|
|
25
|
+
escapeXml,
|
|
26
|
+
parseBaseResponse,
|
|
27
|
+
getTagContent,
|
|
28
|
+
getAttribute,
|
|
29
|
+
getAllElements,
|
|
30
|
+
parseXmlNumber,
|
|
31
|
+
parseXmlBool,
|
|
32
|
+
} from './request.js';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Parse a group element from XML
|
|
36
|
+
*/
|
|
37
|
+
function parseGroup(groupXml: string): Group {
|
|
38
|
+
const id = getAttribute(groupXml, 'id');
|
|
39
|
+
const name = getTagContent(groupXml, 'name');
|
|
40
|
+
const description = getTagContent(groupXml, 'description') || undefined;
|
|
41
|
+
const managedByUserStr = getTagContent(groupXml, 'managedByUser');
|
|
42
|
+
const managedByUser = managedByUserStr ? parseXmlBool(managedByUserStr) : undefined;
|
|
43
|
+
|
|
44
|
+
return { id, name, description, managedByUser };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Parse a user element from GetUsersInGroup response
|
|
49
|
+
*/
|
|
50
|
+
function parseGroupUser(userXml: string): GroupUser {
|
|
51
|
+
return {
|
|
52
|
+
id: getAttribute(userXml, 'id'),
|
|
53
|
+
firstName: getTagContent(userXml, 'firstName'),
|
|
54
|
+
lastName: getTagContent(userXml, 'lastName'),
|
|
55
|
+
email: getTagContent(userXml, 'email'),
|
|
56
|
+
screenName: getTagContent(userXml, 'screenName') || undefined,
|
|
57
|
+
isAdmin: parseXmlBool(getTagContent(userXml, 'isAdmin')),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Parse a manager element from GetUsersInGroup response
|
|
63
|
+
*/
|
|
64
|
+
function parseGroupManager(managerXml: string): GroupManager {
|
|
65
|
+
return {
|
|
66
|
+
id: getAttribute(managerXml, 'id'),
|
|
67
|
+
firstName: getTagContent(managerXml, 'firstName'),
|
|
68
|
+
lastName: getTagContent(managerXml, 'lastName'),
|
|
69
|
+
email: getTagContent(managerXml, 'email'),
|
|
70
|
+
screenName: getTagContent(managerXml, 'screenName') || undefined,
|
|
71
|
+
isMember: parseXmlBool(getTagContent(managerXml, 'isMember')),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Parse a subgroup element
|
|
77
|
+
*/
|
|
78
|
+
function parseSubgroup(subgroupXml: string): Subgroup {
|
|
79
|
+
return { id: getAttribute(subgroupXml, 'id') };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Create a new group.
|
|
84
|
+
*
|
|
85
|
+
* The group will be created with the caller as owner and first member.
|
|
86
|
+
* Caller must be the manager of the account where the group is created.
|
|
87
|
+
*
|
|
88
|
+
* @see https://help.quickbase.com/docs/api-creategroup
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const result = await createGroup(caller, 'MarketingSupport', 'Support staff', '456789');
|
|
93
|
+
* console.log(`Created group: ${result.group.id}`);
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export async function createGroup(
|
|
97
|
+
caller: XmlCaller,
|
|
98
|
+
name: string,
|
|
99
|
+
description?: string,
|
|
100
|
+
accountId?: string
|
|
101
|
+
): Promise<CreateGroupResult> {
|
|
102
|
+
let inner = `<name>${escapeXml(name)}</name>`;
|
|
103
|
+
if (description) {
|
|
104
|
+
inner += `<description>${escapeXml(description)}</description>`;
|
|
105
|
+
}
|
|
106
|
+
if (accountId) {
|
|
107
|
+
inner += `<accountID>${escapeXml(accountId)}</accountID>`;
|
|
108
|
+
}
|
|
109
|
+
const body = buildRequest(inner);
|
|
110
|
+
const xml = await caller.doXml('main', 'API_CreateGroup', body);
|
|
111
|
+
|
|
112
|
+
const base = parseBaseResponse(xml);
|
|
113
|
+
checkError(base);
|
|
114
|
+
|
|
115
|
+
// Parse group element
|
|
116
|
+
const groupMatch = xml.match(/<group[^>]*>([\s\S]*?)<\/group>/);
|
|
117
|
+
if (!groupMatch) {
|
|
118
|
+
throw new Error('Invalid API_CreateGroup response: no group element');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const group = parseGroup(groupMatch[0]);
|
|
122
|
+
return { group };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Delete a group.
|
|
127
|
+
*
|
|
128
|
+
* **Warning:** Once deleted, a group cannot be restored.
|
|
129
|
+
*
|
|
130
|
+
* @see https://help.quickbase.com/docs/api-deletegroup
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* await deleteGroup(caller, '1217.dgpt');
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export async function deleteGroup(
|
|
138
|
+
caller: XmlCaller,
|
|
139
|
+
groupId: string
|
|
140
|
+
): Promise<void> {
|
|
141
|
+
const inner = `<gid>${escapeXml(groupId)}</gid>`;
|
|
142
|
+
const body = buildRequest(inner);
|
|
143
|
+
const xml = await caller.doXml('main', 'API_DeleteGroup', body);
|
|
144
|
+
|
|
145
|
+
const base = parseBaseResponse(xml);
|
|
146
|
+
checkError(base);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Copy a group.
|
|
151
|
+
*
|
|
152
|
+
* @see https://help.quickbase.com/docs/api-copygroup
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const result = await copyGroup(caller, '1217.dgpt', 'NewGroupName', 'New description');
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export async function copyGroup(
|
|
160
|
+
caller: XmlCaller,
|
|
161
|
+
groupId: string,
|
|
162
|
+
name?: string,
|
|
163
|
+
description?: string,
|
|
164
|
+
accountId?: string
|
|
165
|
+
): Promise<CreateGroupResult> {
|
|
166
|
+
let inner = `<gid>${escapeXml(groupId)}</gid>`;
|
|
167
|
+
if (name) {
|
|
168
|
+
inner += `<name>${escapeXml(name)}</name>`;
|
|
169
|
+
}
|
|
170
|
+
if (description) {
|
|
171
|
+
inner += `<description>${escapeXml(description)}</description>`;
|
|
172
|
+
}
|
|
173
|
+
if (accountId) {
|
|
174
|
+
inner += `<accountID>${escapeXml(accountId)}</accountID>`;
|
|
175
|
+
}
|
|
176
|
+
const body = buildRequest(inner);
|
|
177
|
+
const xml = await caller.doXml('main', 'API_CopyGroup', body);
|
|
178
|
+
|
|
179
|
+
const base = parseBaseResponse(xml);
|
|
180
|
+
checkError(base);
|
|
181
|
+
|
|
182
|
+
const groupMatch = xml.match(/<group[^>]*>([\s\S]*?)<\/group>/);
|
|
183
|
+
if (!groupMatch) {
|
|
184
|
+
throw new Error('Invalid API_CopyGroup response: no group element');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const group = parseGroup(groupMatch[0]);
|
|
188
|
+
return { group };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Change group information (name, description).
|
|
193
|
+
*
|
|
194
|
+
* @see https://help.quickbase.com/docs/api-changegroupinfo
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* await changeGroupInfo(caller, '1217.dgpt', 'NewName', 'New description');
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
export async function changeGroupInfo(
|
|
202
|
+
caller: XmlCaller,
|
|
203
|
+
groupId: string,
|
|
204
|
+
name?: string,
|
|
205
|
+
description?: string,
|
|
206
|
+
accountId?: string
|
|
207
|
+
): Promise<void> {
|
|
208
|
+
let inner = `<gid>${escapeXml(groupId)}</gid>`;
|
|
209
|
+
if (name) {
|
|
210
|
+
inner += `<name>${escapeXml(name)}</name>`;
|
|
211
|
+
}
|
|
212
|
+
if (description) {
|
|
213
|
+
inner += `<description>${escapeXml(description)}</description>`;
|
|
214
|
+
}
|
|
215
|
+
if (accountId) {
|
|
216
|
+
inner += `<accountID>${escapeXml(accountId)}</accountID>`;
|
|
217
|
+
}
|
|
218
|
+
const body = buildRequest(inner);
|
|
219
|
+
const xml = await caller.doXml('main', 'API_ChangeGroupInfo', body);
|
|
220
|
+
|
|
221
|
+
const base = parseBaseResponse(xml);
|
|
222
|
+
checkError(base);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Get users and managers in a group.
|
|
227
|
+
*
|
|
228
|
+
* @see https://help.quickbase.com/docs/api-getusersingroup
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```typescript
|
|
232
|
+
* const result = await getUsersInGroup(caller, '2345.skdj', true);
|
|
233
|
+
* console.log(`Group: ${result.name}`);
|
|
234
|
+
* console.log(`Users: ${result.users.length}`);
|
|
235
|
+
* console.log(`Managers: ${result.managers.length}`);
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
export async function getUsersInGroup(
|
|
239
|
+
caller: XmlCaller,
|
|
240
|
+
groupId: string,
|
|
241
|
+
includeManagers?: boolean
|
|
242
|
+
): Promise<GetUsersInGroupResult> {
|
|
243
|
+
let inner = `<gid>${escapeXml(groupId)}</gid>`;
|
|
244
|
+
if (includeManagers) {
|
|
245
|
+
inner += '<includeAllMgrs>true</includeAllMgrs>';
|
|
246
|
+
}
|
|
247
|
+
const body = buildRequest(inner);
|
|
248
|
+
const xml = await caller.doXml('main', 'API_GetUsersInGroup', body);
|
|
249
|
+
|
|
250
|
+
const base = parseBaseResponse(xml);
|
|
251
|
+
checkError(base);
|
|
252
|
+
|
|
253
|
+
// Parse group element
|
|
254
|
+
const groupMatch = xml.match(/<group[^>]*id="([^"]*)"[^>]*>([\s\S]*?)<\/group>/);
|
|
255
|
+
if (!groupMatch || !groupMatch[1]) {
|
|
256
|
+
throw new Error('Invalid API_GetUsersInGroup response: no group element');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const groupXml = groupMatch[0];
|
|
260
|
+
const id = groupMatch[1];
|
|
261
|
+
const name = getTagContent(groupXml, 'name');
|
|
262
|
+
const description = getTagContent(groupXml, 'description') || undefined;
|
|
263
|
+
|
|
264
|
+
// Parse users
|
|
265
|
+
const userElements = getAllElements(groupXml, 'user');
|
|
266
|
+
const users = userElements.map(parseGroupUser);
|
|
267
|
+
|
|
268
|
+
// Parse managers
|
|
269
|
+
const managerElements = getAllElements(groupXml, 'manager');
|
|
270
|
+
const managers = managerElements.map(parseGroupManager);
|
|
271
|
+
|
|
272
|
+
// Parse subgroups
|
|
273
|
+
const subgroupElements = getAllElements(groupXml, 'subgroup');
|
|
274
|
+
const subgroups = subgroupElements.map(parseSubgroup);
|
|
275
|
+
|
|
276
|
+
return { id, name, description, users, managers, subgroups };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Add a user to a group.
|
|
281
|
+
*
|
|
282
|
+
* The user can be added as member, manager, or both.
|
|
283
|
+
*
|
|
284
|
+
* @see https://help.quickbase.com/docs/api-addusertogroup
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```typescript
|
|
288
|
+
* // Add as regular member
|
|
289
|
+
* await addUserToGroup(caller, '1217.dgpt', '112149.bhsv');
|
|
290
|
+
*
|
|
291
|
+
* // Add as manager
|
|
292
|
+
* await addUserToGroup(caller, '1217.dgpt', '112149.bhsv', true);
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
export async function addUserToGroup(
|
|
296
|
+
caller: XmlCaller,
|
|
297
|
+
groupId: string,
|
|
298
|
+
userId: string,
|
|
299
|
+
allowAdminAccess?: boolean
|
|
300
|
+
): Promise<void> {
|
|
301
|
+
let inner = `<gid>${escapeXml(groupId)}</gid>`;
|
|
302
|
+
inner += `<uid>${escapeXml(userId)}</uid>`;
|
|
303
|
+
if (allowAdminAccess) {
|
|
304
|
+
inner += '<allowAdminAccess>true</allowAdminAccess>';
|
|
305
|
+
}
|
|
306
|
+
const body = buildRequest(inner);
|
|
307
|
+
const xml = await caller.doXml('main', 'API_AddUserToGroup', body);
|
|
308
|
+
|
|
309
|
+
const base = parseBaseResponse(xml);
|
|
310
|
+
checkError(base);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Remove a user from a group.
|
|
315
|
+
*
|
|
316
|
+
* @see https://help.quickbase.com/docs/api-removeuserfromgroup
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* ```typescript
|
|
320
|
+
* await removeUserFromGroup(caller, '1217.dgpt', '112149.bhsv');
|
|
321
|
+
* ```
|
|
322
|
+
*/
|
|
323
|
+
export async function removeUserFromGroup(
|
|
324
|
+
caller: XmlCaller,
|
|
325
|
+
groupId: string,
|
|
326
|
+
userId: string
|
|
327
|
+
): Promise<void> {
|
|
328
|
+
const inner =
|
|
329
|
+
`<gid>${escapeXml(groupId)}</gid>` +
|
|
330
|
+
`<uid>${escapeXml(userId)}</uid>`;
|
|
331
|
+
const body = buildRequest(inner);
|
|
332
|
+
const xml = await caller.doXml('main', 'API_RemoveUserFromGroup', body);
|
|
333
|
+
|
|
334
|
+
const base = parseBaseResponse(xml);
|
|
335
|
+
checkError(base);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Get roles assigned to a group in an app.
|
|
340
|
+
*
|
|
341
|
+
* @see https://help.quickbase.com/docs/api-getgrouprole
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```typescript
|
|
345
|
+
* const result = await getGroupRole(caller, 'bqxyz123', '1217.dgpt');
|
|
346
|
+
* for (const role of result.roles) {
|
|
347
|
+
* console.log(`Role ${role.id}: ${role.name}`);
|
|
348
|
+
* }
|
|
349
|
+
* ```
|
|
350
|
+
*/
|
|
351
|
+
export async function getGroupRole(
|
|
352
|
+
caller: XmlCaller,
|
|
353
|
+
appId: string,
|
|
354
|
+
groupId: string
|
|
355
|
+
): Promise<GetGroupRoleResult> {
|
|
356
|
+
const inner = `<gid>${escapeXml(groupId)}</gid>`;
|
|
357
|
+
const body = buildRequest(inner);
|
|
358
|
+
const xml = await caller.doXml(appId, 'API_GetGroupRole', body);
|
|
359
|
+
|
|
360
|
+
const base = parseBaseResponse(xml);
|
|
361
|
+
checkError(base);
|
|
362
|
+
|
|
363
|
+
// Parse roles
|
|
364
|
+
const roleElements = getAllElements(xml, 'role');
|
|
365
|
+
const roles = roleElements.map((roleXml) => ({
|
|
366
|
+
id: parseXmlNumber(getAttribute(roleXml, 'id')),
|
|
367
|
+
name: getTagContent(roleXml, 'name'),
|
|
368
|
+
}));
|
|
369
|
+
|
|
370
|
+
return { roles };
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Assign a group to a role in an app.
|
|
375
|
+
*
|
|
376
|
+
* @see https://help.quickbase.com/docs/api-addgrouptorole
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```typescript
|
|
380
|
+
* await addGroupToRole(caller, 'bqxyz123', '1217.dgpt', 11);
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
export async function addGroupToRole(
|
|
384
|
+
caller: XmlCaller,
|
|
385
|
+
appId: string,
|
|
386
|
+
groupId: string,
|
|
387
|
+
roleId: number
|
|
388
|
+
): Promise<void> {
|
|
389
|
+
const inner =
|
|
390
|
+
`<gid>${escapeXml(groupId)}</gid>` +
|
|
391
|
+
`<roleid>${roleId}</roleid>`;
|
|
392
|
+
const body = buildRequest(inner);
|
|
393
|
+
const xml = await caller.doXml(appId, 'API_AddGroupToRole', body);
|
|
394
|
+
|
|
395
|
+
const base = parseBaseResponse(xml);
|
|
396
|
+
checkError(base);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Remove a group from a role in an app.
|
|
401
|
+
*
|
|
402
|
+
* @see https://help.quickbase.com/docs/api-removegroupfromrole
|
|
403
|
+
*
|
|
404
|
+
* @param allRoles - If true, remove from all roles (ignores roleId)
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* ```typescript
|
|
408
|
+
* // Remove from specific role
|
|
409
|
+
* await removeGroupFromRole(caller, 'bqxyz123', '1217.dgpt', 11);
|
|
410
|
+
*
|
|
411
|
+
* // Remove from all roles
|
|
412
|
+
* await removeGroupFromRole(caller, 'bqxyz123', '1217.dgpt', 0, true);
|
|
413
|
+
* ```
|
|
414
|
+
*/
|
|
415
|
+
export async function removeGroupFromRole(
|
|
416
|
+
caller: XmlCaller,
|
|
417
|
+
appId: string,
|
|
418
|
+
groupId: string,
|
|
419
|
+
roleId: number,
|
|
420
|
+
allRoles?: boolean
|
|
421
|
+
): Promise<void> {
|
|
422
|
+
let inner = `<gid>${escapeXml(groupId)}</gid>`;
|
|
423
|
+
if (allRoles) {
|
|
424
|
+
inner += '<allRoles>true</allRoles>';
|
|
425
|
+
} else {
|
|
426
|
+
inner += `<roleid>${roleId}</roleid>`;
|
|
427
|
+
}
|
|
428
|
+
const body = buildRequest(inner);
|
|
429
|
+
const xml = await caller.doXml(appId, 'API_RemoveGroupFromRole', body);
|
|
430
|
+
|
|
431
|
+
const base = parseBaseResponse(xml);
|
|
432
|
+
checkError(base);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Get groups a user belongs to.
|
|
437
|
+
*
|
|
438
|
+
* If userId is omitted, returns groups for the current user.
|
|
439
|
+
*
|
|
440
|
+
* @see https://help.quickbase.com/docs/api-grantedgroups
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* ```typescript
|
|
444
|
+
* const result = await grantedGroups(caller, '112149.bhsv');
|
|
445
|
+
* for (const group of result.groups) {
|
|
446
|
+
* console.log(`${group.name} (${group.id})`);
|
|
447
|
+
* }
|
|
448
|
+
* ```
|
|
449
|
+
*/
|
|
450
|
+
export async function grantedGroups(
|
|
451
|
+
caller: XmlCaller,
|
|
452
|
+
userId?: string,
|
|
453
|
+
adminOnly?: boolean
|
|
454
|
+
): Promise<GrantedGroupsResult> {
|
|
455
|
+
let inner = '';
|
|
456
|
+
if (userId) {
|
|
457
|
+
inner += `<userid>${escapeXml(userId)}</userid>`;
|
|
458
|
+
}
|
|
459
|
+
if (adminOnly) {
|
|
460
|
+
inner += '<adminOnly>true</adminOnly>';
|
|
461
|
+
}
|
|
462
|
+
const body = buildRequest(inner);
|
|
463
|
+
const xml = await caller.doXml('main', 'API_GrantedGroups', body);
|
|
464
|
+
|
|
465
|
+
const base = parseBaseResponse(xml);
|
|
466
|
+
checkError(base);
|
|
467
|
+
|
|
468
|
+
// Parse groups
|
|
469
|
+
const groupElements = getAllElements(xml, 'group');
|
|
470
|
+
const groups = groupElements.map((groupXml) => ({
|
|
471
|
+
id: getAttribute(groupXml, 'id'),
|
|
472
|
+
name: getTagContent(groupXml, 'name'),
|
|
473
|
+
}));
|
|
474
|
+
|
|
475
|
+
return { groups };
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Get apps a group can access.
|
|
480
|
+
*
|
|
481
|
+
* @see https://help.quickbase.com/docs/api-granteddbsforgroup
|
|
482
|
+
*
|
|
483
|
+
* @example
|
|
484
|
+
* ```typescript
|
|
485
|
+
* const result = await grantedDBsForGroup(caller, '1217.dgpt');
|
|
486
|
+
* for (const db of result.databases) {
|
|
487
|
+
* console.log(`${db.name} (${db.dbid})`);
|
|
488
|
+
* }
|
|
489
|
+
* ```
|
|
490
|
+
*/
|
|
491
|
+
export async function grantedDBsForGroup(
|
|
492
|
+
caller: XmlCaller,
|
|
493
|
+
groupId: string
|
|
494
|
+
): Promise<GrantedDBsForGroupResult> {
|
|
495
|
+
const inner = `<gid>${escapeXml(groupId)}</gid>`;
|
|
496
|
+
const body = buildRequest(inner);
|
|
497
|
+
const xml = await caller.doXml('main', 'API_GrantedDBsForGroup', body);
|
|
498
|
+
|
|
499
|
+
const base = parseBaseResponse(xml);
|
|
500
|
+
checkError(base);
|
|
501
|
+
|
|
502
|
+
// Parse databases
|
|
503
|
+
const dbElements = getAllElements(xml, 'dbinfo');
|
|
504
|
+
const databases = dbElements.map((dbXml) => ({
|
|
505
|
+
dbid: getTagContent(dbXml, 'dbid'),
|
|
506
|
+
name: getTagContent(dbXml, 'dbname'),
|
|
507
|
+
}));
|
|
508
|
+
|
|
509
|
+
return { databases };
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Add a subgroup to a group.
|
|
514
|
+
*
|
|
515
|
+
* @see https://help.quickbase.com/docs/api-addsubgroup
|
|
516
|
+
*
|
|
517
|
+
* @example
|
|
518
|
+
* ```typescript
|
|
519
|
+
* await addSubgroup(caller, '1217.dgpt', '3450.aefs');
|
|
520
|
+
* ```
|
|
521
|
+
*/
|
|
522
|
+
export async function addSubgroup(
|
|
523
|
+
caller: XmlCaller,
|
|
524
|
+
groupId: string,
|
|
525
|
+
subgroupId: string
|
|
526
|
+
): Promise<void> {
|
|
527
|
+
const inner =
|
|
528
|
+
`<gid>${escapeXml(groupId)}</gid>` +
|
|
529
|
+
`<subgroupid>${escapeXml(subgroupId)}</subgroupid>`;
|
|
530
|
+
const body = buildRequest(inner);
|
|
531
|
+
const xml = await caller.doXml('main', 'API_AddSubgroup', body);
|
|
532
|
+
|
|
533
|
+
const base = parseBaseResponse(xml);
|
|
534
|
+
checkError(base);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Remove a subgroup from a group.
|
|
539
|
+
*
|
|
540
|
+
* @see https://help.quickbase.com/docs/api-removesubgroup
|
|
541
|
+
*
|
|
542
|
+
* @example
|
|
543
|
+
* ```typescript
|
|
544
|
+
* await removeSubgroup(caller, '1217.dgpt', '3450.aefs');
|
|
545
|
+
* ```
|
|
546
|
+
*/
|
|
547
|
+
export async function removeSubgroup(
|
|
548
|
+
caller: XmlCaller,
|
|
549
|
+
groupId: string,
|
|
550
|
+
subgroupId: string
|
|
551
|
+
): Promise<void> {
|
|
552
|
+
const inner =
|
|
553
|
+
`<gid>${escapeXml(groupId)}</gid>` +
|
|
554
|
+
`<subgroupid>${escapeXml(subgroupId)}</subgroupid>`;
|
|
555
|
+
const body = buildRequest(inner);
|
|
556
|
+
const xml = await caller.doXml('main', 'API_RemoveSubgroup', body);
|
|
557
|
+
|
|
558
|
+
const base = parseBaseResponse(xml);
|
|
559
|
+
checkError(base);
|
|
560
|
+
}
|
package/src/xml/html.ts
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XML API HTML Generation
|
|
3
|
+
*
|
|
4
|
+
* Endpoints for generating HTML forms and tables.
|
|
5
|
+
*
|
|
6
|
+
* XML-API: Remove this file when QuickBase discontinues the XML API.
|
|
7
|
+
* To find all XML API code, search for: XML-API
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { XmlCaller } from './types.js';
|
|
11
|
+
import { checkError } from './errors.js';
|
|
12
|
+
import {
|
|
13
|
+
buildRequest,
|
|
14
|
+
escapeXml,
|
|
15
|
+
parseBaseResponse,
|
|
16
|
+
} from './request.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generate HTML form for adding a record.
|
|
20
|
+
*
|
|
21
|
+
* @see https://help.quickbase.com/docs/api-genaddrecordform
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const html = await genAddRecordForm(caller, 'bqtable123');
|
|
26
|
+
* // Use the HTML form in your UI
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export async function genAddRecordForm(
|
|
30
|
+
caller: XmlCaller,
|
|
31
|
+
tableId: string,
|
|
32
|
+
fields?: Array<{ id: number; value: string }>
|
|
33
|
+
): Promise<string> {
|
|
34
|
+
let inner = '';
|
|
35
|
+
if (fields) {
|
|
36
|
+
for (const field of fields) {
|
|
37
|
+
inner += `<field fid="${field.id}">${escapeXml(field.value)}</field>`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const body = buildRequest(inner);
|
|
42
|
+
const xml = await caller.doXml(tableId, 'API_GenAddRecordForm', body);
|
|
43
|
+
|
|
44
|
+
// Check for errors - the response may or may not be XML
|
|
45
|
+
if (xml.includes('<errcode>') && !xml.includes('<errcode>0</errcode>')) {
|
|
46
|
+
const base = parseBaseResponse(xml);
|
|
47
|
+
checkError(base);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return xml;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Generate HTML/JS/CSV table of query results.
|
|
55
|
+
*
|
|
56
|
+
* @see https://help.quickbase.com/docs/api-genresultstable
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* const html = await genResultsTable(caller, 'bqtable123', {
|
|
61
|
+
* query: "{'7'.CT.'test'}",
|
|
62
|
+
* clist: [6, 7, 8],
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export async function genResultsTable(
|
|
67
|
+
caller: XmlCaller,
|
|
68
|
+
tableId: string,
|
|
69
|
+
options?: {
|
|
70
|
+
query?: string;
|
|
71
|
+
clist?: number[];
|
|
72
|
+
slist?: number[];
|
|
73
|
+
options?: string;
|
|
74
|
+
format?: 'structured' | 'csv';
|
|
75
|
+
}
|
|
76
|
+
): Promise<string> {
|
|
77
|
+
let inner = '';
|
|
78
|
+
|
|
79
|
+
if (options?.query) {
|
|
80
|
+
inner += `<query>${escapeXml(options.query)}</query>`;
|
|
81
|
+
}
|
|
82
|
+
if (options?.clist && options.clist.length > 0) {
|
|
83
|
+
inner += `<clist>${options.clist.join('.')}</clist>`;
|
|
84
|
+
}
|
|
85
|
+
if (options?.slist && options.slist.length > 0) {
|
|
86
|
+
inner += `<slist>${options.slist.join('.')}</slist>`;
|
|
87
|
+
}
|
|
88
|
+
if (options?.options) {
|
|
89
|
+
inner += `<options>${escapeXml(options.options)}</options>`;
|
|
90
|
+
}
|
|
91
|
+
if (options?.format) {
|
|
92
|
+
inner += `<fmt>${options.format}</fmt>`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const body = buildRequest(inner);
|
|
96
|
+
const xml = await caller.doXml(tableId, 'API_GenResultsTable', body);
|
|
97
|
+
|
|
98
|
+
// Check for errors
|
|
99
|
+
if (xml.includes('<errcode>') && !xml.includes('<errcode>0</errcode>')) {
|
|
100
|
+
const base = parseBaseResponse(xml);
|
|
101
|
+
checkError(base);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return xml;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get a record rendered as HTML.
|
|
109
|
+
*
|
|
110
|
+
* @see https://help.quickbase.com/docs/api-getrecordashtml
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const html = await getRecordAsHTML(caller, 'bqtable123', { rid: 42 });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export async function getRecordAsHTML(
|
|
118
|
+
caller: XmlCaller,
|
|
119
|
+
tableId: string,
|
|
120
|
+
options: {
|
|
121
|
+
rid?: number;
|
|
122
|
+
key?: string;
|
|
123
|
+
jht?: boolean;
|
|
124
|
+
dfid?: number;
|
|
125
|
+
}
|
|
126
|
+
): Promise<string> {
|
|
127
|
+
let inner = '';
|
|
128
|
+
|
|
129
|
+
if (options.rid !== undefined) {
|
|
130
|
+
inner += `<rid>${options.rid}</rid>`;
|
|
131
|
+
}
|
|
132
|
+
if (options.key) {
|
|
133
|
+
inner += `<key>${escapeXml(options.key)}</key>`;
|
|
134
|
+
}
|
|
135
|
+
if (options.jht) {
|
|
136
|
+
inner += '<jht>1</jht>';
|
|
137
|
+
}
|
|
138
|
+
if (options.dfid !== undefined) {
|
|
139
|
+
inner += `<dfid>${options.dfid}</dfid>`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const body = buildRequest(inner);
|
|
143
|
+
const xml = await caller.doXml(tableId, 'API_GetRecordAsHTML', body);
|
|
144
|
+
|
|
145
|
+
// Check for errors
|
|
146
|
+
if (xml.includes('<errcode>') && !xml.includes('<errcode>0</errcode>')) {
|
|
147
|
+
const base = parseBaseResponse(xml);
|
|
148
|
+
checkError(base);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return xml;
|
|
152
|
+
}
|