@hamak/smart-data-dico 1.0.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.
Files changed (50) hide show
  1. package/README.md +292 -0
  2. package/backend/package.json +51 -0
  3. package/backend/src/__tests__/integration/api.test.ts +149 -0
  4. package/backend/src/__tests__/setup.ts +24 -0
  5. package/backend/src/__tests__/utils/testUtils.ts +76 -0
  6. package/backend/src/adapters/EntityFileAdapter.ts +154 -0
  7. package/backend/src/adapters/YamlFileInfoEnricher.ts +52 -0
  8. package/backend/src/controllers/authController.ts +131 -0
  9. package/backend/src/controllers/diagramController.ts +143 -0
  10. package/backend/src/controllers/dictionaryController.ts +306 -0
  11. package/backend/src/controllers/importExportController.ts +64 -0
  12. package/backend/src/controllers/perspectiveController.ts +90 -0
  13. package/backend/src/controllers/serviceController.ts +418 -0
  14. package/backend/src/controllers/stereotypeController.ts +59 -0
  15. package/backend/src/controllers/versionController.ts +226 -0
  16. package/backend/src/kernel/config.ts +43 -0
  17. package/backend/src/middleware/auth.ts +128 -0
  18. package/backend/src/middleware/jwtAuth.ts +100 -0
  19. package/backend/src/models/Dictionary.ts +38 -0
  20. package/backend/src/models/EntitySchema.ts +393 -0
  21. package/backend/src/models/__tests__/Dictionary.test.ts +92 -0
  22. package/backend/src/models/__tests__/EntitySchema.test.ts +119 -0
  23. package/backend/src/routes/index.ts +120 -0
  24. package/backend/src/scripts/migrate-to-uuid.ts +24 -0
  25. package/backend/src/server.ts +140 -0
  26. package/backend/src/services/__mocks__/entityService.ts +38 -0
  27. package/backend/src/services/__mocks__/serviceService.ts +88 -0
  28. package/backend/src/services/__mocks__/versionService.ts +38 -0
  29. package/backend/src/services/__tests__/dictionaryService.test.ts +74 -0
  30. package/backend/src/services/diagramService.ts +165 -0
  31. package/backend/src/services/dictionaryService.ts +582 -0
  32. package/backend/src/services/entityService.ts +102 -0
  33. package/backend/src/services/exportService.ts +172 -0
  34. package/backend/src/services/importService.ts +208 -0
  35. package/backend/src/services/perspectiveService.ts +276 -0
  36. package/backend/src/services/qualityService.ts +121 -0
  37. package/backend/src/services/serviceService.ts +763 -0
  38. package/backend/src/services/stereotypeService.ts +98 -0
  39. package/backend/src/services/versionService.ts +135 -0
  40. package/backend/src/setupTests.ts +12 -0
  41. package/backend/src/utils/__mocks__/fileOperations.ts +116 -0
  42. package/backend/src/utils/fileOperations.ts +602 -0
  43. package/backend/src/utils/logger.ts +38 -0
  44. package/backend/src/utils/migration.ts +254 -0
  45. package/backend/src/utils/swagger.ts +358 -0
  46. package/backend/src/utils/uuid.ts +41 -0
  47. package/backend/tsconfig.json +20 -0
  48. package/bin/cli.js +129 -0
  49. package/data-dictionaries/stereotypes.yaml +91 -0
  50. package/package.json +42 -0
@@ -0,0 +1,418 @@
1
+ import { Request, Response } from 'express';
2
+ import { serviceService } from '../services/serviceService.js';
3
+ import { logger } from '../utils/logger.js';
4
+ import { Entity, Relationship } from '../models/EntitySchema.js';
5
+
6
+ /**
7
+ * @swagger
8
+ * /api/services:
9
+ * get:
10
+ * summary: Get all services (packages)
11
+ * tags: [Services]
12
+ * responses:
13
+ * 200:
14
+ * description: A list of services
15
+ */
16
+ export const getAllServices = async (req: Request, res: Response) => {
17
+ try {
18
+ const services = await serviceService.getAllServices();
19
+ res.json({
20
+ message: 'Success',
21
+ data: services
22
+ });
23
+ } catch (error) {
24
+ logger.error('Error fetching services', error);
25
+ res.status(500).json({ message: 'Error fetching services', error });
26
+ }
27
+ };
28
+
29
+ /**
30
+ * @swagger
31
+ * /api/services/{service}/entities:
32
+ * get:
33
+ * summary: Get all entities for a specific service
34
+ * tags: [Entities]
35
+ */
36
+ export const getServiceEntities = async (req: Request, res: Response) => {
37
+ try {
38
+ const startTime = process.hrtime();
39
+ const { service } = req.params;
40
+
41
+ logger.info(`Starting to fetch entities for service: ${service}`);
42
+ const entities = await serviceService.getServiceEntities(service);
43
+
44
+ const endTime = process.hrtime(startTime);
45
+ const executionTimeMs = Number((endTime[0] * 1e3 + endTime[1] / 1e6).toFixed(2));
46
+
47
+ logger.info(`Fetched ${entities.length} entities for service: ${service} in ${executionTimeMs}ms`);
48
+
49
+ res.json({
50
+ message: 'Success',
51
+ data: entities,
52
+ meta: {
53
+ count: entities.length,
54
+ executionTimeMs
55
+ }
56
+ });
57
+ } catch (error) {
58
+ logger.error(`Error fetching entities for service: ${req.params.service}`, error);
59
+ res.status(500).json({ message: 'Error fetching service entities', error });
60
+ }
61
+ };
62
+
63
+ /**
64
+ * @swagger
65
+ * /api/services/{service}/entities/{entity}:
66
+ * get:
67
+ * summary: Get entity schema by service and entity name
68
+ * tags: [Entities]
69
+ */
70
+ export const getEntitySchema = async (req: Request, res: Response) => {
71
+ try {
72
+ const { service, entity } = req.params;
73
+ const entitySchema = await serviceService.getEntitySchema(service, entity);
74
+
75
+ if (!entitySchema) {
76
+ return res.status(404).json({ message: 'Entity not found' });
77
+ }
78
+
79
+ res.json({
80
+ message: 'Success',
81
+ data: entitySchema
82
+ });
83
+ } catch (error) {
84
+ logger.error(`Error fetching entity schema: ${error}`);
85
+ res.status(500).json({ message: 'Error fetching entity schema', error });
86
+ }
87
+ };
88
+
89
+ /**
90
+ * @swagger
91
+ * /api/services/{service}/entities:
92
+ * post:
93
+ * summary: Create a new entity
94
+ * tags: [Entities]
95
+ */
96
+ export const createEntity = async (req: Request, res: Response) => {
97
+ try {
98
+ const { service } = req.params;
99
+ const entityData = req.body as Entity;
100
+
101
+ const result = await serviceService.createEntity(service, entityData);
102
+
103
+ if (!result.success) {
104
+ return res.status(400).json({
105
+ message: 'Failed to create entity',
106
+ errors: result.errors
107
+ });
108
+ }
109
+
110
+ res.status(201).json({
111
+ message: 'Entity created successfully',
112
+ data: entityData
113
+ });
114
+ } catch (error) {
115
+ logger.error(`Error creating entity: ${error}`);
116
+ res.status(500).json({ message: 'Error creating entity', error });
117
+ }
118
+ };
119
+
120
+ /**
121
+ * @swagger
122
+ * /api/services/{service}/entities/{entity}:
123
+ * put:
124
+ * summary: Update an existing entity
125
+ * tags: [Entities]
126
+ */
127
+ export const updateEntity = async (req: Request, res: Response) => {
128
+ try {
129
+ const { service, entity } = req.params;
130
+ const entityData = req.body as Entity;
131
+
132
+ if (entityData.name !== entity) {
133
+ return res.status(400).json({
134
+ message: 'Entity name mismatch',
135
+ error: `Entity name (${entityData.name}) does not match the URL (${entity})`
136
+ });
137
+ }
138
+
139
+ const existingEntity = await serviceService.getEntitySchema(service, entity);
140
+ if (!existingEntity) {
141
+ return res.status(404).json({ message: 'Entity not found' });
142
+ }
143
+
144
+ const result = await serviceService.updateEntity(service, entityData);
145
+
146
+ if (!result.success) {
147
+ return res.status(400).json({
148
+ message: 'Failed to update entity',
149
+ errors: result.errors
150
+ });
151
+ }
152
+
153
+ res.json({
154
+ message: 'Entity updated successfully',
155
+ data: entityData
156
+ });
157
+ } catch (error) {
158
+ logger.error(`Error updating entity: ${error}`);
159
+ res.status(500).json({ message: 'Error updating entity', error });
160
+ }
161
+ };
162
+
163
+ /**
164
+ * @swagger
165
+ * /api/services/{service}/entities/{entity}:
166
+ * delete:
167
+ * summary: Delete an entity
168
+ * tags: [Entities]
169
+ */
170
+ export const deleteEntity = async (req: Request, res: Response) => {
171
+ try {
172
+ const { service, entity } = req.params;
173
+
174
+ const existingEntity = await serviceService.getEntitySchema(service, entity);
175
+ if (!existingEntity) {
176
+ return res.status(404).json({ message: 'Entity not found' });
177
+ }
178
+
179
+ const result = await serviceService.deleteEntity(service, entity);
180
+
181
+ if (!result.success) {
182
+ return res.status(400).json({
183
+ message: 'Failed to delete entity',
184
+ errors: result.errors
185
+ });
186
+ }
187
+
188
+ res.json({
189
+ message: 'Entity deleted successfully'
190
+ });
191
+ } catch (error) {
192
+ logger.error(`Error deleting entity: ${error}`);
193
+ res.status(500).json({ message: 'Error deleting entity', error });
194
+ }
195
+ };
196
+
197
+ /**
198
+ * @swagger
199
+ * /api/search:
200
+ * get:
201
+ * summary: Search for entities and attributes
202
+ * tags: [Search]
203
+ */
204
+ export const searchEntities = async (req: Request, res: Response) => {
205
+ try {
206
+ const { q, type, service, stereotype, hasMetadata } = req.query;
207
+
208
+ if (!q || typeof q !== 'string') {
209
+ return res.status(400).json({ message: 'Search query is required' });
210
+ }
211
+
212
+ const filters: any = {};
213
+ if (type) filters.type = String(type);
214
+ if (service) filters.service = String(service);
215
+ if (stereotype) filters.stereotype = String(stereotype);
216
+ if (hasMetadata) filters.hasMetadata = String(hasMetadata);
217
+
218
+ const results = await serviceService.searchEntities(q, Object.keys(filters).length > 0 ? filters : undefined);
219
+
220
+ res.json({
221
+ message: 'Success',
222
+ data: results
223
+ });
224
+ } catch (error) {
225
+ logger.error(`Error searching entities: ${error}`);
226
+ res.status(500).json({ message: 'Error searching entities', error });
227
+ }
228
+ };
229
+
230
+ export const submitEntity = async (req: Request, res: Response) => {
231
+ try {
232
+ const { service, entity } = req.params;
233
+ const result = await serviceService.changeEntityStatus(service, entity, 'submitted' as any);
234
+ if (!result.success) return res.status(400).json({ message: 'Failed to submit', errors: result.errors });
235
+ res.json({ message: 'Entity submitted for review' });
236
+ } catch (error) {
237
+ logger.error('Error submitting entity', error);
238
+ res.status(500).json({ message: 'Error submitting entity', error });
239
+ }
240
+ };
241
+
242
+ export const approveEntity = async (req: Request, res: Response) => {
243
+ try {
244
+ const { service, entity } = req.params;
245
+ const result = await serviceService.changeEntityStatus(service, entity, 'approved' as any);
246
+ if (!result.success) return res.status(400).json({ message: 'Failed to approve', errors: result.errors });
247
+ res.json({ message: 'Entity approved' });
248
+ } catch (error) {
249
+ logger.error('Error approving entity', error);
250
+ res.status(500).json({ message: 'Error approving entity', error });
251
+ }
252
+ };
253
+
254
+ export const returnEntity = async (req: Request, res: Response) => {
255
+ try {
256
+ const { service, entity } = req.params;
257
+ const result = await serviceService.changeEntityStatus(service, entity, 'returned' as any);
258
+ if (!result.success) return res.status(400).json({ message: 'Failed to return', errors: result.errors });
259
+
260
+ // Add return comment if provided
261
+ if (req.body.comment) {
262
+ await serviceService.addComment(service, entity, {
263
+ author: req.body.author || 'reviewer',
264
+ message: req.body.comment,
265
+ });
266
+ }
267
+
268
+ res.json({ message: 'Entity returned for revision' });
269
+ } catch (error) {
270
+ logger.error('Error returning entity', error);
271
+ res.status(500).json({ message: 'Error returning entity', error });
272
+ }
273
+ };
274
+
275
+ export const getEntityComments = async (req: Request, res: Response) => {
276
+ try {
277
+ const { service, entity } = req.params;
278
+ const comments = await serviceService.getComments(service, entity);
279
+ res.json({ message: 'Success', data: comments });
280
+ } catch (error) {
281
+ logger.error('Error fetching comments', error);
282
+ res.status(500).json({ message: 'Error fetching comments', error });
283
+ }
284
+ };
285
+
286
+ export const addEntityComment = async (req: Request, res: Response) => {
287
+ try {
288
+ const { service, entity } = req.params;
289
+ const result = await serviceService.addComment(service, entity, req.body);
290
+ if (!result.success) return res.status(400).json({ message: 'Failed to add comment', errors: result.errors });
291
+ res.status(201).json({ message: 'Comment added', data: result.comment });
292
+ } catch (error) {
293
+ logger.error('Error adding comment', error);
294
+ res.status(500).json({ message: 'Error adding comment', error });
295
+ }
296
+ };
297
+
298
+ export const resolveEntityComment = async (req: Request, res: Response) => {
299
+ try {
300
+ const { service, entity, id } = req.params;
301
+ const result = await serviceService.resolveComment(service, entity, id);
302
+ if (!result.success) return res.status(400).json({ message: 'Failed to resolve comment', errors: result.errors });
303
+ res.json({ message: 'Comment resolved' });
304
+ } catch (error) {
305
+ logger.error('Error resolving comment', error);
306
+ res.status(500).json({ message: 'Error resolving comment', error });
307
+ }
308
+ };
309
+
310
+ export const getLineage = async (req: Request, res: Response) => {
311
+ try {
312
+ const { uuid } = req.params;
313
+ const lineage = await serviceService.getLineage(uuid);
314
+ res.json({ message: 'Success', data: lineage });
315
+ } catch (error) {
316
+ logger.error(`Error getting lineage: ${error}`);
317
+ res.status(500).json({ message: 'Error getting lineage', error });
318
+ }
319
+ };
320
+
321
+ export const getImpactAnalysis = async (req: Request, res: Response) => {
322
+ try {
323
+ const { uuid } = req.params;
324
+ const impact = await serviceService.getImpactAnalysis(uuid);
325
+ res.json({ message: 'Success', data: impact });
326
+ } catch (error) {
327
+ logger.error(`Error getting impact analysis: ${error}`);
328
+ res.status(500).json({ message: 'Error getting impact analysis', error });
329
+ }
330
+ };
331
+
332
+ /**
333
+ * @swagger
334
+ * /api/graph/{service}:
335
+ * get:
336
+ * summary: Get graph data for visualization
337
+ * tags: [Visualization]
338
+ */
339
+ export const getGraphData = async (req: Request, res: Response) => {
340
+ try {
341
+ const { service } = req.params;
342
+ const graphData = await serviceService.getGraphData(service);
343
+
344
+ res.json({
345
+ message: 'Success',
346
+ data: graphData
347
+ });
348
+ } catch (error) {
349
+ logger.error(`Error generating graph data: ${error}`);
350
+ res.status(500).json({ message: 'Error generating graph data', error });
351
+ }
352
+ };
353
+
354
+ // --- Relationship CRUD controllers ---
355
+
356
+ export const getPackageRelationships = async (req: Request, res: Response) => {
357
+ try {
358
+ const { packageName } = req.params;
359
+ const relationships = await serviceService.getPackageRelationships(packageName);
360
+ res.json({ message: 'Success', data: relationships });
361
+ } catch (error) {
362
+ logger.error(`Error fetching relationships: ${error}`);
363
+ res.status(500).json({ message: 'Error fetching relationships', error });
364
+ }
365
+ };
366
+
367
+ export const createRelationship = async (req: Request, res: Response) => {
368
+ try {
369
+ const { packageName } = req.params;
370
+ const relationship = req.body as Relationship;
371
+
372
+ const result = await serviceService.createRelationship(packageName, relationship);
373
+
374
+ if (!result.success) {
375
+ return res.status(400).json({ message: 'Failed to create relationship', errors: result.errors });
376
+ }
377
+
378
+ res.status(201).json({ message: 'Relationship created successfully', data: result.relationship });
379
+ } catch (error) {
380
+ logger.error(`Error creating relationship: ${error}`);
381
+ res.status(500).json({ message: 'Error creating relationship', error });
382
+ }
383
+ };
384
+
385
+ export const updateRelationship = async (req: Request, res: Response) => {
386
+ try {
387
+ const { packageName, uuid } = req.params;
388
+ const relationship = req.body as Relationship;
389
+
390
+ const result = await serviceService.updateRelationship(packageName, uuid, relationship);
391
+
392
+ if (!result.success) {
393
+ return res.status(400).json({ message: 'Failed to update relationship', errors: result.errors });
394
+ }
395
+
396
+ res.json({ message: 'Relationship updated successfully' });
397
+ } catch (error) {
398
+ logger.error(`Error updating relationship: ${error}`);
399
+ res.status(500).json({ message: 'Error updating relationship', error });
400
+ }
401
+ };
402
+
403
+ export const deleteRelationship = async (req: Request, res: Response) => {
404
+ try {
405
+ const { packageName, uuid } = req.params;
406
+
407
+ const result = await serviceService.deleteRelationship(packageName, uuid);
408
+
409
+ if (!result.success) {
410
+ return res.status(400).json({ message: 'Failed to delete relationship', errors: result.errors });
411
+ }
412
+
413
+ res.json({ message: 'Relationship deleted successfully' });
414
+ } catch (error) {
415
+ logger.error(`Error deleting relationship: ${error}`);
416
+ res.status(500).json({ message: 'Error deleting relationship', error });
417
+ }
418
+ };
@@ -0,0 +1,59 @@
1
+ import { Request, Response } from 'express';
2
+ import { stereotypeService } from '../services/stereotypeService.js';
3
+ import { StereotypeTarget } from '../models/EntitySchema.js';
4
+ import { logger } from '../utils/logger.js';
5
+
6
+ export const getAllStereotypes = async (req: Request, res: Response) => {
7
+ try {
8
+ const appliesTo = req.query.appliesTo as StereotypeTarget | undefined;
9
+ const stereotypes = await stereotypeService.getAllStereotypes(appliesTo);
10
+ res.json({ message: 'Success', data: stereotypes });
11
+ } catch (error) {
12
+ logger.error('Error fetching stereotypes', error);
13
+ res.status(500).json({ message: 'Error fetching stereotypes', error });
14
+ }
15
+ };
16
+
17
+ export const getStereotype = async (req: Request, res: Response) => {
18
+ try {
19
+ const stereotype = await stereotypeService.getStereotype(req.params.id);
20
+ if (!stereotype) return res.status(404).json({ message: 'Stereotype not found' });
21
+ res.json({ message: 'Success', data: stereotype });
22
+ } catch (error) {
23
+ logger.error('Error fetching stereotype', error);
24
+ res.status(500).json({ message: 'Error fetching stereotype', error });
25
+ }
26
+ };
27
+
28
+ export const createStereotype = async (req: Request, res: Response) => {
29
+ try {
30
+ const result = await stereotypeService.createStereotype(req.body);
31
+ if (!result.success) return res.status(400).json({ message: 'Failed to create stereotype', errors: result.errors });
32
+ res.status(201).json({ message: 'Stereotype created successfully', data: result.stereotype });
33
+ } catch (error) {
34
+ logger.error('Error creating stereotype', error);
35
+ res.status(500).json({ message: 'Error creating stereotype', error });
36
+ }
37
+ };
38
+
39
+ export const updateStereotype = async (req: Request, res: Response) => {
40
+ try {
41
+ const result = await stereotypeService.updateStereotype(req.params.id, req.body);
42
+ if (!result.success) return res.status(400).json({ message: 'Failed to update stereotype', errors: result.errors });
43
+ res.json({ message: 'Stereotype updated successfully', data: result.stereotype });
44
+ } catch (error) {
45
+ logger.error('Error updating stereotype', error);
46
+ res.status(500).json({ message: 'Error updating stereotype', error });
47
+ }
48
+ };
49
+
50
+ export const deleteStereotype = async (req: Request, res: Response) => {
51
+ try {
52
+ const result = await stereotypeService.deleteStereotype(req.params.id);
53
+ if (!result.success) return res.status(400).json({ message: 'Failed to delete stereotype', errors: result.errors });
54
+ res.json({ message: 'Stereotype deleted successfully' });
55
+ } catch (error) {
56
+ logger.error('Error deleting stereotype', error);
57
+ res.status(500).json({ message: 'Error deleting stereotype', error });
58
+ }
59
+ };
@@ -0,0 +1,226 @@
1
+ import { Request, Response } from 'express';
2
+ import { versionService } from '../services/versionService.js';
3
+ import { logger } from '../utils/logger.js';
4
+
5
+ /**
6
+ * @swagger
7
+ * /api/commit:
8
+ * post:
9
+ * summary: Commit changes to the local git repository
10
+ * description: Creates a new commit with all pending changes
11
+ * tags: [Version Control]
12
+ * security:
13
+ * - basicAuth: []
14
+ * requestBody:
15
+ * required: true
16
+ * content:
17
+ * application/json:
18
+ * schema:
19
+ * type: object
20
+ * required:
21
+ * - message
22
+ * properties:
23
+ * message:
24
+ * type: string
25
+ * description: Commit message
26
+ * responses:
27
+ * 200:
28
+ * description: Changes committed successfully
29
+ * content:
30
+ * application/json:
31
+ * schema:
32
+ * type: object
33
+ * properties:
34
+ * message:
35
+ * type: string
36
+ * example: Changes committed successfully
37
+ * data:
38
+ * type: object
39
+ * properties:
40
+ * commitHash:
41
+ * type: string
42
+ * description: Hash of the new commit
43
+ * commitMessage:
44
+ * type: string
45
+ * description: Commit message
46
+ * timestamp:
47
+ * type: string
48
+ * format: date-time
49
+ * description: Timestamp of the commit
50
+ * 400:
51
+ * description: Failed to commit changes
52
+ * 401:
53
+ * description: Unauthorized
54
+ * 403:
55
+ * description: Forbidden
56
+ * 500:
57
+ * description: Server error
58
+ *
59
+ * @param req Express request
60
+ * @param res Express response
61
+ */
62
+ export const commitChanges = async (req: Request, res: Response) => {
63
+ try {
64
+ const { message } = req.body;
65
+
66
+ if (!message) {
67
+ return res.status(400).json({ message: 'Commit message is required' });
68
+ }
69
+
70
+ const result = await versionService.commitChanges(message);
71
+
72
+ if (!result.success) {
73
+ return res.status(400).json({
74
+ message: 'Failed to commit changes',
75
+ errors: result.errors
76
+ });
77
+ }
78
+
79
+ res.json({
80
+ message: 'Changes committed successfully',
81
+ data: {
82
+ commitHash: result.commitHash,
83
+ commitMessage: message,
84
+ timestamp: result.timestamp
85
+ }
86
+ });
87
+ } catch (error) {
88
+ logger.error(`Error committing changes: ${error}`);
89
+ res.status(500).json({ message: 'Error committing changes', error });
90
+ }
91
+ };
92
+
93
+ /**
94
+ * @swagger
95
+ * /api/history:
96
+ * get:
97
+ * summary: Get commit history
98
+ * description: Returns the commit history for the repository
99
+ * tags: [Version Control]
100
+ * parameters:
101
+ * - in: query
102
+ * name: limit
103
+ * schema:
104
+ * type: integer
105
+ * default: 10
106
+ * description: Maximum number of commits to return
107
+ * responses:
108
+ * 200:
109
+ * description: Commit history
110
+ * content:
111
+ * application/json:
112
+ * schema:
113
+ * type: object
114
+ * properties:
115
+ * message:
116
+ * type: string
117
+ * example: Success
118
+ * data:
119
+ * type: array
120
+ * items:
121
+ * $ref: '#/components/schemas/CommitInfo'
122
+ * 500:
123
+ * description: Server error
124
+ *
125
+ * @param req Express request
126
+ * @param res Express response
127
+ */
128
+ export const getCommitHistory = async (req: Request, res: Response) => {
129
+ try {
130
+ const { limit } = req.query;
131
+ const limitNum = limit ? parseInt(limit as string, 10) : 10;
132
+
133
+ const history = await versionService.getCommitHistory(limitNum);
134
+
135
+ res.json({
136
+ message: 'Success',
137
+ data: history
138
+ });
139
+ } catch (error) {
140
+ logger.error(`Error fetching commit history: ${error}`);
141
+ res.status(500).json({ message: 'Error fetching commit history', error });
142
+ }
143
+ };
144
+
145
+ /**
146
+ * @swagger
147
+ * /api/revert:
148
+ * post:
149
+ * summary: Revert to a previous commit
150
+ * description: Creates a new commit that reverts the changes in the specified commit
151
+ * tags: [Version Control]
152
+ * security:
153
+ * - basicAuth: []
154
+ * requestBody:
155
+ * required: true
156
+ * content:
157
+ * application/json:
158
+ * schema:
159
+ * type: object
160
+ * required:
161
+ * - commitHash
162
+ * properties:
163
+ * commitHash:
164
+ * type: string
165
+ * description: Hash of the commit to revert
166
+ * responses:
167
+ * 200:
168
+ * description: Successfully reverted to commit
169
+ * content:
170
+ * application/json:
171
+ * schema:
172
+ * type: object
173
+ * properties:
174
+ * message:
175
+ * type: string
176
+ * example: Successfully reverted to commit
177
+ * data:
178
+ * type: object
179
+ * properties:
180
+ * commitHash:
181
+ * type: string
182
+ * description: Hash of the reverted commit
183
+ * newCommitHash:
184
+ * type: string
185
+ * description: Hash of the new revert commit
186
+ * 400:
187
+ * description: Failed to revert to commit
188
+ * 401:
189
+ * description: Unauthorized
190
+ * 403:
191
+ * description: Forbidden
192
+ * 500:
193
+ * description: Server error
194
+ *
195
+ * @param req Express request
196
+ * @param res Express response
197
+ */
198
+ export const revertToCommit = async (req: Request, res: Response) => {
199
+ try {
200
+ const { commitHash } = req.body;
201
+
202
+ if (!commitHash) {
203
+ return res.status(400).json({ message: 'Commit hash is required' });
204
+ }
205
+
206
+ const result = await versionService.revertToCommit(commitHash);
207
+
208
+ if (!result.success) {
209
+ return res.status(400).json({
210
+ message: 'Failed to revert to commit',
211
+ errors: result.errors
212
+ });
213
+ }
214
+
215
+ res.json({
216
+ message: 'Successfully reverted to commit',
217
+ data: {
218
+ commitHash,
219
+ newCommitHash: result.newCommitHash
220
+ }
221
+ });
222
+ } catch (error) {
223
+ logger.error(`Error reverting to commit: ${error}`);
224
+ res.status(500).json({ message: 'Error reverting to commit', error });
225
+ }
226
+ };