@vezlo/assistant-server 2.10.0 → 2.11.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 +2 -1
- package/database-schema.sql +48 -0
- package/dist/src/bootstrap/initializeServices.d.ts +5 -0
- package/dist/src/bootstrap/initializeServices.d.ts.map +1 -1
- package/dist/src/bootstrap/initializeServices.js +18 -3
- package/dist/src/bootstrap/initializeServices.js.map +1 -1
- package/dist/src/controllers/ChatController.d.ts +3 -0
- package/dist/src/controllers/ChatController.d.ts.map +1 -1
- package/dist/src/controllers/ChatController.js +75 -15
- package/dist/src/controllers/ChatController.js.map +1 -1
- package/dist/src/controllers/DatabaseToolConfigController.d.ts +81 -0
- package/dist/src/controllers/DatabaseToolConfigController.d.ts.map +1 -0
- package/dist/src/controllers/DatabaseToolConfigController.js +573 -0
- package/dist/src/controllers/DatabaseToolConfigController.js.map +1 -0
- package/dist/src/controllers/KnowledgeController.js +4 -4
- package/dist/src/controllers/KnowledgeController.js.map +1 -1
- package/dist/src/migrations/011_create_database_tool_configs.d.ts +4 -0
- package/dist/src/migrations/011_create_database_tool_configs.d.ts.map +1 -0
- package/dist/src/migrations/011_create_database_tool_configs.js +51 -0
- package/dist/src/migrations/011_create_database_tool_configs.js.map +1 -0
- package/dist/src/server.js +399 -0
- package/dist/src/server.js.map +1 -1
- package/dist/src/services/AIService.d.ts +3 -0
- package/dist/src/services/AIService.d.ts.map +1 -1
- package/dist/src/services/AIService.js +5 -0
- package/dist/src/services/AIService.js.map +1 -1
- package/dist/src/services/DatabaseToolConfigService.d.ts +135 -0
- package/dist/src/services/DatabaseToolConfigService.d.ts.map +1 -0
- package/dist/src/services/DatabaseToolConfigService.js +451 -0
- package/dist/src/services/DatabaseToolConfigService.js.map +1 -0
- package/dist/src/services/DatabaseToolService.d.ts +75 -0
- package/dist/src/services/DatabaseToolService.d.ts.map +1 -0
- package/dist/src/services/DatabaseToolService.js +299 -0
- package/dist/src/services/DatabaseToolService.js.map +1 -0
- package/dist/src/services/IntentService.d.ts +10 -1
- package/dist/src/services/IntentService.d.ts.map +1 -1
- package/dist/src/services/IntentService.js +34 -5
- package/dist/src/services/IntentService.js.map +1 -1
- package/dist/src/services/ResponseGenerationService.d.ts +5 -3
- package/dist/src/services/ResponseGenerationService.d.ts.map +1 -1
- package/dist/src/services/ResponseGenerationService.js +29 -4
- package/dist/src/services/ResponseGenerationService.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DatabaseToolConfigController
|
|
3
|
+
*
|
|
4
|
+
* Handles API endpoints for managing external database tool configurations
|
|
5
|
+
* Admin-only access
|
|
6
|
+
*/
|
|
7
|
+
import { Response } from 'express';
|
|
8
|
+
import { AuthenticatedRequest } from '../middleware/auth';
|
|
9
|
+
import { DatabaseToolConfigService } from '../services/DatabaseToolConfigService';
|
|
10
|
+
import { DatabaseToolService } from '../services/DatabaseToolService';
|
|
11
|
+
export declare class DatabaseToolConfigController {
|
|
12
|
+
private service;
|
|
13
|
+
private toolService?;
|
|
14
|
+
constructor(service: DatabaseToolConfigService, toolService?: DatabaseToolService);
|
|
15
|
+
/**
|
|
16
|
+
* Create new database configuration
|
|
17
|
+
* POST /api/database-tools/config
|
|
18
|
+
*/
|
|
19
|
+
createConfig(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Get database configuration for current company
|
|
22
|
+
* GET /api/database-tools/config
|
|
23
|
+
*/
|
|
24
|
+
getConfig(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Update database configuration
|
|
27
|
+
* PUT /api/database-tools/config/:configId
|
|
28
|
+
*/
|
|
29
|
+
updateConfig(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Delete database configuration
|
|
32
|
+
* DELETE /api/database-tools/config/:configId
|
|
33
|
+
*/
|
|
34
|
+
deleteConfig(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Validate database connection
|
|
37
|
+
* POST /api/database-tools/validate
|
|
38
|
+
*/
|
|
39
|
+
validateConnection(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Get available tables from database
|
|
42
|
+
* POST /api/database-tools/tables
|
|
43
|
+
*/
|
|
44
|
+
getTables(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Get available tables from existing config
|
|
47
|
+
* GET /api/database-tools/config/:configId/tables
|
|
48
|
+
*/
|
|
49
|
+
getTablesFromConfig(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Get table schema from existing config
|
|
52
|
+
* GET /api/database-tools/config/:configId/tables/:tableName/schema
|
|
53
|
+
*/
|
|
54
|
+
getTableSchemaFromConfig(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Get table schema (columns)
|
|
57
|
+
* POST /api/database-tools/tables/:tableName/schema
|
|
58
|
+
*/
|
|
59
|
+
getTableSchema(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Create a tool for a table
|
|
62
|
+
* POST /api/database-tools/tools
|
|
63
|
+
*/
|
|
64
|
+
createTool(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Get all tools for current company
|
|
67
|
+
* GET /api/database-tools/tools
|
|
68
|
+
*/
|
|
69
|
+
getTools(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Update a tool
|
|
72
|
+
* PUT /api/database-tools/tools/:toolId
|
|
73
|
+
*/
|
|
74
|
+
updateTool(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Delete a tool
|
|
77
|
+
* DELETE /api/database-tools/tools/:toolId
|
|
78
|
+
*/
|
|
79
|
+
deleteTool(req: AuthenticatedRequest, res: Response): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=DatabaseToolConfigController.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DatabaseToolConfigController.d.ts","sourceRoot":"","sources":["../../../src/controllers/DatabaseToolConfigController.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAGtE,qBAAa,4BAA4B;IACvC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,WAAW,CAAC,CAAsB;gBAE9B,OAAO,EAAE,yBAAyB,EAAE,WAAW,CAAC,EAAE,mBAAmB;IAKjF;;;OAGG;IACG,YAAY,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA0D3E;;;OAGG;IACG,SAAS,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCxE;;;OAGG;IACG,YAAY,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAmD3E;;;OAGG;IACG,YAAY,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA6C3E;;;OAGG;IACG,kBAAkB,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BjF;;;OAGG;IACG,SAAS,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BxE;;;OAGG;IACG,mBAAmB,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAuClF;;;OAGG;IACG,wBAAwB,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAwCvF;;;OAGG;IACG,cAAc,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA4B7E;;;OAGG;IACG,UAAU,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAqFzE;;;OAGG;IACG,QAAQ,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA6CvE;;;OAGG;IACG,UAAU,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAuDzE;;;OAGG;IACG,UAAU,CAAC,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CAqC1E"}
|
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DatabaseToolConfigController
|
|
4
|
+
*
|
|
5
|
+
* Handles API endpoints for managing external database tool configurations
|
|
6
|
+
* Admin-only access
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DatabaseToolConfigController = void 0;
|
|
13
|
+
const logger_1 = __importDefault(require("../config/logger"));
|
|
14
|
+
class DatabaseToolConfigController {
|
|
15
|
+
constructor(service, toolService) {
|
|
16
|
+
this.service = service;
|
|
17
|
+
this.toolService = toolService;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create new database configuration
|
|
21
|
+
* POST /api/database-tools/config
|
|
22
|
+
*/
|
|
23
|
+
async createConfig(req, res) {
|
|
24
|
+
try {
|
|
25
|
+
const { db_url, db_key } = req.body;
|
|
26
|
+
const companyId = parseInt(req.profile?.companyId || '0');
|
|
27
|
+
if (!db_url || !db_key) {
|
|
28
|
+
res.status(400).json({
|
|
29
|
+
success: false,
|
|
30
|
+
error: 'db_url and db_key are required'
|
|
31
|
+
});
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!companyId) {
|
|
35
|
+
res.status(401).json({
|
|
36
|
+
success: false,
|
|
37
|
+
error: 'Company ID not found'
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// Check if config already exists
|
|
42
|
+
const existing = await this.service.getConfigByCompany(companyId);
|
|
43
|
+
if (existing) {
|
|
44
|
+
res.status(409).json({
|
|
45
|
+
success: false,
|
|
46
|
+
error: 'Database configuration already exists for this company'
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const config = await this.service.createConfig(companyId, db_url, db_key);
|
|
51
|
+
// Clear cache for this company (new config added)
|
|
52
|
+
if (this.toolService) {
|
|
53
|
+
this.toolService.clearClientCache(companyId);
|
|
54
|
+
this.toolService.clearSchemaCache();
|
|
55
|
+
logger_1.default.info(`🧹 Cleared cache after creating config for company ${companyId}`);
|
|
56
|
+
}
|
|
57
|
+
res.status(201).json({
|
|
58
|
+
success: true,
|
|
59
|
+
config: {
|
|
60
|
+
uuid: config.uuid,
|
|
61
|
+
company_id: config.company_id,
|
|
62
|
+
enabled: config.enabled,
|
|
63
|
+
created_at: config.created_at
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
logger_1.default.error('Create database config error:', error);
|
|
69
|
+
res.status(500).json({
|
|
70
|
+
success: false,
|
|
71
|
+
error: error instanceof Error ? error.message : 'Failed to create configuration'
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get database configuration for current company
|
|
77
|
+
* GET /api/database-tools/config
|
|
78
|
+
*/
|
|
79
|
+
async getConfig(req, res) {
|
|
80
|
+
try {
|
|
81
|
+
const companyId = parseInt(req.profile?.companyId || '0');
|
|
82
|
+
if (!companyId) {
|
|
83
|
+
res.status(401).json({
|
|
84
|
+
success: false,
|
|
85
|
+
error: 'Company ID not found'
|
|
86
|
+
});
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const config = await this.service.getConfigByCompany(companyId);
|
|
90
|
+
if (!config) {
|
|
91
|
+
res.status(404).json({
|
|
92
|
+
success: false,
|
|
93
|
+
error: 'No database configuration found'
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
res.json({
|
|
98
|
+
success: true,
|
|
99
|
+
config: {
|
|
100
|
+
uuid: config.uuid,
|
|
101
|
+
company_id: config.company_id,
|
|
102
|
+
enabled: config.enabled,
|
|
103
|
+
created_at: config.created_at,
|
|
104
|
+
updated_at: config.updated_at
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
logger_1.default.error('Get database config error:', error);
|
|
110
|
+
res.status(500).json({
|
|
111
|
+
success: false,
|
|
112
|
+
error: error instanceof Error ? error.message : 'Failed to get configuration'
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Update database configuration
|
|
118
|
+
* PUT /api/database-tools/config/:configId
|
|
119
|
+
*/
|
|
120
|
+
async updateConfig(req, res) {
|
|
121
|
+
try {
|
|
122
|
+
const configId = Array.isArray(req.params.configId) ? req.params.configId[0] : req.params.configId;
|
|
123
|
+
const { db_url, db_key, enabled } = req.body;
|
|
124
|
+
const companyId = parseInt(req.profile?.companyId || '0');
|
|
125
|
+
if (!companyId) {
|
|
126
|
+
res.status(401).json({
|
|
127
|
+
success: false,
|
|
128
|
+
error: 'Company ID not found'
|
|
129
|
+
});
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
// Verify ownership (configId from API is UUID)
|
|
133
|
+
const existing = await this.service.getConfigByCompany(companyId);
|
|
134
|
+
if (!existing || existing.uuid !== configId) {
|
|
135
|
+
res.status(403).json({
|
|
136
|
+
success: false,
|
|
137
|
+
error: 'Configuration not found or access denied'
|
|
138
|
+
});
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const config = await this.service.updateConfig(configId, db_url, db_key, enabled);
|
|
142
|
+
// Clear cache for this company (credentials or settings changed)
|
|
143
|
+
if (this.toolService) {
|
|
144
|
+
this.toolService.clearClientCache(companyId);
|
|
145
|
+
this.toolService.clearSchemaCache();
|
|
146
|
+
logger_1.default.info(`🧹 Cleared cache after updating config for company ${companyId}`);
|
|
147
|
+
}
|
|
148
|
+
res.json({
|
|
149
|
+
success: true,
|
|
150
|
+
config: {
|
|
151
|
+
id: config.id,
|
|
152
|
+
company_id: config.company_id,
|
|
153
|
+
enabled: config.enabled,
|
|
154
|
+
updated_at: config.updated_at
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
logger_1.default.error('Update database config error:', error);
|
|
160
|
+
res.status(500).json({
|
|
161
|
+
success: false,
|
|
162
|
+
error: error instanceof Error ? error.message : 'Failed to update configuration'
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Delete database configuration
|
|
168
|
+
* DELETE /api/database-tools/config/:configId
|
|
169
|
+
*/
|
|
170
|
+
async deleteConfig(req, res) {
|
|
171
|
+
try {
|
|
172
|
+
const configId = Array.isArray(req.params.configId) ? req.params.configId[0] : req.params.configId;
|
|
173
|
+
const companyId = parseInt(req.profile?.companyId || '0');
|
|
174
|
+
if (!companyId) {
|
|
175
|
+
res.status(401).json({
|
|
176
|
+
success: false,
|
|
177
|
+
error: 'Company ID not found'
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// Verify ownership (configId from API is UUID)
|
|
182
|
+
const existing = await this.service.getConfigByCompany(companyId);
|
|
183
|
+
if (!existing || existing.uuid !== configId) {
|
|
184
|
+
res.status(403).json({
|
|
185
|
+
success: false,
|
|
186
|
+
error: 'Configuration not found or access denied'
|
|
187
|
+
});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
await this.service.deleteConfig(configId);
|
|
191
|
+
// Clear cache for this company (config deleted)
|
|
192
|
+
if (this.toolService) {
|
|
193
|
+
this.toolService.clearClientCache(companyId);
|
|
194
|
+
this.toolService.clearSchemaCache();
|
|
195
|
+
logger_1.default.info(`🧹 Cleared cache after deleting config for company ${companyId}`);
|
|
196
|
+
}
|
|
197
|
+
res.json({
|
|
198
|
+
success: true,
|
|
199
|
+
message: 'Configuration deleted successfully'
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
logger_1.default.error('Delete database config error:', error);
|
|
204
|
+
res.status(500).json({
|
|
205
|
+
success: false,
|
|
206
|
+
error: error instanceof Error ? error.message : 'Failed to delete configuration'
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Validate database connection
|
|
212
|
+
* POST /api/database-tools/validate
|
|
213
|
+
*/
|
|
214
|
+
async validateConnection(req, res) {
|
|
215
|
+
try {
|
|
216
|
+
const { db_url, db_key } = req.body;
|
|
217
|
+
if (!db_url || !db_key) {
|
|
218
|
+
res.status(400).json({
|
|
219
|
+
success: false,
|
|
220
|
+
error: 'db_url and db_key are required'
|
|
221
|
+
});
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const result = await this.service.validateConnection(db_url, db_key);
|
|
225
|
+
res.json({
|
|
226
|
+
success: true,
|
|
227
|
+
...result
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
logger_1.default.error('Validate connection error:', error);
|
|
232
|
+
res.status(500).json({
|
|
233
|
+
success: false,
|
|
234
|
+
error: error instanceof Error ? error.message : 'Failed to validate connection'
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get available tables from database
|
|
240
|
+
* POST /api/database-tools/tables
|
|
241
|
+
*/
|
|
242
|
+
async getTables(req, res) {
|
|
243
|
+
try {
|
|
244
|
+
const { db_url, db_key } = req.body;
|
|
245
|
+
if (!db_url || !db_key) {
|
|
246
|
+
res.status(400).json({
|
|
247
|
+
success: false,
|
|
248
|
+
error: 'db_url and db_key are required'
|
|
249
|
+
});
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const tables = await this.service.introspectTables(db_url, db_key);
|
|
253
|
+
res.json({
|
|
254
|
+
success: true,
|
|
255
|
+
tables
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
logger_1.default.error('Get tables error:', error);
|
|
260
|
+
res.status(500).json({
|
|
261
|
+
success: false,
|
|
262
|
+
error: error instanceof Error ? error.message : 'Failed to get tables'
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Get available tables from existing config
|
|
268
|
+
* GET /api/database-tools/config/:configId/tables
|
|
269
|
+
*/
|
|
270
|
+
async getTablesFromConfig(req, res) {
|
|
271
|
+
try {
|
|
272
|
+
const configId = Array.isArray(req.params.configId) ? req.params.configId[0] : req.params.configId;
|
|
273
|
+
const companyId = parseInt(req.profile?.companyId || '0');
|
|
274
|
+
if (!companyId) {
|
|
275
|
+
res.status(401).json({
|
|
276
|
+
success: false,
|
|
277
|
+
error: 'Company ID not found'
|
|
278
|
+
});
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
// Get decrypted credentials
|
|
282
|
+
const credentials = await this.service.getDecryptedCredentialsByConfigId(configId);
|
|
283
|
+
if (!credentials) {
|
|
284
|
+
res.status(404).json({
|
|
285
|
+
success: false,
|
|
286
|
+
error: 'Configuration not found'
|
|
287
|
+
});
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const tables = await this.service.introspectTables(credentials.url, credentials.key);
|
|
291
|
+
res.json({
|
|
292
|
+
success: true,
|
|
293
|
+
tables
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
logger_1.default.error('Get tables from config error:', error);
|
|
298
|
+
res.status(500).json({
|
|
299
|
+
success: false,
|
|
300
|
+
error: error instanceof Error ? error.message : 'Failed to get tables'
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Get table schema from existing config
|
|
306
|
+
* GET /api/database-tools/config/:configId/tables/:tableName/schema
|
|
307
|
+
*/
|
|
308
|
+
async getTableSchemaFromConfig(req, res) {
|
|
309
|
+
try {
|
|
310
|
+
const configId = Array.isArray(req.params.configId) ? req.params.configId[0] : req.params.configId;
|
|
311
|
+
const tableName = Array.isArray(req.params.tableName) ? req.params.tableName[0] : req.params.tableName;
|
|
312
|
+
const companyId = parseInt(req.profile?.companyId || '0');
|
|
313
|
+
if (!companyId) {
|
|
314
|
+
res.status(401).json({
|
|
315
|
+
success: false,
|
|
316
|
+
error: 'Company ID not found'
|
|
317
|
+
});
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
// Get decrypted credentials
|
|
321
|
+
const credentials = await this.service.getDecryptedCredentialsByConfigId(configId);
|
|
322
|
+
if (!credentials) {
|
|
323
|
+
res.status(404).json({
|
|
324
|
+
success: false,
|
|
325
|
+
error: 'Configuration not found'
|
|
326
|
+
});
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const schema = await this.service.introspectTableColumns(credentials.url, credentials.key, tableName);
|
|
330
|
+
res.json({
|
|
331
|
+
success: true,
|
|
332
|
+
schema
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
logger_1.default.error('Get table schema from config error:', error);
|
|
337
|
+
res.status(500).json({
|
|
338
|
+
success: false,
|
|
339
|
+
error: error instanceof Error ? error.message : 'Failed to get table schema'
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Get table schema (columns)
|
|
345
|
+
* POST /api/database-tools/tables/:tableName/schema
|
|
346
|
+
*/
|
|
347
|
+
async getTableSchema(req, res) {
|
|
348
|
+
try {
|
|
349
|
+
const tableName = Array.isArray(req.params.tableName) ? req.params.tableName[0] : req.params.tableName;
|
|
350
|
+
const { db_url, db_key } = req.body;
|
|
351
|
+
if (!db_url || !db_key) {
|
|
352
|
+
res.status(400).json({
|
|
353
|
+
success: false,
|
|
354
|
+
error: 'db_url and db_key are required'
|
|
355
|
+
});
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const schema = await this.service.introspectTableColumns(db_url, db_key, tableName);
|
|
359
|
+
res.json({
|
|
360
|
+
success: true,
|
|
361
|
+
schema
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
logger_1.default.error('Get table schema error:', error);
|
|
366
|
+
res.status(500).json({
|
|
367
|
+
success: false,
|
|
368
|
+
error: error instanceof Error ? error.message : 'Failed to get table schema'
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Create a tool for a table
|
|
374
|
+
* POST /api/database-tools/tools
|
|
375
|
+
*/
|
|
376
|
+
async createTool(req, res) {
|
|
377
|
+
try {
|
|
378
|
+
const { config_id, table_name, tool_name, tool_description, columns, id_column, id_column_type, requires_user_context, user_filter_column, user_filter_type, user_context_key } = req.body;
|
|
379
|
+
const companyId = parseInt(req.profile?.companyId || '0');
|
|
380
|
+
if (!config_id || !table_name || !tool_name || !columns || !id_column) {
|
|
381
|
+
res.status(400).json({
|
|
382
|
+
success: false,
|
|
383
|
+
error: 'config_id, table_name, tool_name, columns, and id_column are required'
|
|
384
|
+
});
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (!companyId) {
|
|
388
|
+
res.status(401).json({
|
|
389
|
+
success: false,
|
|
390
|
+
error: 'Company ID not found'
|
|
391
|
+
});
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
// Verify ownership of config (config_id from API is UUID)
|
|
395
|
+
const config = await this.service.getConfigByCompany(companyId);
|
|
396
|
+
if (!config || config.uuid !== config_id) {
|
|
397
|
+
res.status(403).json({
|
|
398
|
+
success: false,
|
|
399
|
+
error: 'Configuration not found or access denied'
|
|
400
|
+
});
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const tool = await this.service.createTool(config_id, // This is UUID from API
|
|
404
|
+
table_name, tool_name, tool_description || `Get data from ${table_name}`, columns, id_column, id_column_type || 'integer', requires_user_context, user_filter_column, user_filter_type, user_context_key);
|
|
405
|
+
// Return only public fields (UUID, not internal ID)
|
|
406
|
+
res.status(201).json({
|
|
407
|
+
success: true,
|
|
408
|
+
tool: {
|
|
409
|
+
uuid: tool.uuid,
|
|
410
|
+
table_name: tool.table_name,
|
|
411
|
+
tool_name: tool.tool_name,
|
|
412
|
+
tool_description: tool.tool_description,
|
|
413
|
+
columns: tool.columns,
|
|
414
|
+
id_column: tool.id_column,
|
|
415
|
+
id_column_type: tool.id_column_type,
|
|
416
|
+
enabled: tool.enabled,
|
|
417
|
+
requires_user_context: tool.requires_user_context,
|
|
418
|
+
user_filter_column: tool.user_filter_column,
|
|
419
|
+
user_filter_type: tool.user_filter_type,
|
|
420
|
+
user_context_key: tool.user_context_key,
|
|
421
|
+
created_at: tool.created_at
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
logger_1.default.error('Create tool error:', error);
|
|
427
|
+
res.status(500).json({
|
|
428
|
+
success: false,
|
|
429
|
+
error: error instanceof Error ? error.message : 'Failed to create tool'
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Get all tools for current company
|
|
435
|
+
* GET /api/database-tools/tools
|
|
436
|
+
*/
|
|
437
|
+
async getTools(req, res) {
|
|
438
|
+
try {
|
|
439
|
+
const companyId = parseInt(req.profile?.companyId || '0');
|
|
440
|
+
if (!companyId) {
|
|
441
|
+
res.status(401).json({
|
|
442
|
+
success: false,
|
|
443
|
+
error: 'Company ID not found'
|
|
444
|
+
});
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const tools = await this.service.getEnabledToolsByCompany(companyId);
|
|
448
|
+
// Map to expose only UUID, not internal ID
|
|
449
|
+
const publicTools = tools.map(tool => ({
|
|
450
|
+
uuid: tool.uuid,
|
|
451
|
+
table_name: tool.table_name,
|
|
452
|
+
tool_name: tool.tool_name,
|
|
453
|
+
tool_description: tool.tool_description,
|
|
454
|
+
columns: tool.columns,
|
|
455
|
+
id_column: tool.id_column,
|
|
456
|
+
id_column_type: tool.id_column_type,
|
|
457
|
+
enabled: tool.enabled,
|
|
458
|
+
requires_user_context: tool.requires_user_context,
|
|
459
|
+
user_filter_column: tool.user_filter_column,
|
|
460
|
+
user_filter_type: tool.user_filter_type,
|
|
461
|
+
user_context_key: tool.user_context_key,
|
|
462
|
+
created_at: tool.created_at,
|
|
463
|
+
updated_at: tool.updated_at
|
|
464
|
+
}));
|
|
465
|
+
res.json({
|
|
466
|
+
success: true,
|
|
467
|
+
tools: publicTools
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
logger_1.default.error('Get tools error:', error);
|
|
472
|
+
res.status(500).json({
|
|
473
|
+
success: false,
|
|
474
|
+
error: error instanceof Error ? error.message : 'Failed to get tools'
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Update a tool
|
|
480
|
+
* PUT /api/database-tools/tools/:toolId
|
|
481
|
+
*/
|
|
482
|
+
async updateTool(req, res) {
|
|
483
|
+
try {
|
|
484
|
+
const toolId = Array.isArray(req.params.toolId) ? req.params.toolId[0] : req.params.toolId;
|
|
485
|
+
const updates = req.body;
|
|
486
|
+
const companyId = parseInt(req.profile?.companyId || '0');
|
|
487
|
+
if (!companyId) {
|
|
488
|
+
res.status(401).json({
|
|
489
|
+
success: false,
|
|
490
|
+
error: 'Company ID not found'
|
|
491
|
+
});
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
// Verify ownership
|
|
495
|
+
const config = await this.service.getConfigByCompany(companyId);
|
|
496
|
+
if (!config) {
|
|
497
|
+
res.status(403).json({
|
|
498
|
+
success: false,
|
|
499
|
+
error: 'Access denied'
|
|
500
|
+
});
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const tool = await this.service.updateTool(toolId, updates);
|
|
504
|
+
// Return only public fields (UUID, not internal ID)
|
|
505
|
+
res.json({
|
|
506
|
+
success: true,
|
|
507
|
+
tool: {
|
|
508
|
+
uuid: tool.uuid,
|
|
509
|
+
table_name: tool.table_name,
|
|
510
|
+
tool_name: tool.tool_name,
|
|
511
|
+
tool_description: tool.tool_description,
|
|
512
|
+
columns: tool.columns,
|
|
513
|
+
id_column: tool.id_column,
|
|
514
|
+
id_column_type: tool.id_column_type,
|
|
515
|
+
enabled: tool.enabled,
|
|
516
|
+
requires_user_context: tool.requires_user_context,
|
|
517
|
+
user_filter_column: tool.user_filter_column,
|
|
518
|
+
user_filter_type: tool.user_filter_type,
|
|
519
|
+
user_context_key: tool.user_context_key,
|
|
520
|
+
created_at: tool.created_at,
|
|
521
|
+
updated_at: tool.updated_at
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
catch (error) {
|
|
526
|
+
logger_1.default.error('Update tool error:', error);
|
|
527
|
+
res.status(500).json({
|
|
528
|
+
success: false,
|
|
529
|
+
error: error instanceof Error ? error.message : 'Failed to update tool'
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Delete a tool
|
|
535
|
+
* DELETE /api/database-tools/tools/:toolId
|
|
536
|
+
*/
|
|
537
|
+
async deleteTool(req, res) {
|
|
538
|
+
try {
|
|
539
|
+
const toolId = Array.isArray(req.params.toolId) ? req.params.toolId[0] : req.params.toolId;
|
|
540
|
+
const companyId = parseInt(req.profile?.companyId || '0');
|
|
541
|
+
if (!companyId) {
|
|
542
|
+
res.status(401).json({
|
|
543
|
+
success: false,
|
|
544
|
+
error: 'Company ID not found'
|
|
545
|
+
});
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
// Verify ownership
|
|
549
|
+
const config = await this.service.getConfigByCompany(companyId);
|
|
550
|
+
if (!config) {
|
|
551
|
+
res.status(403).json({
|
|
552
|
+
success: false,
|
|
553
|
+
error: 'Access denied'
|
|
554
|
+
});
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
await this.service.deleteTool(toolId);
|
|
558
|
+
res.json({
|
|
559
|
+
success: true,
|
|
560
|
+
message: 'Tool deleted successfully'
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
catch (error) {
|
|
564
|
+
logger_1.default.error('Delete tool error:', error);
|
|
565
|
+
res.status(500).json({
|
|
566
|
+
success: false,
|
|
567
|
+
error: error instanceof Error ? error.message : 'Failed to delete tool'
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
exports.DatabaseToolConfigController = DatabaseToolConfigController;
|
|
573
|
+
//# sourceMappingURL=DatabaseToolConfigController.js.map
|