@memberjunction/server 3.4.0 → 4.1.0
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 +689 -513
- package/dist/agents/skip-agent.d.ts +65 -0
- package/dist/agents/skip-agent.d.ts.map +1 -1
- package/dist/agents/skip-agent.js +63 -5
- package/dist/agents/skip-agent.js.map +1 -1
- package/dist/agents/skip-sdk.d.ts +163 -0
- package/dist/agents/skip-sdk.d.ts.map +1 -1
- package/dist/agents/skip-sdk.js +143 -12
- package/dist/agents/skip-sdk.js.map +1 -1
- package/dist/apolloServer/index.d.ts +0 -1
- package/dist/apolloServer/index.d.ts.map +1 -1
- package/dist/auth/APIKeyScopeAuth.d.ts +82 -0
- package/dist/auth/APIKeyScopeAuth.d.ts.map +1 -1
- package/dist/auth/APIKeyScopeAuth.js +78 -0
- package/dist/auth/APIKeyScopeAuth.js.map +1 -1
- package/dist/auth/AuthProviderFactory.d.ts +35 -0
- package/dist/auth/AuthProviderFactory.d.ts.map +1 -1
- package/dist/auth/AuthProviderFactory.js +51 -4
- package/dist/auth/AuthProviderFactory.js.map +1 -1
- package/dist/auth/BaseAuthProvider.d.ts +21 -0
- package/dist/auth/BaseAuthProvider.d.ts.map +1 -1
- package/dist/auth/BaseAuthProvider.js +24 -9
- package/dist/auth/BaseAuthProvider.js.map +1 -1
- package/dist/auth/IAuthProvider.d.ts +32 -0
- package/dist/auth/IAuthProvider.d.ts.map +1 -1
- package/dist/auth/exampleNewUserSubClass.d.ts +5 -1
- package/dist/auth/exampleNewUserSubClass.d.ts.map +1 -1
- package/dist/auth/exampleNewUserSubClass.js +21 -6
- package/dist/auth/exampleNewUserSubClass.js.map +1 -1
- package/dist/auth/index.d.ts +14 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +35 -22
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.d.ts +3 -0
- package/dist/auth/initializeProviders.d.ts.map +1 -1
- package/dist/auth/initializeProviders.js +6 -0
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +14 -3
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/auth/providers/Auth0Provider.d.ts +9 -0
- package/dist/auth/providers/Auth0Provider.d.ts.map +1 -1
- package/dist/auth/providers/Auth0Provider.js +10 -0
- package/dist/auth/providers/Auth0Provider.js.map +1 -1
- package/dist/auth/providers/CognitoProvider.d.ts +9 -0
- package/dist/auth/providers/CognitoProvider.d.ts.map +1 -1
- package/dist/auth/providers/CognitoProvider.js +10 -0
- package/dist/auth/providers/CognitoProvider.js.map +1 -1
- package/dist/auth/providers/GoogleProvider.d.ts +9 -0
- package/dist/auth/providers/GoogleProvider.d.ts.map +1 -1
- package/dist/auth/providers/GoogleProvider.js +11 -1
- package/dist/auth/providers/GoogleProvider.js.map +1 -1
- package/dist/auth/providers/MSALProvider.d.ts +9 -0
- package/dist/auth/providers/MSALProvider.d.ts.map +1 -1
- package/dist/auth/providers/MSALProvider.js +10 -0
- package/dist/auth/providers/MSALProvider.js.map +1 -1
- package/dist/auth/providers/OktaProvider.d.ts +9 -0
- package/dist/auth/providers/OktaProvider.d.ts.map +1 -1
- package/dist/auth/providers/OktaProvider.js +10 -0
- package/dist/auth/providers/OktaProvider.js.map +1 -1
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +42 -8
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +8 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +26 -4
- package/dist/context.js.map +1 -1
- package/dist/directives/Public.js +2 -0
- package/dist/directives/Public.js.map +1 -1
- package/dist/entitySubclasses/entityPermissions.server.d.ts +7 -2
- package/dist/entitySubclasses/entityPermissions.server.d.ts.map +1 -1
- package/dist/entitySubclasses/entityPermissions.server.js +26 -8
- package/dist/entitySubclasses/entityPermissions.server.js.map +1 -1
- package/dist/generated/generated.d.ts +539 -2
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +9985 -14951
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/DeleteOptionsInput.d.ts +3 -0
- package/dist/generic/DeleteOptionsInput.d.ts.map +1 -1
- package/dist/generic/DeleteOptionsInput.js +3 -2
- package/dist/generic/DeleteOptionsInput.js.map +1 -1
- package/dist/generic/KeyInputOutputTypes.js +0 -6
- package/dist/generic/KeyInputOutputTypes.js.map +1 -1
- package/dist/generic/KeyValuePairInput.d.ts +4 -0
- package/dist/generic/KeyValuePairInput.d.ts.map +1 -1
- package/dist/generic/KeyValuePairInput.js +4 -2
- package/dist/generic/KeyValuePairInput.js.map +1 -1
- package/dist/generic/PushStatusResolver.js +0 -3
- package/dist/generic/PushStatusResolver.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +58 -0
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +203 -18
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +22 -0
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +42 -108
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +94 -37
- package/dist/index.js.map +1 -1
- package/dist/orm.d.ts.map +1 -1
- package/dist/orm.js +2 -1
- package/dist/orm.js.map +1 -1
- package/dist/resolvers/APIKeyResolver.d.ts +74 -0
- package/dist/resolvers/APIKeyResolver.d.ts.map +1 -1
- package/dist/resolvers/APIKeyResolver.js +49 -10
- package/dist/resolvers/APIKeyResolver.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +189 -0
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +152 -21
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/ColorResolver.js +0 -5
- package/dist/resolvers/ColorResolver.js.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.d.ts +65 -0
- package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.js +118 -40
- package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
- package/dist/resolvers/CreateQueryResolver.d.ts +47 -0
- package/dist/resolvers/CreateQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/CreateQueryResolver.js +92 -116
- package/dist/resolvers/CreateQueryResolver.js.map +1 -1
- package/dist/resolvers/DatasetResolver.js +2 -14
- package/dist/resolvers/DatasetResolver.js.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts +40 -0
- package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.js +2 -36
- package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +0 -7
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
- package/dist/resolvers/FileCategoryResolver.js +15 -3
- package/dist/resolvers/FileCategoryResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +16 -0
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +59 -74
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts +18 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.js +17 -9
- package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts +19 -0
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +35 -35
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/InfoResolver.d.ts +2 -2
- package/dist/resolvers/InfoResolver.d.ts.map +1 -1
- package/dist/resolvers/InfoResolver.js +17 -20
- package/dist/resolvers/InfoResolver.js.map +1 -1
- package/dist/resolvers/MCPResolver.d.ts +325 -1
- package/dist/resolvers/MCPResolver.d.ts.map +1 -1
- package/dist/resolvers/MCPResolver.js +931 -24
- package/dist/resolvers/MCPResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +3 -29
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts.map +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.js +0 -3
- package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts +20 -0
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +44 -36
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/ReportResolver.d.ts +3 -0
- package/dist/resolvers/ReportResolver.d.ts.map +1 -1
- package/dist/resolvers/ReportResolver.js +9 -10
- package/dist/resolvers/ReportResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +54 -0
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +116 -40
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts +42 -0
- package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +95 -22
- package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +9 -6
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/RunTestResolver.d.ts +12 -0
- package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTestResolver.js +35 -21
- package/dist/resolvers/RunTestResolver.js.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts +312 -0
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +295 -45
- package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts +21 -0
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +36 -22
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.d.ts +14 -0
- package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.js +54 -21
- package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
- package/dist/resolvers/TaskResolver.d.ts +13 -0
- package/dist/resolvers/TaskResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskResolver.js +22 -7
- package/dist/resolvers/TaskResolver.js.map +1 -1
- package/dist/resolvers/TelemetryResolver.d.ts +22 -0
- package/dist/resolvers/TelemetryResolver.d.ts.map +1 -1
- package/dist/resolvers/TelemetryResolver.js +45 -79
- package/dist/resolvers/TelemetryResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +11 -13
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.js +3 -12
- package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
- package/dist/resolvers/UserResolver.js +10 -0
- package/dist/resolvers/UserResolver.js.map +1 -1
- package/dist/resolvers/UserViewResolver.js +4 -0
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/dist/resolvers/VersionHistoryResolver.d.ts +39 -0
- package/dist/resolvers/VersionHistoryResolver.d.ts.map +1 -0
- package/dist/resolvers/VersionHistoryResolver.js +208 -0
- package/dist/resolvers/VersionHistoryResolver.js.map +1 -0
- package/dist/rest/EntityCRUDHandler.d.ts +19 -0
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +55 -0
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/OAuthCallbackHandler.d.ts +143 -0
- package/dist/rest/OAuthCallbackHandler.d.ts.map +1 -0
- package/dist/rest/OAuthCallbackHandler.js +634 -0
- package/dist/rest/OAuthCallbackHandler.js.map +1 -0
- package/dist/rest/RESTEndpointHandler.d.ts +120 -0
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +213 -24
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +19 -0
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +39 -0
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/rest/index.d.ts +1 -0
- package/dist/rest/index.d.ts.map +1 -1
- package/dist/rest/index.js +1 -0
- package/dist/rest/index.js.map +1 -1
- package/dist/rest/setupRESTEndpoints.d.ts +35 -0
- package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
- package/dist/rest/setupRESTEndpoints.js +15 -1
- package/dist/rest/setupRESTEndpoints.js.map +1 -1
- package/dist/services/ScheduledJobsService.d.ts +31 -0
- package/dist/services/ScheduledJobsService.d.ts.map +1 -1
- package/dist/services/ScheduledJobsService.js +38 -4
- package/dist/services/ScheduledJobsService.js.map +1 -1
- package/dist/services/TaskOrchestrator.d.ts +73 -0
- package/dist/services/TaskOrchestrator.d.ts.map +1 -1
- package/dist/services/TaskOrchestrator.js +137 -15
- package/dist/services/TaskOrchestrator.js.map +1 -1
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -13
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +37 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +55 -8
- package/dist/util.js.map +1 -1
- package/package.json +83 -78
- package/src/auth/exampleNewUserSubClass.ts +1 -5
- package/src/auth/newUsers.ts +4 -2
- package/src/entitySubclasses/entityPermissions.server.ts +1 -3
- package/src/generated/generated.ts +4707 -2664
- package/src/index.ts +73 -62
- package/src/resolvers/FileCategoryResolver.ts +1 -1
- package/src/resolvers/InfoResolver.ts +10 -6
- package/src/resolvers/MCPResolver.ts +910 -10
- package/src/resolvers/PotentialDuplicateRecordResolver.ts +0 -4
- package/src/resolvers/VersionHistoryResolver.ts +177 -0
- package/src/rest/OAuthCallbackHandler.ts +766 -0
- package/src/rest/RESTEndpointHandler.ts +58 -35
- package/src/rest/index.ts +2 -1
- package/src/rest/setupRESTEndpoints.ts +13 -12
|
@@ -2,31 +2,55 @@ import express from 'express';
|
|
|
2
2
|
import { CompositeKey, EntityDeleteOptions, LogError, Metadata } from '@memberjunction/core';
|
|
3
3
|
import { EntityCRUDHandler } from './EntityCRUDHandler.js';
|
|
4
4
|
import { ViewOperationsHandler } from './ViewOperationsHandler.js';
|
|
5
|
+
/**
|
|
6
|
+
* RESTEndpointHandler provides REST API functionality for MemberJunction entities
|
|
7
|
+
* This class handles request routing and processing for a /rest endpoint that exposes
|
|
8
|
+
* entity operations via REST instead of GraphQL
|
|
9
|
+
*/
|
|
5
10
|
export class RESTEndpointHandler {
|
|
6
|
-
router;
|
|
7
|
-
options;
|
|
8
11
|
constructor(options = {}) {
|
|
9
12
|
this.router = express.Router();
|
|
10
13
|
this.options = options;
|
|
11
14
|
this.setupRoutes();
|
|
12
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Helper to safely extract a string from Express route params
|
|
18
|
+
* Express 5.x types params as string | string[] | undefined
|
|
19
|
+
*/
|
|
20
|
+
getStringParam(param) {
|
|
21
|
+
if (Array.isArray(param)) {
|
|
22
|
+
return param[0] || '';
|
|
23
|
+
}
|
|
24
|
+
return param || '';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Determines if an entity is allowed based on include/exclude lists
|
|
28
|
+
* with support for wildcards and schema-level filtering
|
|
29
|
+
* @param entityName The name of the entity to check
|
|
30
|
+
* @returns True if the entity is allowed, false otherwise
|
|
31
|
+
*/
|
|
13
32
|
isEntityAllowed(entityName) {
|
|
14
33
|
const name = entityName.toLowerCase();
|
|
15
34
|
const md = new Metadata();
|
|
16
35
|
const entity = md.Entities.find(e => e.Name.toLowerCase() === name);
|
|
36
|
+
// If entity not found in metadata, don't allow it
|
|
17
37
|
if (!entity) {
|
|
18
38
|
return false;
|
|
19
39
|
}
|
|
20
40
|
const schemaName = entity.SchemaName.toLowerCase();
|
|
41
|
+
// 1. Check schema exclusions first (these take highest precedence)
|
|
21
42
|
if (this.options.excludeSchemas && this.options.excludeSchemas.length > 0) {
|
|
22
43
|
if (this.options.excludeSchemas.some(schema => schema.toLowerCase() === schemaName)) {
|
|
23
44
|
return false;
|
|
24
45
|
}
|
|
25
46
|
}
|
|
47
|
+
// 2. Check entity exclusions next (these override entity inclusions)
|
|
26
48
|
if (this.options.excludeEntities && this.options.excludeEntities.length > 0) {
|
|
49
|
+
// Check for direct match
|
|
27
50
|
if (this.options.excludeEntities.includes(name)) {
|
|
28
51
|
return false;
|
|
29
52
|
}
|
|
53
|
+
// Check for wildcard matches
|
|
30
54
|
for (const pattern of this.options.excludeEntities) {
|
|
31
55
|
if (pattern.includes('*')) {
|
|
32
56
|
const regex = new RegExp('^' + pattern.toLowerCase().replace(/\*/g, '.*') + '$');
|
|
@@ -36,15 +60,19 @@ export class RESTEndpointHandler {
|
|
|
36
60
|
}
|
|
37
61
|
}
|
|
38
62
|
}
|
|
63
|
+
// 3. Check schema inclusions (if specified, only entities from these schemas are allowed)
|
|
39
64
|
if (this.options.includeSchemas && this.options.includeSchemas.length > 0) {
|
|
40
65
|
if (!this.options.includeSchemas.some(schema => schema.toLowerCase() === schemaName)) {
|
|
41
66
|
return false;
|
|
42
67
|
}
|
|
43
68
|
}
|
|
69
|
+
// 4. Check entity inclusions
|
|
44
70
|
if (this.options.includeEntities && this.options.includeEntities.length > 0) {
|
|
71
|
+
// Check for direct match
|
|
45
72
|
if (this.options.includeEntities.includes(name)) {
|
|
46
73
|
return true;
|
|
47
74
|
}
|
|
75
|
+
// Check for wildcard matches
|
|
48
76
|
for (const pattern of this.options.includeEntities) {
|
|
49
77
|
if (pattern.includes('*')) {
|
|
50
78
|
const regex = new RegExp('^' + pattern.toLowerCase().replace(/\*/g, '.*') + '$');
|
|
@@ -53,41 +81,61 @@ export class RESTEndpointHandler {
|
|
|
53
81
|
}
|
|
54
82
|
}
|
|
55
83
|
}
|
|
84
|
+
// If include list is specified but no matches found, entity is not allowed
|
|
56
85
|
return false;
|
|
57
86
|
}
|
|
87
|
+
// By default, allow all entities
|
|
58
88
|
return true;
|
|
59
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Set up all the API routes for the REST endpoints
|
|
92
|
+
*/
|
|
60
93
|
setupRoutes() {
|
|
94
|
+
// Middleware to extract MJ user
|
|
61
95
|
this.router.use(this.extractMJUser);
|
|
96
|
+
// Middleware to check entity allowlist/blocklist
|
|
62
97
|
this.router.use('/entities/:entityName', this.checkEntityAccess.bind(this));
|
|
63
98
|
this.router.use('/views/:entityName', this.checkEntityAccess.bind(this));
|
|
64
99
|
this.router.use('/metadata/entities/:entityName', this.checkEntityAccess.bind(this));
|
|
65
100
|
this.router.use('/users/:userId/favorites/:entityName', this.checkEntityAccess.bind(this));
|
|
101
|
+
// Entity collection operations
|
|
66
102
|
this.router.get('/entities/:entityName', this.getEntityList.bind(this));
|
|
67
103
|
this.router.post('/entities/:entityName', this.createEntity.bind(this));
|
|
104
|
+
// Individual entity operations
|
|
68
105
|
this.router.get('/entities/:entityName/:id', this.getEntity.bind(this));
|
|
69
106
|
this.router.put('/entities/:entityName/:id', this.updateEntity.bind(this));
|
|
70
107
|
this.router.delete('/entities/:entityName/:id', this.deleteEntity.bind(this));
|
|
108
|
+
// Record changes and dependencies
|
|
71
109
|
this.router.get('/entities/:entityName/:id/changes', this.getRecordChanges.bind(this));
|
|
72
110
|
this.router.get('/entities/:entityName/:id/dependencies', this.getRecordDependencies.bind(this));
|
|
73
111
|
this.router.get('/entities/:entityName/:id/name', this.getEntityRecordName.bind(this));
|
|
112
|
+
// View operations
|
|
74
113
|
this.router.post('/views/:entityName', this.runView.bind(this));
|
|
75
114
|
this.router.post('/views/batch', this.runViews.bind(this));
|
|
76
115
|
this.router.get('/views/entity', this.getViewEntity.bind(this));
|
|
116
|
+
// Metadata endpoints
|
|
77
117
|
this.router.get('/metadata/entities', this.getEntityMetadata.bind(this));
|
|
78
118
|
this.router.get('/metadata/entities/:entityName', this.getEntityFieldMetadata.bind(this));
|
|
119
|
+
// Views metadata
|
|
79
120
|
this.router.get('/views/:entityName/metadata', this.getViewsMetadata.bind(this));
|
|
121
|
+
// User operations
|
|
80
122
|
this.router.get('/users/current', this.getCurrentUser.bind(this));
|
|
81
123
|
this.router.get('/users/:userId/favorites/:entityName/:id', this.getRecordFavoriteStatus.bind(this));
|
|
82
124
|
this.router.put('/users/:userId/favorites/:entityName/:id', this.setRecordFavoriteStatus.bind(this));
|
|
83
125
|
this.router.delete('/users/:userId/favorites/:entityName/:id', this.removeRecordFavoriteStatus.bind(this));
|
|
126
|
+
// Transaction operations
|
|
84
127
|
this.router.post('/transactions', this.executeTransaction.bind(this));
|
|
128
|
+
// Reports and queries
|
|
85
129
|
this.router.get('/reports/:reportId', this.runReport.bind(this));
|
|
86
130
|
this.router.post('/queries/run', this.runQuery.bind(this));
|
|
131
|
+
// Error handling
|
|
87
132
|
this.router.use(this.errorHandler);
|
|
88
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Middleware to check entity access based on include/exclude lists
|
|
136
|
+
*/
|
|
89
137
|
checkEntityAccess(req, res, next) {
|
|
90
|
-
const entityName = req.params.entityName;
|
|
138
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
91
139
|
if (!entityName) {
|
|
92
140
|
next();
|
|
93
141
|
return;
|
|
@@ -101,11 +149,19 @@ export class RESTEndpointHandler {
|
|
|
101
149
|
}
|
|
102
150
|
next();
|
|
103
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Middleware to extract MJ user from request
|
|
154
|
+
*/
|
|
104
155
|
async extractMJUser(req, res, next) {
|
|
105
156
|
try {
|
|
157
|
+
// If authentication middleware has already set req.user with basic info
|
|
106
158
|
if (req['user']) {
|
|
159
|
+
// Get the full MemberJunction user
|
|
107
160
|
const md = new Metadata();
|
|
108
161
|
const userInfo = req['user'];
|
|
162
|
+
// Get user info based on email or ID
|
|
163
|
+
// Note: The actual implementation here would depend on how the MemberJunction core handles user lookup
|
|
164
|
+
// This is a simplification that would need to be implemented properly
|
|
109
165
|
req['mjUser'] = userInfo;
|
|
110
166
|
if (!req['mjUser']) {
|
|
111
167
|
res.status(401).json({ error: 'User not found in MemberJunction' });
|
|
@@ -122,6 +178,9 @@ export class RESTEndpointHandler {
|
|
|
122
178
|
next(error);
|
|
123
179
|
}
|
|
124
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Error handling middleware
|
|
183
|
+
*/
|
|
125
184
|
errorHandler(err, req, res, next) {
|
|
126
185
|
LogError(err);
|
|
127
186
|
if (err.name === 'UnauthorizedError') {
|
|
@@ -130,9 +189,13 @@ export class RESTEndpointHandler {
|
|
|
130
189
|
}
|
|
131
190
|
res.status(500).json({ error: err?.message || 'Internal server error' });
|
|
132
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Get the current user
|
|
194
|
+
*/
|
|
133
195
|
async getCurrentUser(req, res) {
|
|
134
196
|
try {
|
|
135
197
|
const user = req['mjUser'];
|
|
198
|
+
// Return user info without sensitive data
|
|
136
199
|
res.json({
|
|
137
200
|
ID: user.ID,
|
|
138
201
|
Name: user.Name,
|
|
@@ -152,11 +215,15 @@ export class RESTEndpointHandler {
|
|
|
152
215
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
153
216
|
}
|
|
154
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Lists entities with optional filtering
|
|
220
|
+
*/
|
|
155
221
|
async getEntityList(req, res) {
|
|
156
222
|
try {
|
|
157
|
-
const
|
|
223
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
158
224
|
const { filter, orderBy, fields, maxRows, startRow } = req.query;
|
|
159
225
|
const user = req['mjUser'];
|
|
226
|
+
// Convert the request to a RunViewParams object
|
|
160
227
|
const params = {
|
|
161
228
|
EntityName: entityName,
|
|
162
229
|
ExtraFilter: filter,
|
|
@@ -173,10 +240,14 @@ export class RESTEndpointHandler {
|
|
|
173
240
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
174
241
|
}
|
|
175
242
|
}
|
|
243
|
+
/**
|
|
244
|
+
* Get a single entity by ID
|
|
245
|
+
*/
|
|
176
246
|
async getEntity(req, res) {
|
|
177
247
|
try {
|
|
178
|
-
const
|
|
179
|
-
const
|
|
248
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
249
|
+
const id = this.getStringParam(req.params.id);
|
|
250
|
+
const { include } = req.query; // Optional related entities to include
|
|
180
251
|
const user = req['mjUser'];
|
|
181
252
|
const relatedEntities = include ? include.split(',') : null;
|
|
182
253
|
const result = await EntityCRUDHandler.getEntity(entityName, id, relatedEntities, user);
|
|
@@ -192,9 +263,12 @@ export class RESTEndpointHandler {
|
|
|
192
263
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
193
264
|
}
|
|
194
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Create a new entity
|
|
268
|
+
*/
|
|
195
269
|
async createEntity(req, res) {
|
|
196
270
|
try {
|
|
197
|
-
const
|
|
271
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
198
272
|
const entityData = req.body;
|
|
199
273
|
const user = req['mjUser'];
|
|
200
274
|
const result = await EntityCRUDHandler.createEntity(entityName, entityData, user);
|
|
@@ -213,9 +287,13 @@ export class RESTEndpointHandler {
|
|
|
213
287
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
214
288
|
}
|
|
215
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* Update an existing entity
|
|
292
|
+
*/
|
|
216
293
|
async updateEntity(req, res) {
|
|
217
294
|
try {
|
|
218
|
-
const
|
|
295
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
296
|
+
const id = this.getStringParam(req.params.id);
|
|
219
297
|
const updateData = req.body;
|
|
220
298
|
const user = req['mjUser'];
|
|
221
299
|
const result = await EntityCRUDHandler.updateEntity(entityName, id, updateData, user);
|
|
@@ -234,11 +312,16 @@ export class RESTEndpointHandler {
|
|
|
234
312
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
235
313
|
}
|
|
236
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* Delete an entity
|
|
317
|
+
*/
|
|
237
318
|
async deleteEntity(req, res) {
|
|
238
319
|
try {
|
|
239
|
-
const
|
|
320
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
321
|
+
const id = this.getStringParam(req.params.id);
|
|
240
322
|
const options = req.query.options ? JSON.parse(req.query.options) : {};
|
|
241
323
|
const user = req['mjUser'];
|
|
324
|
+
// Convert options to EntityDeleteOptions
|
|
242
325
|
const deleteOptions = new EntityDeleteOptions();
|
|
243
326
|
if (options.SkipEntityAIActions !== undefined)
|
|
244
327
|
deleteOptions.SkipEntityAIActions = !!options.SkipEntityAIActions;
|
|
@@ -259,14 +342,23 @@ export class RESTEndpointHandler {
|
|
|
259
342
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
260
343
|
}
|
|
261
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* Get record changes for an entity
|
|
347
|
+
*/
|
|
262
348
|
async getRecordChanges(req, res) {
|
|
263
349
|
try {
|
|
264
|
-
const
|
|
350
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
351
|
+
const id = this.getStringParam(req.params.id);
|
|
265
352
|
const user = req['mjUser'];
|
|
353
|
+
// Get the entity object
|
|
266
354
|
const md = new Metadata();
|
|
267
355
|
const entity = await md.GetEntityObject(entityName, user);
|
|
356
|
+
// Create a composite key
|
|
268
357
|
const compositeKey = this.createCompositeKey(entity.EntityInfo, id);
|
|
269
|
-
|
|
358
|
+
// Use a direct approach for getting record changes
|
|
359
|
+
// Note: This is a simplification. The actual implementation may need to be adjusted
|
|
360
|
+
// based on how the MemberJunction core handles record changes
|
|
361
|
+
const changes = []; // This would be populated with actual record changes
|
|
270
362
|
res.json(changes);
|
|
271
363
|
}
|
|
272
364
|
catch (error) {
|
|
@@ -274,14 +366,23 @@ export class RESTEndpointHandler {
|
|
|
274
366
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
275
367
|
}
|
|
276
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* Get record dependencies for an entity
|
|
371
|
+
*/
|
|
277
372
|
async getRecordDependencies(req, res) {
|
|
278
373
|
try {
|
|
279
|
-
const
|
|
374
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
375
|
+
const id = this.getStringParam(req.params.id);
|
|
280
376
|
const user = req['mjUser'];
|
|
377
|
+
// Get the entity object
|
|
281
378
|
const md = new Metadata();
|
|
282
379
|
const entity = await md.GetEntityObject(entityName, user);
|
|
380
|
+
// Create a composite key
|
|
283
381
|
const compositeKey = this.createCompositeKey(entity.EntityInfo, id);
|
|
284
|
-
|
|
382
|
+
// Use a direct approach for getting record dependencies
|
|
383
|
+
// Note: This is a simplification. The actual implementation may need to be adjusted
|
|
384
|
+
// based on how the MemberJunction core handles record dependencies
|
|
385
|
+
const dependencies = []; // This would be populated with actual record dependencies
|
|
285
386
|
res.json(dependencies);
|
|
286
387
|
}
|
|
287
388
|
catch (error) {
|
|
@@ -289,14 +390,22 @@ export class RESTEndpointHandler {
|
|
|
289
390
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
290
391
|
}
|
|
291
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* Get entity record name
|
|
395
|
+
*/
|
|
292
396
|
async getEntityRecordName(req, res) {
|
|
293
397
|
try {
|
|
294
|
-
const
|
|
398
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
399
|
+
const id = this.getStringParam(req.params.id);
|
|
295
400
|
const user = req['mjUser'];
|
|
401
|
+
// Get the entity object
|
|
296
402
|
const md = new Metadata();
|
|
297
403
|
const entity = await md.GetEntityObject(entityName, user);
|
|
404
|
+
// Create a composite key
|
|
298
405
|
const compositeKey = this.createCompositeKey(entity.EntityInfo, id);
|
|
299
|
-
|
|
406
|
+
// Use a direct approach for getting entity record name
|
|
407
|
+
// Note: This is a simplification. The actual implementation may need to be adjusted
|
|
408
|
+
const recordName = "Record Name"; // This would be populated with the actual record name
|
|
300
409
|
res.json({ recordName });
|
|
301
410
|
}
|
|
302
411
|
catch (error) {
|
|
@@ -304,11 +413,15 @@ export class RESTEndpointHandler {
|
|
|
304
413
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
305
414
|
}
|
|
306
415
|
}
|
|
416
|
+
/**
|
|
417
|
+
* Run a view
|
|
418
|
+
*/
|
|
307
419
|
async runView(req, res) {
|
|
308
420
|
try {
|
|
309
|
-
const
|
|
421
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
310
422
|
const viewParams = req.body;
|
|
311
423
|
const user = req['mjUser'];
|
|
424
|
+
// Create RunViewParams from the request body
|
|
312
425
|
const params = {
|
|
313
426
|
EntityName: entityName,
|
|
314
427
|
...viewParams
|
|
@@ -326,6 +439,9 @@ export class RESTEndpointHandler {
|
|
|
326
439
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
327
440
|
}
|
|
328
441
|
}
|
|
442
|
+
/**
|
|
443
|
+
* Run multiple views in batch
|
|
444
|
+
*/
|
|
329
445
|
async runViews(req, res) {
|
|
330
446
|
try {
|
|
331
447
|
const { params } = req.body;
|
|
@@ -334,7 +450,10 @@ export class RESTEndpointHandler {
|
|
|
334
450
|
res.status(400).json({ error: 'params must be an array of RunViewParams' });
|
|
335
451
|
return;
|
|
336
452
|
}
|
|
453
|
+
// Filter out any views for entities that aren't allowed
|
|
454
|
+
// using our enhanced entity filtering with wildcards and schema support
|
|
337
455
|
const filteredParams = params.filter(p => this.isEntityAllowed(p.EntityName));
|
|
456
|
+
// If all requested entities were filtered out, return an error
|
|
338
457
|
if (filteredParams.length === 0 && params.length > 0) {
|
|
339
458
|
res.status(403).json({
|
|
340
459
|
error: 'None of the requested entities are allowed through the REST API',
|
|
@@ -355,6 +474,9 @@ export class RESTEndpointHandler {
|
|
|
355
474
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
356
475
|
}
|
|
357
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Get entity for a view
|
|
479
|
+
*/
|
|
358
480
|
async getViewEntity(req, res) {
|
|
359
481
|
try {
|
|
360
482
|
const { ViewID, ViewName } = req.query;
|
|
@@ -363,7 +485,8 @@ export class RESTEndpointHandler {
|
|
|
363
485
|
res.status(400).json({ error: 'Either ViewID or ViewName must be provided' });
|
|
364
486
|
return;
|
|
365
487
|
}
|
|
366
|
-
|
|
488
|
+
// Placeholder implementation - this would need to be implemented to lookup view metadata
|
|
489
|
+
const entityName = "SampleEntity"; // This would be determined by looking up the view
|
|
367
490
|
res.json({ entityName });
|
|
368
491
|
}
|
|
369
492
|
catch (error) {
|
|
@@ -371,14 +494,20 @@ export class RESTEndpointHandler {
|
|
|
371
494
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
372
495
|
}
|
|
373
496
|
}
|
|
497
|
+
/**
|
|
498
|
+
* Get metadata for all entities
|
|
499
|
+
*/
|
|
374
500
|
async getEntityMetadata(req, res) {
|
|
375
501
|
try {
|
|
376
502
|
const user = req['mjUser'];
|
|
503
|
+
// Filter entities based on user permissions and REST API configuration
|
|
377
504
|
const md = new Metadata();
|
|
378
505
|
const entities = md.Entities.filter(e => {
|
|
506
|
+
// First check if entity is allowed based on configuration
|
|
379
507
|
if (!this.isEntityAllowed(e.Name)) {
|
|
380
508
|
return false;
|
|
381
509
|
}
|
|
510
|
+
// Then check user permissions
|
|
382
511
|
const permissions = e.GetUserPermisions(user);
|
|
383
512
|
return permissions.CanRead;
|
|
384
513
|
});
|
|
@@ -400,9 +529,12 @@ export class RESTEndpointHandler {
|
|
|
400
529
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
401
530
|
}
|
|
402
531
|
}
|
|
532
|
+
/**
|
|
533
|
+
* Get field metadata for a specific entity
|
|
534
|
+
*/
|
|
403
535
|
async getEntityFieldMetadata(req, res) {
|
|
404
536
|
try {
|
|
405
|
-
const
|
|
537
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
406
538
|
const user = req['mjUser'];
|
|
407
539
|
const md = new Metadata();
|
|
408
540
|
const entity = md.Entities.find(e => e.Name === entityName);
|
|
@@ -410,6 +542,7 @@ export class RESTEndpointHandler {
|
|
|
410
542
|
res.status(404).json({ error: `Entity '${entityName}' not found` });
|
|
411
543
|
return;
|
|
412
544
|
}
|
|
545
|
+
// Check if user can read this entity
|
|
413
546
|
const permissions = entity.GetUserPermisions(user);
|
|
414
547
|
if (!permissions.CanRead) {
|
|
415
548
|
res.status(403).json({ error: 'Permission denied' });
|
|
@@ -435,11 +568,16 @@ export class RESTEndpointHandler {
|
|
|
435
568
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
436
569
|
}
|
|
437
570
|
}
|
|
571
|
+
/**
|
|
572
|
+
* Get metadata about available views for an entity
|
|
573
|
+
*/
|
|
438
574
|
async getViewsMetadata(req, res) {
|
|
439
575
|
try {
|
|
440
|
-
const
|
|
576
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
441
577
|
const user = req['mjUser'];
|
|
442
|
-
|
|
578
|
+
// This would need to be implemented to retrieve available views
|
|
579
|
+
// Placeholder implementation
|
|
580
|
+
const views = []; // Would need to query available views for this entity
|
|
443
581
|
res.json(views);
|
|
444
582
|
}
|
|
445
583
|
catch (error) {
|
|
@@ -447,14 +585,23 @@ export class RESTEndpointHandler {
|
|
|
447
585
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
448
586
|
}
|
|
449
587
|
}
|
|
588
|
+
/**
|
|
589
|
+
* Get favorite status for a record
|
|
590
|
+
*/
|
|
450
591
|
async getRecordFavoriteStatus(req, res) {
|
|
451
592
|
try {
|
|
452
|
-
const
|
|
593
|
+
const userId = this.getStringParam(req.params.userId);
|
|
594
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
595
|
+
const id = this.getStringParam(req.params.id);
|
|
453
596
|
const user = req['mjUser'];
|
|
597
|
+
// Get the entity object
|
|
454
598
|
const md = new Metadata();
|
|
455
599
|
const entity = await md.GetEntityObject(entityName, user);
|
|
600
|
+
// Create a composite key
|
|
456
601
|
const compositeKey = this.createCompositeKey(entity.EntityInfo, id);
|
|
457
|
-
|
|
602
|
+
// Use a direct approach for getting favorite status
|
|
603
|
+
// Note: This is a simplification. The actual implementation may need to be adjusted
|
|
604
|
+
const isFavorite = false; // This would be populated with the actual favorite status
|
|
458
605
|
res.json({ isFavorite });
|
|
459
606
|
}
|
|
460
607
|
catch (error) {
|
|
@@ -462,13 +609,23 @@ export class RESTEndpointHandler {
|
|
|
462
609
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
463
610
|
}
|
|
464
611
|
}
|
|
612
|
+
/**
|
|
613
|
+
* Set favorite status for a record
|
|
614
|
+
*/
|
|
465
615
|
async setRecordFavoriteStatus(req, res) {
|
|
466
616
|
try {
|
|
467
|
-
const
|
|
617
|
+
const userId = this.getStringParam(req.params.userId);
|
|
618
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
619
|
+
const id = this.getStringParam(req.params.id);
|
|
468
620
|
const user = req['mjUser'];
|
|
621
|
+
// Get the entity object
|
|
469
622
|
const md = new Metadata();
|
|
470
623
|
const entity = await md.GetEntityObject(entityName, user);
|
|
624
|
+
// Create a composite key
|
|
471
625
|
const compositeKey = this.createCompositeKey(entity.EntityInfo, id);
|
|
626
|
+
// Use a direct approach for setting favorite status
|
|
627
|
+
// Note: This is a simplification. The actual implementation may need to be adjusted
|
|
628
|
+
// This would set the favorite status to true
|
|
472
629
|
res.status(204).send();
|
|
473
630
|
}
|
|
474
631
|
catch (error) {
|
|
@@ -476,13 +633,23 @@ export class RESTEndpointHandler {
|
|
|
476
633
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
477
634
|
}
|
|
478
635
|
}
|
|
636
|
+
/**
|
|
637
|
+
* Remove favorite status for a record
|
|
638
|
+
*/
|
|
479
639
|
async removeRecordFavoriteStatus(req, res) {
|
|
480
640
|
try {
|
|
481
|
-
const
|
|
641
|
+
const userId = this.getStringParam(req.params.userId);
|
|
642
|
+
const entityName = this.getStringParam(req.params.entityName);
|
|
643
|
+
const id = this.getStringParam(req.params.id);
|
|
482
644
|
const user = req['mjUser'];
|
|
645
|
+
// Get the entity object
|
|
483
646
|
const md = new Metadata();
|
|
484
647
|
const entity = await md.GetEntityObject(entityName, user);
|
|
648
|
+
// Create a composite key
|
|
485
649
|
const compositeKey = this.createCompositeKey(entity.EntityInfo, id);
|
|
650
|
+
// Use a direct approach for setting favorite status
|
|
651
|
+
// Note: This is a simplification. The actual implementation may need to be adjusted
|
|
652
|
+
// This would set the favorite status to false
|
|
486
653
|
res.status(204).send();
|
|
487
654
|
}
|
|
488
655
|
catch (error) {
|
|
@@ -490,8 +657,12 @@ export class RESTEndpointHandler {
|
|
|
490
657
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
491
658
|
}
|
|
492
659
|
}
|
|
660
|
+
/**
|
|
661
|
+
* Execute a transaction
|
|
662
|
+
*/
|
|
493
663
|
async executeTransaction(req, res) {
|
|
494
664
|
try {
|
|
665
|
+
// Placeholder implementation - this would need to be implemented to handle transactions
|
|
495
666
|
res.status(501).json({ error: 'Not implemented' });
|
|
496
667
|
}
|
|
497
668
|
catch (error) {
|
|
@@ -499,8 +670,12 @@ export class RESTEndpointHandler {
|
|
|
499
670
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
500
671
|
}
|
|
501
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Run a report
|
|
675
|
+
*/
|
|
502
676
|
async runReport(req, res) {
|
|
503
677
|
try {
|
|
678
|
+
// Placeholder implementation - this would need to be implemented to run reports
|
|
504
679
|
res.status(501).json({ error: 'Not implemented' });
|
|
505
680
|
}
|
|
506
681
|
catch (error) {
|
|
@@ -508,8 +683,12 @@ export class RESTEndpointHandler {
|
|
|
508
683
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
509
684
|
}
|
|
510
685
|
}
|
|
686
|
+
/**
|
|
687
|
+
* Run a query
|
|
688
|
+
*/
|
|
511
689
|
async runQuery(req, res) {
|
|
512
690
|
try {
|
|
691
|
+
// Placeholder implementation - this would need to be implemented to run queries
|
|
513
692
|
res.status(501).json({ error: 'Not implemented' });
|
|
514
693
|
}
|
|
515
694
|
catch (error) {
|
|
@@ -517,19 +696,29 @@ export class RESTEndpointHandler {
|
|
|
517
696
|
res.status(500).json({ error: error?.message || 'Unknown error' });
|
|
518
697
|
}
|
|
519
698
|
}
|
|
699
|
+
/**
|
|
700
|
+
* Helper method to create a composite key from an ID
|
|
701
|
+
*/
|
|
520
702
|
createCompositeKey(entityInfo, id) {
|
|
521
703
|
if (entityInfo.PrimaryKeys.length === 1) {
|
|
704
|
+
// Single primary key
|
|
522
705
|
const primaryKeyField = entityInfo.PrimaryKeys[0].Name;
|
|
523
706
|
const compositeKey = new CompositeKey();
|
|
707
|
+
// Use key-value pairs instead of SetValue
|
|
524
708
|
compositeKey.KeyValuePairs = [
|
|
525
709
|
{ FieldName: primaryKeyField, Value: id }
|
|
526
710
|
];
|
|
527
711
|
return compositeKey;
|
|
528
712
|
}
|
|
529
713
|
else {
|
|
714
|
+
// Composite primary key
|
|
715
|
+
// This is a simplification - in a real implementation, we would need to handle composite keys properly
|
|
530
716
|
throw new Error('Composite primary keys are not supported in this implementation');
|
|
531
717
|
}
|
|
532
718
|
}
|
|
719
|
+
/**
|
|
720
|
+
* Get the Express router with all configured routes
|
|
721
|
+
*/
|
|
533
722
|
getRouter() {
|
|
534
723
|
return this.router;
|
|
535
724
|
}
|