@openhi/constructs 0.0.160 → 0.0.161
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/lib/{chunk-HQ67J7BP.mjs → chunk-5S6VFBLT.mjs} +12 -70
- package/lib/chunk-5S6VFBLT.mjs.map +1 -0
- package/lib/{chunk-MVQWAIMC.mjs → chunk-6BB4CRSS.mjs} +3 -312
- package/lib/chunk-6BB4CRSS.mjs.map +1 -0
- package/lib/{chunk-WPCBVDFZ.mjs → chunk-76UM2LQ5.mjs} +2 -2
- package/lib/{chunk-QFHYTCVY.mjs → chunk-7TRO2STL.mjs} +7 -7
- package/lib/chunk-BUAYVN3C.mjs +87 -0
- package/lib/chunk-BUAYVN3C.mjs.map +1 -0
- package/lib/{chunk-23PUSHBV.mjs → chunk-D2Y6DDOC.mjs} +2 -2
- package/lib/chunk-DWSWCUZR.mjs +123 -0
- package/lib/chunk-DWSWCUZR.mjs.map +1 -0
- package/lib/{chunk-VZCPGQXA.mjs → chunk-EUIP2U5F.mjs} +69 -1
- package/lib/{chunk-VZCPGQXA.mjs.map → chunk-EUIP2U5F.mjs.map} +1 -1
- package/lib/chunk-GJTPXJKD.mjs +46 -0
- package/lib/chunk-GJTPXJKD.mjs.map +1 -0
- package/lib/chunk-I6LUPJUY.mjs +61 -0
- package/lib/chunk-I6LUPJUY.mjs.map +1 -0
- package/lib/{chunk-KR2Y2CVQ.mjs → chunk-KA3OMP3X.mjs} +2 -2
- package/lib/{chunk-ZM4GDHHC.mjs → chunk-KMEWULMX.mjs} +51 -3
- package/lib/chunk-KMEWULMX.mjs.map +1 -0
- package/lib/chunk-LKKLO66E.mjs +25 -0
- package/lib/chunk-LKKLO66E.mjs.map +1 -0
- package/lib/{chunk-CFJDATDK.mjs → chunk-MLFMW5IF.mjs} +43 -9
- package/lib/chunk-MLFMW5IF.mjs.map +1 -0
- package/lib/chunk-O5VQWB6U.mjs +315 -0
- package/lib/chunk-O5VQWB6U.mjs.map +1 -0
- package/lib/{chunk-7BQHLC7U.mjs → chunk-P3CTZWC2.mjs} +8 -40
- package/lib/chunk-P3CTZWC2.mjs.map +1 -0
- package/lib/{chunk-EFB5OFM7.mjs → chunk-P3NFCKTZ.mjs} +6 -4
- package/lib/{chunk-EFB5OFM7.mjs.map → chunk-P3NFCKTZ.mjs.map} +1 -1
- package/lib/{chunk-M7Y3BOQW.mjs → chunk-Q3MKITPY.mjs} +5 -5
- package/lib/chunk-Q64MOYJ7.mjs +218 -0
- package/lib/chunk-Q64MOYJ7.mjs.map +1 -0
- package/lib/chunk-RQKJNMX5.mjs +89 -0
- package/lib/chunk-RQKJNMX5.mjs.map +1 -0
- package/lib/{chunk-ZWSGM6PZ.mjs → chunk-SD7J3N3C.mjs} +2 -2
- package/lib/{chunk-7RZHFI77.mjs → chunk-VESULYQQ.mjs} +2 -2
- package/lib/{chunk-AOSEKL7U.mjs → chunk-WOTU36P3.mjs} +6 -103
- package/lib/chunk-WOTU36P3.mjs.map +1 -0
- package/lib/{chunk-X5E4YJGZ.mjs → chunk-YPTJJ35S.mjs} +2 -2
- package/lib/counter-apply-operation-DZM3MIDm.d.mts +63 -0
- package/lib/counter-apply-operation-DZM3MIDm.d.ts +63 -0
- package/lib/counter-maintenance.handler.d.mts +38 -0
- package/lib/counter-maintenance.handler.d.ts +38 -0
- package/lib/counter-maintenance.handler.js +2885 -0
- package/lib/counter-maintenance.handler.js.map +1 -0
- package/lib/counter-maintenance.handler.mjs +180 -0
- package/lib/counter-maintenance.handler.mjs.map +1 -0
- package/lib/counter-reconciliation.handler.d.mts +116 -0
- package/lib/counter-reconciliation.handler.d.ts +116 -0
- package/lib/counter-reconciliation.handler.js +3324 -0
- package/lib/counter-reconciliation.handler.js.map +1 -0
- package/lib/counter-reconciliation.handler.mjs +295 -0
- package/lib/counter-reconciliation.handler.mjs.map +1 -0
- package/lib/data-store-postgres-replication.handler.js +50 -2
- package/lib/data-store-postgres-replication.handler.js.map +1 -1
- package/lib/data-store-postgres-replication.handler.mjs +2 -2
- package/lib/delete-chunk.handler.js +118 -2
- package/lib/delete-chunk.handler.js.map +1 -1
- package/lib/delete-chunk.handler.mjs +3 -3
- package/lib/finalize.handler.js +50 -2
- package/lib/finalize.handler.js.map +1 -1
- package/lib/finalize.handler.mjs +4 -4
- package/lib/firehose-archive-transform.handler.js +50 -2
- package/lib/firehose-archive-transform.handler.js.map +1 -1
- package/lib/firehose-archive-transform.handler.mjs +2 -2
- package/lib/index.d.mts +140 -2
- package/lib/index.d.ts +143 -5
- package/lib/index.js +493 -196
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +360 -193
- package/lib/index.mjs.map +1 -1
- package/lib/list-chunks.handler.js +118 -2
- package/lib/list-chunks.handler.js.map +1 -1
- package/lib/list-chunks.handler.mjs +3 -3
- package/lib/platform-deploy-bridge.handler.js +50 -2
- package/lib/platform-deploy-bridge.handler.js.map +1 -1
- package/lib/platform-deploy-bridge.handler.mjs +1 -1
- package/lib/pre-token-generation.handler.js +68 -0
- package/lib/pre-token-generation.handler.js.map +1 -1
- package/lib/pre-token-generation.handler.mjs +9 -5
- package/lib/pre-token-generation.handler.mjs.map +1 -1
- package/lib/provision-default-workspace.handler.js +883 -0
- package/lib/provision-default-workspace.handler.js.map +1 -1
- package/lib/provision-default-workspace.handler.mjs +10 -5
- package/lib/provision-default-workspace.handler.mjs.map +1 -1
- package/lib/rename-finalize.handler.js +50 -2
- package/lib/rename-finalize.handler.js.map +1 -1
- package/lib/rename-finalize.handler.mjs +2 -2
- package/lib/rename-list-targets.handler.js +118 -2
- package/lib/rename-list-targets.handler.js.map +1 -1
- package/lib/rename-list-targets.handler.mjs +11 -9
- package/lib/rename-list-targets.handler.mjs.map +1 -1
- package/lib/rename-rewrite-chunk.handler.js +68 -0
- package/lib/rename-rewrite-chunk.handler.js.map +1 -1
- package/lib/rename-rewrite-chunk.handler.mjs +2 -2
- package/lib/rest-api-lambda.handler.js +1454 -251
- package/lib/rest-api-lambda.handler.js.map +1 -1
- package/lib/rest-api-lambda.handler.mjs +415 -291
- package/lib/rest-api-lambda.handler.mjs.map +1 -1
- package/lib/seed-demo-data.handler.js +205 -8
- package/lib/seed-demo-data.handler.js.map +1 -1
- package/lib/seed-demo-data.handler.mjs +10 -7
- package/lib/seed-system-data.handler.js +118 -2
- package/lib/seed-system-data.handler.js.map +1 -1
- package/lib/seed-system-data.handler.mjs +5 -5
- package/package.json +1 -1
- package/lib/chunk-7BQHLC7U.mjs.map +0 -1
- package/lib/chunk-AOSEKL7U.mjs.map +0 -1
- package/lib/chunk-CFJDATDK.mjs.map +0 -1
- package/lib/chunk-HQ67J7BP.mjs.map +0 -1
- package/lib/chunk-MVQWAIMC.mjs.map +0 -1
- package/lib/chunk-ZM4GDHHC.mjs.map +0 -1
- /package/lib/{chunk-WPCBVDFZ.mjs.map → chunk-76UM2LQ5.mjs.map} +0 -0
- /package/lib/{chunk-QFHYTCVY.mjs.map → chunk-7TRO2STL.mjs.map} +0 -0
- /package/lib/{chunk-23PUSHBV.mjs.map → chunk-D2Y6DDOC.mjs.map} +0 -0
- /package/lib/{chunk-KR2Y2CVQ.mjs.map → chunk-KA3OMP3X.mjs.map} +0 -0
- /package/lib/{chunk-M7Y3BOQW.mjs.map → chunk-Q3MKITPY.mjs.map} +0 -0
- /package/lib/{chunk-ZWSGM6PZ.mjs.map → chunk-SD7J3N3C.mjs.map} +0 -0
- /package/lib/{chunk-7RZHFI77.mjs.map → chunk-VESULYQQ.mjs.map} +0 -0
- /package/lib/{chunk-X5E4YJGZ.mjs.map → chunk-YPTJJ35S.mjs.map} +0 -0
|
@@ -3,7 +3,14 @@ import {
|
|
|
3
3
|
} from "./chunk-2O3CXY2C.mjs";
|
|
4
4
|
import {
|
|
5
5
|
createRoleOperation
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SD7J3N3C.mjs";
|
|
7
|
+
import {
|
|
8
|
+
countMembershipsByUserOperation,
|
|
9
|
+
listTenantsOperation,
|
|
10
|
+
listWorkspacesOperation,
|
|
11
|
+
membershipListByWorkspaceOperation,
|
|
12
|
+
roleAssignmentListByWorkspaceOperation
|
|
13
|
+
} from "./chunk-Q64MOYJ7.mjs";
|
|
7
14
|
import {
|
|
8
15
|
createAccountOperation,
|
|
9
16
|
createAppointmentOperation,
|
|
@@ -19,27 +26,37 @@ import {
|
|
|
19
26
|
createPractitionerOperation,
|
|
20
27
|
createProcedureOperation,
|
|
21
28
|
getRoleByIdOperation
|
|
22
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-P3NFCKTZ.mjs";
|
|
23
30
|
import {
|
|
24
|
-
listMembershipsOperation,
|
|
25
31
|
listPractitionerRolesOperation,
|
|
26
32
|
listRoleAssignmentsOperation
|
|
27
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-P3CTZWC2.mjs";
|
|
34
|
+
import {
|
|
35
|
+
listMembershipsOperation
|
|
36
|
+
} from "./chunk-GJTPXJKD.mjs";
|
|
28
37
|
import {
|
|
29
38
|
createMembershipOperation,
|
|
30
39
|
createRoleAssignmentOperation,
|
|
31
40
|
createTenantOperation,
|
|
32
41
|
createWorkspaceOperation,
|
|
33
42
|
extractDenormalizedReferenceDisplay
|
|
34
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-MLFMW5IF.mjs";
|
|
44
|
+
import {
|
|
45
|
+
extractRoleLevel,
|
|
46
|
+
publishMembershipDeleted,
|
|
47
|
+
publishRoleAssignmentDeleted,
|
|
48
|
+
publishWorkspaceDeleted
|
|
49
|
+
} from "./chunk-BUAYVN3C.mjs";
|
|
35
50
|
import {
|
|
36
|
-
buildMembershipUserProjectionItem,
|
|
37
51
|
buildMembershipWorkspaceProjectionItem,
|
|
38
52
|
buildRoleAssignmentUserProjectionItem,
|
|
39
53
|
buildRoleAssignmentWorkspaceProjectionItem,
|
|
40
|
-
extractReferenceSlug
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
extractReferenceSlug as extractReferenceSlug2
|
|
55
|
+
} from "./chunk-5S6VFBLT.mjs";
|
|
56
|
+
import {
|
|
57
|
+
buildMembershipUserProjectionItem,
|
|
58
|
+
extractReferenceSlug
|
|
59
|
+
} from "./chunk-I6LUPJUY.mjs";
|
|
43
60
|
import {
|
|
44
61
|
executeMultiWrite
|
|
45
62
|
} from "./chunk-QJDHVMKT.mjs";
|
|
@@ -48,11 +65,16 @@ import {
|
|
|
48
65
|
deleteUserOperation,
|
|
49
66
|
findUserBySubOperation,
|
|
50
67
|
getUserByIdOperation,
|
|
51
|
-
listUsersOperation,
|
|
52
|
-
membershipListByUserOperation,
|
|
53
68
|
switchUserTenantWorkspaceOperation,
|
|
54
69
|
updateUserOperation
|
|
55
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-WOTU36P3.mjs";
|
|
71
|
+
import {
|
|
72
|
+
listUsersOperation,
|
|
73
|
+
membershipListByUserOperation
|
|
74
|
+
} from "./chunk-DWSWCUZR.mjs";
|
|
75
|
+
import {
|
|
76
|
+
getDynamoDataService
|
|
77
|
+
} from "./chunk-6BB4CRSS.mjs";
|
|
56
78
|
import {
|
|
57
79
|
batchGetWithRetry,
|
|
58
80
|
buildUpdatedResourceWithAudit,
|
|
@@ -62,11 +84,10 @@ import {
|
|
|
62
84
|
deleteDataEntityById,
|
|
63
85
|
dispatchListMode,
|
|
64
86
|
getDataEntityById,
|
|
65
|
-
getDynamoDataService,
|
|
66
87
|
listDataEntitiesByWorkspace,
|
|
67
88
|
mergeAuditIntoMeta,
|
|
68
89
|
updateDataEntityById
|
|
69
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-O5VQWB6U.mjs";
|
|
70
91
|
import {
|
|
71
92
|
ConflictError,
|
|
72
93
|
ForbiddenError,
|
|
@@ -77,8 +98,9 @@ import {
|
|
|
77
98
|
import {
|
|
78
99
|
SHARD_COUNT,
|
|
79
100
|
getDynamoControlService
|
|
80
|
-
} from "./chunk-
|
|
101
|
+
} from "./chunk-EUIP2U5F.mjs";
|
|
81
102
|
import "./chunk-TRY7JGWO.mjs";
|
|
103
|
+
import "./chunk-KMEWULMX.mjs";
|
|
82
104
|
import "./chunk-LZOMFHX3.mjs";
|
|
83
105
|
|
|
84
106
|
// src/data/lambda/rest-api-lambda.handler.ts
|
|
@@ -1052,7 +1074,7 @@ function sendInvalidSummary400(res, diagnostics) {
|
|
|
1052
1074
|
}
|
|
1053
1075
|
async function handleListRoute(opts) {
|
|
1054
1076
|
const { req, res, basePath, listOperation, errorLogContext } = opts;
|
|
1055
|
-
const ctx = req.openhiContext;
|
|
1077
|
+
const ctx = opts.context ?? req.openhiContext;
|
|
1056
1078
|
const parsed = parseSearchSubsetting(req, res);
|
|
1057
1079
|
if ("errorResponse" in parsed) return parsed.errorResponse;
|
|
1058
1080
|
try {
|
|
@@ -1732,6 +1754,14 @@ async function deleteMembershipOperation(params) {
|
|
|
1732
1754
|
});
|
|
1733
1755
|
}
|
|
1734
1756
|
await executeMultiWrite({ service, triples });
|
|
1757
|
+
await publishMembershipDeleted(context, {
|
|
1758
|
+
membershipId: id,
|
|
1759
|
+
tenantId: context.tenantId,
|
|
1760
|
+
...userIdFromResource !== void 0 && { userId: userIdFromResource },
|
|
1761
|
+
...workspaceIdFromResource !== void 0 && {
|
|
1762
|
+
workspaceId: workspaceIdFromResource
|
|
1763
|
+
}
|
|
1764
|
+
});
|
|
1735
1765
|
}
|
|
1736
1766
|
|
|
1737
1767
|
// src/data/rest-api/routes/control/membership/membership-delete-route.ts
|
|
@@ -1783,14 +1813,154 @@ async function getMembershipByIdRoute(req, res) {
|
|
|
1783
1813
|
}
|
|
1784
1814
|
}
|
|
1785
1815
|
|
|
1816
|
+
// src/data/rest-api/routes/control/cross-cutting-route-helpers.ts
|
|
1817
|
+
function sendInvalidQuery400(res, diagnostics) {
|
|
1818
|
+
return res.status(400).json({
|
|
1819
|
+
resourceType: "OperationOutcome",
|
|
1820
|
+
issue: [{ severity: "error", code: "invalid", diagnostics }]
|
|
1821
|
+
});
|
|
1822
|
+
}
|
|
1823
|
+
function resolveTenantScopeOverride(req, res, context) {
|
|
1824
|
+
const raw = (req.query ?? {}).tenant;
|
|
1825
|
+
if (raw === void 0) {
|
|
1826
|
+
return { ok: true, context };
|
|
1827
|
+
}
|
|
1828
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
1829
|
+
return {
|
|
1830
|
+
ok: false,
|
|
1831
|
+
response: sendInvalidQuery400(
|
|
1832
|
+
res,
|
|
1833
|
+
"Query parameter `tenant` must be a non-empty string."
|
|
1834
|
+
)
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
1837
|
+
return { ok: true, context: { ...context, tenantId: raw } };
|
|
1838
|
+
}
|
|
1839
|
+
function sendForbidden403(res, diagnostics) {
|
|
1840
|
+
return res.status(403).json({
|
|
1841
|
+
resourceType: "OperationOutcome",
|
|
1842
|
+
issue: [{ severity: "error", code: "forbidden", diagnostics }]
|
|
1843
|
+
});
|
|
1844
|
+
}
|
|
1845
|
+
var COMMON_KEYS = ["cursor", "limit", "order"];
|
|
1846
|
+
function parseCommonListQuery(req, res, options = {}) {
|
|
1847
|
+
const q = req.query ?? {};
|
|
1848
|
+
const allowedKeys = /* @__PURE__ */ new Set([
|
|
1849
|
+
...COMMON_KEYS,
|
|
1850
|
+
...options.extraKeys ?? []
|
|
1851
|
+
]);
|
|
1852
|
+
const extra = Object.keys(q).filter((k) => !allowedKeys.has(k));
|
|
1853
|
+
if (extra.length > 0) {
|
|
1854
|
+
return {
|
|
1855
|
+
ok: false,
|
|
1856
|
+
response: sendInvalidQuery400(
|
|
1857
|
+
res,
|
|
1858
|
+
`Unsupported query parameter${extra.length === 1 ? "" : "s"}: ${extra.join(", ")}.`
|
|
1859
|
+
)
|
|
1860
|
+
};
|
|
1861
|
+
}
|
|
1862
|
+
const rawCursor = q.cursor;
|
|
1863
|
+
let cursor = null;
|
|
1864
|
+
if (rawCursor !== void 0) {
|
|
1865
|
+
if (typeof rawCursor !== "string") {
|
|
1866
|
+
return {
|
|
1867
|
+
ok: false,
|
|
1868
|
+
response: sendInvalidQuery400(
|
|
1869
|
+
res,
|
|
1870
|
+
"Query parameter `cursor` must be a string."
|
|
1871
|
+
)
|
|
1872
|
+
};
|
|
1873
|
+
}
|
|
1874
|
+
cursor = rawCursor;
|
|
1875
|
+
}
|
|
1876
|
+
const rawLimit = q.limit;
|
|
1877
|
+
let limit;
|
|
1878
|
+
if (rawLimit !== void 0) {
|
|
1879
|
+
if (typeof rawLimit !== "string" || rawLimit.length === 0) {
|
|
1880
|
+
return {
|
|
1881
|
+
ok: false,
|
|
1882
|
+
response: sendInvalidQuery400(
|
|
1883
|
+
res,
|
|
1884
|
+
"Query parameter `limit` must be a positive integer."
|
|
1885
|
+
)
|
|
1886
|
+
};
|
|
1887
|
+
}
|
|
1888
|
+
const parsed = Number(rawLimit);
|
|
1889
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
1890
|
+
return {
|
|
1891
|
+
ok: false,
|
|
1892
|
+
response: sendInvalidQuery400(
|
|
1893
|
+
res,
|
|
1894
|
+
"Query parameter `limit` must be a positive integer."
|
|
1895
|
+
)
|
|
1896
|
+
};
|
|
1897
|
+
}
|
|
1898
|
+
limit = parsed;
|
|
1899
|
+
}
|
|
1900
|
+
const rawOrder = q.order;
|
|
1901
|
+
let order;
|
|
1902
|
+
if (rawOrder !== void 0) {
|
|
1903
|
+
if (rawOrder !== "asc" && rawOrder !== "desc") {
|
|
1904
|
+
return {
|
|
1905
|
+
ok: false,
|
|
1906
|
+
response: sendInvalidQuery400(
|
|
1907
|
+
res,
|
|
1908
|
+
'Query parameter `order` must be one of "asc", "desc".'
|
|
1909
|
+
)
|
|
1910
|
+
};
|
|
1911
|
+
}
|
|
1912
|
+
order = rawOrder;
|
|
1913
|
+
}
|
|
1914
|
+
const value = order === void 0 ? limit === void 0 ? { cursor } : { cursor, limit } : limit === void 0 ? { cursor, order } : { cursor, limit, order };
|
|
1915
|
+
return { ok: true, value };
|
|
1916
|
+
}
|
|
1917
|
+
function buildPaginationLinks(opts) {
|
|
1918
|
+
const links = [
|
|
1919
|
+
{ relation: "self", url: composeUrl(opts.basePath, opts.query) }
|
|
1920
|
+
];
|
|
1921
|
+
if (opts.nextCursor !== null && opts.nextCursor.length > 0) {
|
|
1922
|
+
const nextQuery = { ...opts.query };
|
|
1923
|
+
nextQuery.cursor = opts.nextCursor;
|
|
1924
|
+
links.push({
|
|
1925
|
+
relation: "next",
|
|
1926
|
+
url: composeUrl(opts.basePath, nextQuery)
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
return links;
|
|
1930
|
+
}
|
|
1931
|
+
function composeUrl(basePath, query) {
|
|
1932
|
+
const usp = new URLSearchParams();
|
|
1933
|
+
for (const [key, value] of Object.entries(query)) {
|
|
1934
|
+
if (value === void 0 || value === null) {
|
|
1935
|
+
continue;
|
|
1936
|
+
}
|
|
1937
|
+
if (Array.isArray(value)) {
|
|
1938
|
+
for (const v of value) {
|
|
1939
|
+
if (v !== void 0 && v !== null) {
|
|
1940
|
+
usp.append(key, String(v));
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
} else {
|
|
1944
|
+
usp.append(key, String(value));
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
const qs = usp.toString();
|
|
1948
|
+
return qs.length === 0 ? basePath : `${basePath}?${qs}`;
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1786
1951
|
// src/data/rest-api/routes/control/membership/membership-list-route.ts
|
|
1787
1952
|
async function listMembershipsRoute(req, res) {
|
|
1953
|
+
const scope = resolveTenantScopeOverride(req, res, req.openhiContext);
|
|
1954
|
+
if (!scope.ok) {
|
|
1955
|
+
return scope.response;
|
|
1956
|
+
}
|
|
1788
1957
|
return handleListRoute({
|
|
1789
1958
|
req,
|
|
1790
1959
|
res,
|
|
1791
1960
|
basePath: BASE_PATH.MEMBERSHIP,
|
|
1792
1961
|
listOperation: listMembershipsOperation,
|
|
1793
|
-
errorLogContext: "GET /Membership list error:"
|
|
1962
|
+
errorLogContext: "GET /Membership list error:",
|
|
1963
|
+
context: scope.context
|
|
1794
1964
|
});
|
|
1795
1965
|
}
|
|
1796
1966
|
|
|
@@ -2277,6 +2447,18 @@ async function deleteRoleAssignmentOperation(params) {
|
|
|
2277
2447
|
});
|
|
2278
2448
|
}
|
|
2279
2449
|
await executeMultiWrite({ service, triples });
|
|
2450
|
+
await publishRoleAssignmentDeleted(context, {
|
|
2451
|
+
roleAssignmentId: id,
|
|
2452
|
+
tenantId: context.tenantId,
|
|
2453
|
+
...userIdFromResource !== void 0 && { userId: userIdFromResource },
|
|
2454
|
+
...workspaceIdFromResource !== void 0 && {
|
|
2455
|
+
workspaceId: workspaceIdFromResource
|
|
2456
|
+
},
|
|
2457
|
+
...roleIdFromResource !== void 0 && { roleId: roleIdFromResource },
|
|
2458
|
+
...extractRoleLevel(parsed) !== void 0 && {
|
|
2459
|
+
roleLevel: extractRoleLevel(parsed)
|
|
2460
|
+
}
|
|
2461
|
+
});
|
|
2280
2462
|
}
|
|
2281
2463
|
|
|
2282
2464
|
// src/data/rest-api/routes/control/roleassignment/roleassignment-delete-route.ts
|
|
@@ -2631,42 +2813,6 @@ async function getTenantByIdRoute(req, res) {
|
|
|
2631
2813
|
}
|
|
2632
2814
|
}
|
|
2633
2815
|
|
|
2634
|
-
// src/data/operations/control/tenant/tenant-list-operation.ts
|
|
2635
|
-
var SK7 = "CURRENT";
|
|
2636
|
-
async function listTenantsOperation(params) {
|
|
2637
|
-
const { tableName, mode = "full" } = params;
|
|
2638
|
-
const service = getDynamoControlService(tableName);
|
|
2639
|
-
const shardResults = await Promise.all(
|
|
2640
|
-
Array.from(
|
|
2641
|
-
{ length: SHARD_COUNT },
|
|
2642
|
-
(_, shard) => service.entities.tenant.query.gsi1({ gsi1Shard: String(shard) }).go()
|
|
2643
|
-
)
|
|
2644
|
-
);
|
|
2645
|
-
return dispatchListMode(
|
|
2646
|
-
mode,
|
|
2647
|
-
shardResults,
|
|
2648
|
-
{
|
|
2649
|
-
hydrate: (orderedIds) => batchGetWithRetry(
|
|
2650
|
-
service.entities.tenant,
|
|
2651
|
-
orderedIds.map((id) => ({ tenantId: id, sk: SK7 }))
|
|
2652
|
-
),
|
|
2653
|
-
getId: (item) => item.id,
|
|
2654
|
-
buildEntry: (id, item) => ({
|
|
2655
|
-
id,
|
|
2656
|
-
resource: {
|
|
2657
|
-
resourceType: "Tenant",
|
|
2658
|
-
id,
|
|
2659
|
-
...JSON.parse(item.resource)
|
|
2660
|
-
}
|
|
2661
|
-
}),
|
|
2662
|
-
buildSummaryEntry: (id, parsed) => ({
|
|
2663
|
-
id,
|
|
2664
|
-
resource: { resourceType: "Tenant", id, ...parsed }
|
|
2665
|
-
})
|
|
2666
|
-
}
|
|
2667
|
-
);
|
|
2668
|
-
}
|
|
2669
|
-
|
|
2670
2816
|
// src/data/rest-api/routes/control/tenant/tenant-list-route.ts
|
|
2671
2817
|
async function listTenantsRoute(req, res) {
|
|
2672
2818
|
return handleListRoute({
|
|
@@ -2678,6 +2824,179 @@ async function listTenantsRoute(req, res) {
|
|
|
2678
2824
|
});
|
|
2679
2825
|
}
|
|
2680
2826
|
|
|
2827
|
+
// src/data/operations/control/tenant/tenant-users-operation.ts
|
|
2828
|
+
var USER_SK = "CURRENT";
|
|
2829
|
+
function extractEmail(user) {
|
|
2830
|
+
const telecom = user.telecom;
|
|
2831
|
+
if (!Array.isArray(telecom)) {
|
|
2832
|
+
return null;
|
|
2833
|
+
}
|
|
2834
|
+
for (const entry of telecom) {
|
|
2835
|
+
if (entry.system === "email" && typeof entry.value === "string" && entry.value.length > 0) {
|
|
2836
|
+
return entry.value;
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
return null;
|
|
2840
|
+
}
|
|
2841
|
+
function extractDisplayName(user) {
|
|
2842
|
+
const name = user.name;
|
|
2843
|
+
if (!Array.isArray(name) || name.length === 0) {
|
|
2844
|
+
return null;
|
|
2845
|
+
}
|
|
2846
|
+
const first = name[0];
|
|
2847
|
+
if (typeof first.text === "string" && first.text.trim().length > 0) {
|
|
2848
|
+
return first.text.trim();
|
|
2849
|
+
}
|
|
2850
|
+
const given = Array.isArray(first.given) ? first.given.filter((g) => typeof g === "string").join(" ").trim() : "";
|
|
2851
|
+
const family = typeof first.family === "string" ? first.family : "";
|
|
2852
|
+
const composed = `${given} ${family}`.trim();
|
|
2853
|
+
return composed.length > 0 ? composed : null;
|
|
2854
|
+
}
|
|
2855
|
+
function extractReferenceDisplay(resource, fieldName) {
|
|
2856
|
+
const field = resource[fieldName];
|
|
2857
|
+
if (!field || typeof field !== "object") {
|
|
2858
|
+
return null;
|
|
2859
|
+
}
|
|
2860
|
+
const display = field.display;
|
|
2861
|
+
if (typeof display !== "string") {
|
|
2862
|
+
return null;
|
|
2863
|
+
}
|
|
2864
|
+
const trimmed = display.trim();
|
|
2865
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
2866
|
+
}
|
|
2867
|
+
function ensureAccumulator(byUser, userId) {
|
|
2868
|
+
let acc = byUser.get(userId);
|
|
2869
|
+
if (!acc) {
|
|
2870
|
+
acc = { tenantRole: null, workspaces: /* @__PURE__ */ new Map() };
|
|
2871
|
+
byUser.set(userId, acc);
|
|
2872
|
+
}
|
|
2873
|
+
return acc;
|
|
2874
|
+
}
|
|
2875
|
+
async function tenantUsersOperation(params) {
|
|
2876
|
+
const { context, tableName } = params;
|
|
2877
|
+
const service = getDynamoControlService(tableName);
|
|
2878
|
+
const [memberships, roleAssignments, workspaces] = await Promise.all([
|
|
2879
|
+
listMembershipsOperation({ context, tableName }),
|
|
2880
|
+
listRoleAssignmentsOperation({ context, tableName }),
|
|
2881
|
+
listWorkspacesOperation({ context, tableName })
|
|
2882
|
+
]);
|
|
2883
|
+
const workspaceNames = /* @__PURE__ */ new Map();
|
|
2884
|
+
for (const entry of workspaces.entries) {
|
|
2885
|
+
const resource = entry.resource;
|
|
2886
|
+
const name = typeof resource.name === "string" && resource.name.trim().length > 0 ? resource.name.trim() : null;
|
|
2887
|
+
workspaceNames.set(entry.id, name);
|
|
2888
|
+
}
|
|
2889
|
+
const byUser = /* @__PURE__ */ new Map();
|
|
2890
|
+
for (const entry of memberships.entries) {
|
|
2891
|
+
const resource = entry.resource;
|
|
2892
|
+
const userId = extractReferenceSlug(resource, "user");
|
|
2893
|
+
if (userId === void 0) {
|
|
2894
|
+
continue;
|
|
2895
|
+
}
|
|
2896
|
+
const acc = ensureAccumulator(byUser, userId);
|
|
2897
|
+
const workspaceId = extractReferenceSlug(resource, "workspace");
|
|
2898
|
+
if (workspaceId !== void 0 && !acc.workspaces.has(workspaceId)) {
|
|
2899
|
+
acc.workspaces.set(workspaceId, { workspaceId, role: null });
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
for (const entry of roleAssignments.entries) {
|
|
2903
|
+
const resource = entry.resource;
|
|
2904
|
+
const userId = extractReferenceSlug(resource, "user");
|
|
2905
|
+
const roleId = extractReferenceSlug(resource, "role");
|
|
2906
|
+
if (userId === void 0 || roleId === void 0) {
|
|
2907
|
+
continue;
|
|
2908
|
+
}
|
|
2909
|
+
const acc = ensureAccumulator(byUser, userId);
|
|
2910
|
+
const role = {
|
|
2911
|
+
roleId,
|
|
2912
|
+
roleName: extractReferenceDisplay(resource, "role")
|
|
2913
|
+
};
|
|
2914
|
+
const workspaceId = extractReferenceSlug(resource, "workspace");
|
|
2915
|
+
if (workspaceId === void 0) {
|
|
2916
|
+
acc.tenantRole = role;
|
|
2917
|
+
} else {
|
|
2918
|
+
const existing = acc.workspaces.get(workspaceId);
|
|
2919
|
+
if (existing) {
|
|
2920
|
+
existing.role = role;
|
|
2921
|
+
} else {
|
|
2922
|
+
acc.workspaces.set(workspaceId, { workspaceId, role });
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
const userIds = Array.from(byUser.keys());
|
|
2927
|
+
const userRows = userIds.length === 0 ? [] : await batchGetWithRetry(
|
|
2928
|
+
service.entities.user,
|
|
2929
|
+
userIds.map((id) => ({ id, sk: USER_SK }))
|
|
2930
|
+
);
|
|
2931
|
+
const usersById = /* @__PURE__ */ new Map();
|
|
2932
|
+
for (const row of userRows) {
|
|
2933
|
+
try {
|
|
2934
|
+
usersById.set(
|
|
2935
|
+
row.id,
|
|
2936
|
+
JSON.parse(row.resource)
|
|
2937
|
+
);
|
|
2938
|
+
} catch {
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
const entries = userIds.map((userId) => {
|
|
2942
|
+
const acc = byUser.get(userId);
|
|
2943
|
+
const user = usersById.get(userId);
|
|
2944
|
+
const workspaceEntries = Array.from(
|
|
2945
|
+
acc.workspaces.values()
|
|
2946
|
+
).map((ws) => ({
|
|
2947
|
+
workspaceId: ws.workspaceId,
|
|
2948
|
+
workspaceName: workspaceNames.get(ws.workspaceId) ?? null,
|
|
2949
|
+
role: ws.role
|
|
2950
|
+
}));
|
|
2951
|
+
return {
|
|
2952
|
+
resourceType: "TenantUser",
|
|
2953
|
+
userId,
|
|
2954
|
+
displayName: user ? extractDisplayName(user) : null,
|
|
2955
|
+
email: user ? extractEmail(user) : null,
|
|
2956
|
+
tenantRole: acc.tenantRole,
|
|
2957
|
+
workspaces: workspaceEntries
|
|
2958
|
+
};
|
|
2959
|
+
});
|
|
2960
|
+
return { entries };
|
|
2961
|
+
}
|
|
2962
|
+
|
|
2963
|
+
// src/data/rest-api/routes/control/tenant/tenant-list-users-route.ts
|
|
2964
|
+
async function listTenantUsersRoute(req, res) {
|
|
2965
|
+
const ctx = req.openhiContext;
|
|
2966
|
+
if (!ctx) {
|
|
2967
|
+
return sendForbidden403(
|
|
2968
|
+
res,
|
|
2969
|
+
"Missing or invalid OpenHI JWT claims (tenant, workspace, or audit context)."
|
|
2970
|
+
);
|
|
2971
|
+
}
|
|
2972
|
+
const tenantId = String(req.params.id);
|
|
2973
|
+
if (tenantId.length === 0) {
|
|
2974
|
+
return sendForbidden403(res, "Tenant id is required.");
|
|
2975
|
+
}
|
|
2976
|
+
const parsed = parseCommonListQuery(req, res);
|
|
2977
|
+
if (!parsed.ok) {
|
|
2978
|
+
return parsed.response;
|
|
2979
|
+
}
|
|
2980
|
+
const scopedContext = { ...ctx, tenantId };
|
|
2981
|
+
try {
|
|
2982
|
+
const result = await tenantUsersOperation({ context: scopedContext });
|
|
2983
|
+
const basePath = `${BASE_PATH.TENANT}/${tenantId}/users`;
|
|
2984
|
+
const entries = result.entries.map((entry) => ({
|
|
2985
|
+
fullUrl: `${BASE_PATH.USER}/${entry.userId}`,
|
|
2986
|
+
resource: entry
|
|
2987
|
+
}));
|
|
2988
|
+
return res.json({
|
|
2989
|
+
resourceType: "Bundle",
|
|
2990
|
+
type: "searchset",
|
|
2991
|
+
total: entries.length,
|
|
2992
|
+
link: [{ relation: "self", url: basePath }],
|
|
2993
|
+
entry: entries
|
|
2994
|
+
});
|
|
2995
|
+
} catch (err) {
|
|
2996
|
+
return sendOperationOutcome500(res, err, "GET /Tenant/:id/users error:");
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
|
|
2681
3000
|
// src/data/operations/control/tenant/tenant-update-operation.ts
|
|
2682
3001
|
import { extractSummary as extractSummary4 } from "@openhi/types";
|
|
2683
3002
|
async function updateTenantOperation(params) {
|
|
@@ -2745,6 +3064,7 @@ async function updateTenantRoute(req, res) {
|
|
|
2745
3064
|
// src/data/rest-api/routes/control/tenant/tenant.ts
|
|
2746
3065
|
var router6 = express6.Router();
|
|
2747
3066
|
router6.get("/", listTenantsRoute);
|
|
3067
|
+
router6.get("/:id/users", listTenantUsersRoute);
|
|
2748
3068
|
router6.get("/:id", getTenantByIdRoute);
|
|
2749
3069
|
router6.post("/", createTenantRoute);
|
|
2750
3070
|
router6.put("/:id", updateTenantRoute);
|
|
@@ -2892,125 +3212,6 @@ async function configurationListByWorkspaceOperation(params) {
|
|
|
2892
3212
|
return { items, cursor: result.cursor ?? null };
|
|
2893
3213
|
}
|
|
2894
3214
|
|
|
2895
|
-
// src/data/rest-api/routes/control/cross-cutting-route-helpers.ts
|
|
2896
|
-
function sendInvalidQuery400(res, diagnostics) {
|
|
2897
|
-
return res.status(400).json({
|
|
2898
|
-
resourceType: "OperationOutcome",
|
|
2899
|
-
issue: [{ severity: "error", code: "invalid", diagnostics }]
|
|
2900
|
-
});
|
|
2901
|
-
}
|
|
2902
|
-
function sendForbidden403(res, diagnostics) {
|
|
2903
|
-
return res.status(403).json({
|
|
2904
|
-
resourceType: "OperationOutcome",
|
|
2905
|
-
issue: [{ severity: "error", code: "forbidden", diagnostics }]
|
|
2906
|
-
});
|
|
2907
|
-
}
|
|
2908
|
-
var COMMON_KEYS = ["cursor", "limit", "order"];
|
|
2909
|
-
function parseCommonListQuery(req, res, options = {}) {
|
|
2910
|
-
const q = req.query ?? {};
|
|
2911
|
-
const allowedKeys = /* @__PURE__ */ new Set([
|
|
2912
|
-
...COMMON_KEYS,
|
|
2913
|
-
...options.extraKeys ?? []
|
|
2914
|
-
]);
|
|
2915
|
-
const extra = Object.keys(q).filter((k) => !allowedKeys.has(k));
|
|
2916
|
-
if (extra.length > 0) {
|
|
2917
|
-
return {
|
|
2918
|
-
ok: false,
|
|
2919
|
-
response: sendInvalidQuery400(
|
|
2920
|
-
res,
|
|
2921
|
-
`Unsupported query parameter${extra.length === 1 ? "" : "s"}: ${extra.join(", ")}.`
|
|
2922
|
-
)
|
|
2923
|
-
};
|
|
2924
|
-
}
|
|
2925
|
-
const rawCursor = q.cursor;
|
|
2926
|
-
let cursor = null;
|
|
2927
|
-
if (rawCursor !== void 0) {
|
|
2928
|
-
if (typeof rawCursor !== "string") {
|
|
2929
|
-
return {
|
|
2930
|
-
ok: false,
|
|
2931
|
-
response: sendInvalidQuery400(
|
|
2932
|
-
res,
|
|
2933
|
-
"Query parameter `cursor` must be a string."
|
|
2934
|
-
)
|
|
2935
|
-
};
|
|
2936
|
-
}
|
|
2937
|
-
cursor = rawCursor;
|
|
2938
|
-
}
|
|
2939
|
-
const rawLimit = q.limit;
|
|
2940
|
-
let limit;
|
|
2941
|
-
if (rawLimit !== void 0) {
|
|
2942
|
-
if (typeof rawLimit !== "string" || rawLimit.length === 0) {
|
|
2943
|
-
return {
|
|
2944
|
-
ok: false,
|
|
2945
|
-
response: sendInvalidQuery400(
|
|
2946
|
-
res,
|
|
2947
|
-
"Query parameter `limit` must be a positive integer."
|
|
2948
|
-
)
|
|
2949
|
-
};
|
|
2950
|
-
}
|
|
2951
|
-
const parsed = Number(rawLimit);
|
|
2952
|
-
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
2953
|
-
return {
|
|
2954
|
-
ok: false,
|
|
2955
|
-
response: sendInvalidQuery400(
|
|
2956
|
-
res,
|
|
2957
|
-
"Query parameter `limit` must be a positive integer."
|
|
2958
|
-
)
|
|
2959
|
-
};
|
|
2960
|
-
}
|
|
2961
|
-
limit = parsed;
|
|
2962
|
-
}
|
|
2963
|
-
const rawOrder = q.order;
|
|
2964
|
-
let order;
|
|
2965
|
-
if (rawOrder !== void 0) {
|
|
2966
|
-
if (rawOrder !== "asc" && rawOrder !== "desc") {
|
|
2967
|
-
return {
|
|
2968
|
-
ok: false,
|
|
2969
|
-
response: sendInvalidQuery400(
|
|
2970
|
-
res,
|
|
2971
|
-
'Query parameter `order` must be one of "asc", "desc".'
|
|
2972
|
-
)
|
|
2973
|
-
};
|
|
2974
|
-
}
|
|
2975
|
-
order = rawOrder;
|
|
2976
|
-
}
|
|
2977
|
-
const value = order === void 0 ? limit === void 0 ? { cursor } : { cursor, limit } : limit === void 0 ? { cursor, order } : { cursor, limit, order };
|
|
2978
|
-
return { ok: true, value };
|
|
2979
|
-
}
|
|
2980
|
-
function buildPaginationLinks(opts) {
|
|
2981
|
-
const links = [
|
|
2982
|
-
{ relation: "self", url: composeUrl(opts.basePath, opts.query) }
|
|
2983
|
-
];
|
|
2984
|
-
if (opts.nextCursor !== null && opts.nextCursor.length > 0) {
|
|
2985
|
-
const nextQuery = { ...opts.query };
|
|
2986
|
-
nextQuery.cursor = opts.nextCursor;
|
|
2987
|
-
links.push({
|
|
2988
|
-
relation: "next",
|
|
2989
|
-
url: composeUrl(opts.basePath, nextQuery)
|
|
2990
|
-
});
|
|
2991
|
-
}
|
|
2992
|
-
return links;
|
|
2993
|
-
}
|
|
2994
|
-
function composeUrl(basePath, query) {
|
|
2995
|
-
const usp = new URLSearchParams();
|
|
2996
|
-
for (const [key, value] of Object.entries(query)) {
|
|
2997
|
-
if (value === void 0 || value === null) {
|
|
2998
|
-
continue;
|
|
2999
|
-
}
|
|
3000
|
-
if (Array.isArray(value)) {
|
|
3001
|
-
for (const v of value) {
|
|
3002
|
-
if (v !== void 0 && v !== null) {
|
|
3003
|
-
usp.append(key, String(v));
|
|
3004
|
-
}
|
|
3005
|
-
}
|
|
3006
|
-
} else {
|
|
3007
|
-
usp.append(key, String(value));
|
|
3008
|
-
}
|
|
3009
|
-
}
|
|
3010
|
-
const qs = usp.toString();
|
|
3011
|
-
return qs.length === 0 ? basePath : `${basePath}?${qs}`;
|
|
3012
|
-
}
|
|
3013
|
-
|
|
3014
3215
|
// src/data/rest-api/routes/control/projection-bundle-helpers.ts
|
|
3015
3216
|
var EXT_BASE = "https://openhi.org/fhir/StructureDefinition";
|
|
3016
3217
|
function parseProjectionSummary(summary) {
|
|
@@ -3267,41 +3468,6 @@ async function listUserConfigurationsRoute(req, res) {
|
|
|
3267
3468
|
}
|
|
3268
3469
|
}
|
|
3269
3470
|
|
|
3270
|
-
// src/data/operations/control/membership/membership-list-by-workspace-operation.ts
|
|
3271
|
-
async function membershipListByWorkspaceOperation(params) {
|
|
3272
|
-
const {
|
|
3273
|
-
tenantId,
|
|
3274
|
-
workspaceId,
|
|
3275
|
-
cursor = null,
|
|
3276
|
-
limit,
|
|
3277
|
-
order,
|
|
3278
|
-
tableName
|
|
3279
|
-
} = params;
|
|
3280
|
-
const service = getDynamoControlService(tableName);
|
|
3281
|
-
const goOptions = {
|
|
3282
|
-
cursor
|
|
3283
|
-
};
|
|
3284
|
-
if (limit !== void 0) {
|
|
3285
|
-
goOptions.limit = limit;
|
|
3286
|
-
}
|
|
3287
|
-
if (order !== void 0) {
|
|
3288
|
-
goOptions.order = order;
|
|
3289
|
-
}
|
|
3290
|
-
const result = await service.entities.membershipWorkspaceProjection.query.record({ tenantId, workspaceId }).begins({ sk: "MEMBERSHIP#" }).go(goOptions);
|
|
3291
|
-
const items = (result.data ?? []).map((row) => ({
|
|
3292
|
-
tenantId: row.tenantId,
|
|
3293
|
-
workspaceId: row.workspaceId,
|
|
3294
|
-
sk: row.sk,
|
|
3295
|
-
userId: row.userId,
|
|
3296
|
-
membershipId: row.membershipId,
|
|
3297
|
-
summary: row.summary,
|
|
3298
|
-
vid: row.vid,
|
|
3299
|
-
lastUpdated: row.lastUpdated,
|
|
3300
|
-
denormalizedUserName: row.denormalizedUserName
|
|
3301
|
-
}));
|
|
3302
|
-
return { items, cursor: result.cursor ?? null };
|
|
3303
|
-
}
|
|
3304
|
-
|
|
3305
3471
|
// src/data/rest-api/routes/control/user/user-list-memberships-route.ts
|
|
3306
3472
|
var ALLOWED_MODES = [
|
|
3307
3473
|
"all",
|
|
@@ -3325,7 +3491,7 @@ async function listUserMembershipsRoute(req, res) {
|
|
|
3325
3491
|
);
|
|
3326
3492
|
}
|
|
3327
3493
|
const parsed = parseCommonListQuery(req, res, {
|
|
3328
|
-
extraKeys: ["mode", "tenantId"]
|
|
3494
|
+
extraKeys: ["mode", "tenantId", "_summary"]
|
|
3329
3495
|
});
|
|
3330
3496
|
if (!parsed.ok) {
|
|
3331
3497
|
return parsed.response;
|
|
@@ -3358,6 +3524,33 @@ async function listUserMembershipsRoute(req, res) {
|
|
|
3358
3524
|
'Query parameter `tenantId` is required when `mode === "workspaceInTenant"`.'
|
|
3359
3525
|
);
|
|
3360
3526
|
}
|
|
3527
|
+
const rawSummary = req.query._summary;
|
|
3528
|
+
if (rawSummary !== void 0) {
|
|
3529
|
+
if (rawSummary !== "count") {
|
|
3530
|
+
return sendInvalidQuery400(
|
|
3531
|
+
res,
|
|
3532
|
+
'Query parameter `_summary` must be "count" on this endpoint.'
|
|
3533
|
+
);
|
|
3534
|
+
}
|
|
3535
|
+
try {
|
|
3536
|
+
const total = await countMembershipsByUserOperation({
|
|
3537
|
+
userId,
|
|
3538
|
+
mode,
|
|
3539
|
+
tenantId
|
|
3540
|
+
});
|
|
3541
|
+
return res.json({
|
|
3542
|
+
resourceType: "Bundle",
|
|
3543
|
+
type: "searchset",
|
|
3544
|
+
total
|
|
3545
|
+
});
|
|
3546
|
+
} catch (err) {
|
|
3547
|
+
return sendOperationOutcome500(
|
|
3548
|
+
res,
|
|
3549
|
+
err,
|
|
3550
|
+
"GET /User/:id/Membership count error:"
|
|
3551
|
+
);
|
|
3552
|
+
}
|
|
3553
|
+
}
|
|
3361
3554
|
try {
|
|
3362
3555
|
const result = await membershipListByUserOperation({
|
|
3363
3556
|
userId,
|
|
@@ -3454,51 +3647,6 @@ async function roleAssignmentListByUserOperation(params) {
|
|
|
3454
3647
|
return { items, cursor: result.cursor ?? null };
|
|
3455
3648
|
}
|
|
3456
3649
|
|
|
3457
|
-
// src/data/operations/control/roleassignment/roleassignment-list-by-workspace-operation.ts
|
|
3458
|
-
function buildSkPrefix2(roleId) {
|
|
3459
|
-
if (roleId === void 0 || roleId.length === 0) {
|
|
3460
|
-
return "ROLEASSIGNMENT#";
|
|
3461
|
-
}
|
|
3462
|
-
return `ROLEASSIGNMENT#${roleId}#`;
|
|
3463
|
-
}
|
|
3464
|
-
async function roleAssignmentListByWorkspaceOperation(params) {
|
|
3465
|
-
const {
|
|
3466
|
-
tenantId,
|
|
3467
|
-
workspaceId,
|
|
3468
|
-
roleId,
|
|
3469
|
-
cursor = null,
|
|
3470
|
-
limit,
|
|
3471
|
-
order,
|
|
3472
|
-
tableName
|
|
3473
|
-
} = params;
|
|
3474
|
-
const service = getDynamoControlService(tableName);
|
|
3475
|
-
const skPrefix = buildSkPrefix2(roleId);
|
|
3476
|
-
const goOptions = {
|
|
3477
|
-
cursor
|
|
3478
|
-
};
|
|
3479
|
-
if (limit !== void 0) {
|
|
3480
|
-
goOptions.limit = limit;
|
|
3481
|
-
}
|
|
3482
|
-
if (order !== void 0) {
|
|
3483
|
-
goOptions.order = order;
|
|
3484
|
-
}
|
|
3485
|
-
const result = await service.entities.roleAssignmentWorkspaceProjection.query.record({ tenantId, workspaceId }).begins({ sk: skPrefix }).go(goOptions);
|
|
3486
|
-
const items = (result.data ?? []).map((row) => ({
|
|
3487
|
-
tenantId: row.tenantId,
|
|
3488
|
-
workspaceId: row.workspaceId,
|
|
3489
|
-
sk: row.sk,
|
|
3490
|
-
userId: row.userId,
|
|
3491
|
-
roleId: row.roleId,
|
|
3492
|
-
roleAssignmentId: row.roleAssignmentId,
|
|
3493
|
-
summary: row.summary,
|
|
3494
|
-
vid: row.vid,
|
|
3495
|
-
lastUpdated: row.lastUpdated,
|
|
3496
|
-
denormalizedUserName: row.denormalizedUserName,
|
|
3497
|
-
denormalizedRoleName: row.denormalizedRoleName
|
|
3498
|
-
}));
|
|
3499
|
-
return { items, cursor: result.cursor ?? null };
|
|
3500
|
-
}
|
|
3501
|
-
|
|
3502
3650
|
// src/data/rest-api/routes/control/user/user-list-role-assignments-route.ts
|
|
3503
3651
|
var ALLOWED_MODES2 = [
|
|
3504
3652
|
"all",
|
|
@@ -4111,12 +4259,20 @@ async function deleteWorkspaceOperation(params) {
|
|
|
4111
4259
|
const { context, id, tableName } = params;
|
|
4112
4260
|
const { tenantId } = context;
|
|
4113
4261
|
const service = getDynamoControlService(tableName);
|
|
4262
|
+
const existing = await service.entities.workspace.get({ tenantId, id, sk: "CURRENT" }).go();
|
|
4263
|
+
const workspaceExisted = existing.data !== null;
|
|
4114
4264
|
await service.entities.workspace.delete({ tenantId, id, sk: "CURRENT" }).go();
|
|
4115
4265
|
await deleteOrganizationOperation({
|
|
4116
4266
|
context: { ...context, workspaceId: id },
|
|
4117
4267
|
id,
|
|
4118
4268
|
tableName
|
|
4119
4269
|
});
|
|
4270
|
+
if (workspaceExisted) {
|
|
4271
|
+
await publishWorkspaceDeleted(context, {
|
|
4272
|
+
workspaceId: id,
|
|
4273
|
+
tenantId
|
|
4274
|
+
});
|
|
4275
|
+
}
|
|
4120
4276
|
}
|
|
4121
4277
|
|
|
4122
4278
|
// src/data/rest-api/routes/control/workspace/workspace-delete-route.ts
|
|
@@ -4382,51 +4538,19 @@ async function listWorkspaceRoleAssignmentsRoute(req, res) {
|
|
|
4382
4538
|
}
|
|
4383
4539
|
}
|
|
4384
4540
|
|
|
4385
|
-
// src/data/operations/control/workspace/workspace-list-operation.ts
|
|
4386
|
-
var SK8 = "CURRENT";
|
|
4387
|
-
async function listWorkspacesOperation(params) {
|
|
4388
|
-
const { context, tableName, mode = "full" } = params;
|
|
4389
|
-
const { tenantId } = context;
|
|
4390
|
-
const service = getDynamoControlService(tableName);
|
|
4391
|
-
const shardResults = await Promise.all(
|
|
4392
|
-
Array.from(
|
|
4393
|
-
{ length: SHARD_COUNT },
|
|
4394
|
-
(_, shard) => service.entities.workspace.query.gsi1({ tenantId, gsi1Shard: String(shard) }).go()
|
|
4395
|
-
)
|
|
4396
|
-
);
|
|
4397
|
-
return dispatchListMode(
|
|
4398
|
-
mode,
|
|
4399
|
-
shardResults,
|
|
4400
|
-
{
|
|
4401
|
-
hydrate: (orderedIds) => batchGetWithRetry(
|
|
4402
|
-
service.entities.workspace,
|
|
4403
|
-
orderedIds.map((id) => ({ tenantId, id, sk: SK8 }))
|
|
4404
|
-
),
|
|
4405
|
-
getId: (item) => item.id,
|
|
4406
|
-
buildEntry: (id, item) => ({
|
|
4407
|
-
id,
|
|
4408
|
-
resource: {
|
|
4409
|
-
resourceType: "Workspace",
|
|
4410
|
-
id,
|
|
4411
|
-
...JSON.parse(item.resource)
|
|
4412
|
-
}
|
|
4413
|
-
}),
|
|
4414
|
-
buildSummaryEntry: (id, parsed) => ({
|
|
4415
|
-
id,
|
|
4416
|
-
resource: { resourceType: "Workspace", id, ...parsed }
|
|
4417
|
-
})
|
|
4418
|
-
}
|
|
4419
|
-
);
|
|
4420
|
-
}
|
|
4421
|
-
|
|
4422
4541
|
// src/data/rest-api/routes/control/workspace/workspace-list-route.ts
|
|
4423
4542
|
async function listWorkspacesRoute(req, res) {
|
|
4543
|
+
const scope = resolveTenantScopeOverride(req, res, req.openhiContext);
|
|
4544
|
+
if (!scope.ok) {
|
|
4545
|
+
return scope.response;
|
|
4546
|
+
}
|
|
4424
4547
|
return handleListRoute({
|
|
4425
4548
|
req,
|
|
4426
4549
|
res,
|
|
4427
4550
|
basePath: BASE_PATH.WORKSPACE,
|
|
4428
4551
|
listOperation: listWorkspacesOperation,
|
|
4429
|
-
errorLogContext: "GET /Workspace list error:"
|
|
4552
|
+
errorLogContext: "GET /Workspace list error:",
|
|
4553
|
+
context: scope.context
|
|
4430
4554
|
});
|
|
4431
4555
|
}
|
|
4432
4556
|
|