- Fix query parameter type issues (string | string[] to string) in controllers - Add public getDatabaseAdapter() method to SchemaRepository for db access - Fix SchemaSyncService export and import issues - Fix referenceObject vs referenceObjectType property name - Add missing jiraAssetsClient import in normalizedCacheStore - Fix duplicate properties in object literals - Add type annotations for implicit any types - Fix type predicate issues with generics - Fix method calls (getEnabledObjectTypes, syncAllSchemas) - Fix type mismatches (ObjectTypeRecord vs expected types) - Fix Buffer type issue in biaMatchingService - Export SchemaSyncService class for ServiceFactory
210 lines
6.7 KiB
TypeScript
210 lines
6.7 KiB
TypeScript
/**
|
|
* Schema Configuration routes
|
|
*
|
|
* Provides endpoints for configuring which object types should be synced.
|
|
*/
|
|
|
|
import { Router, Request, Response } from 'express';
|
|
import { logger } from '../services/logger.js';
|
|
import { requireAuth, requirePermission } from '../middleware/authorization.js';
|
|
import { schemaConfigurationService } from '../services/schemaConfigurationService.js';
|
|
import { schemaSyncService } from '../services/SchemaSyncService.js';
|
|
|
|
const router = Router();
|
|
|
|
// All routes require authentication and manage_settings permission
|
|
router.use(requireAuth);
|
|
router.use(requirePermission('manage_settings'));
|
|
|
|
/**
|
|
* GET /api/schema-configuration/stats
|
|
* Get configuration statistics
|
|
*/
|
|
router.get('/stats', async (req: Request, res: Response) => {
|
|
try {
|
|
const stats = await schemaConfigurationService.getConfigurationStats();
|
|
res.json(stats);
|
|
} catch (error) {
|
|
logger.error('Failed to get configuration stats', error);
|
|
res.status(500).json({ error: 'Failed to get configuration stats' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/schema-configuration/discover
|
|
* Discover and store all schemas, object types, and attributes from Jira Assets
|
|
* Uses the unified SchemaSyncService
|
|
*/
|
|
router.post('/discover', async (req: Request, res: Response) => {
|
|
try {
|
|
logger.info('Schema configuration: Manual schema sync triggered');
|
|
const result = await schemaSyncService.syncAll();
|
|
|
|
if (result.schemasProcessed === 0) {
|
|
logger.warn('Schema configuration: Sync returned 0 schemas - this might indicate an API issue');
|
|
res.status(400).json({
|
|
message: 'No schemas found. Please check: 1) JIRA_SERVICE_ACCOUNT_TOKEN is configured correctly, 2) Jira Assets API is accessible, 3) API endpoint /rest/assets/1.0/objectschema/list is available',
|
|
...result,
|
|
});
|
|
return;
|
|
}
|
|
|
|
res.json({
|
|
message: 'Schema synchronization completed successfully',
|
|
schemasDiscovered: result.schemasProcessed,
|
|
objectTypesDiscovered: result.objectTypesProcessed,
|
|
attributesDiscovered: result.attributesProcessed,
|
|
...result,
|
|
});
|
|
} catch (error) {
|
|
logger.error('Failed to sync schemas and object types', error);
|
|
res.status(500).json({
|
|
error: 'Failed to sync schemas and object types',
|
|
details: error instanceof Error ? error.message : String(error),
|
|
stack: error instanceof Error ? error.stack : undefined
|
|
});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/schema-configuration/object-types
|
|
* Get all configured object types grouped by schema
|
|
*/
|
|
router.get('/object-types', async (req: Request, res: Response) => {
|
|
try {
|
|
const schemas = await schemaConfigurationService.getConfiguredObjectTypes();
|
|
res.json({ schemas });
|
|
} catch (error) {
|
|
logger.error('Failed to get configured object types', error);
|
|
res.status(500).json({ error: 'Failed to get configured object types' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* PATCH /api/schema-configuration/object-types/:id/enabled
|
|
* Enable or disable an object type
|
|
*/
|
|
router.patch('/object-types/:id/enabled', async (req: Request, res: Response) => {
|
|
try {
|
|
const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
|
|
if (!id) {
|
|
res.status(400).json({ error: 'id parameter required' });
|
|
return;
|
|
}
|
|
const { enabled } = req.body;
|
|
|
|
if (typeof enabled !== 'boolean') {
|
|
res.status(400).json({ error: 'enabled must be a boolean' });
|
|
return;
|
|
}
|
|
|
|
await schemaConfigurationService.setObjectTypeEnabled(id, enabled);
|
|
|
|
res.json({
|
|
status: 'success',
|
|
message: `Object type ${id} ${enabled ? 'enabled' : 'disabled'}`,
|
|
});
|
|
} catch (error) {
|
|
logger.error('Failed to update object type enabled status', error);
|
|
res.status(500).json({ error: 'Failed to update object type enabled status' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* PATCH /api/schema-configuration/object-types/bulk-enabled
|
|
* Bulk update enabled status for multiple object types
|
|
*/
|
|
router.patch('/object-types/bulk-enabled', async (req: Request, res: Response) => {
|
|
try {
|
|
const { updates } = req.body;
|
|
|
|
if (!Array.isArray(updates)) {
|
|
res.status(400).json({ error: 'updates must be an array' });
|
|
return;
|
|
}
|
|
|
|
// Validate each update
|
|
for (const update of updates) {
|
|
if (!update.id || typeof update.enabled !== 'boolean') {
|
|
res.status(400).json({ error: 'Each update must have id (string) and enabled (boolean)' });
|
|
return;
|
|
}
|
|
}
|
|
|
|
await schemaConfigurationService.bulkSetObjectTypesEnabled(updates);
|
|
|
|
res.json({
|
|
status: 'success',
|
|
message: `Updated ${updates.length} object types`,
|
|
});
|
|
} catch (error) {
|
|
logger.error('Failed to bulk update object types', error);
|
|
res.status(500).json({ error: 'Failed to bulk update object types' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/schema-configuration/check
|
|
* Check if configuration is complete (at least one object type enabled)
|
|
*/
|
|
router.get('/check', async (req: Request, res: Response) => {
|
|
try {
|
|
const isComplete = await schemaConfigurationService.isConfigurationComplete();
|
|
const stats = await schemaConfigurationService.getConfigurationStats();
|
|
res.json({
|
|
isConfigured: isComplete,
|
|
stats,
|
|
});
|
|
} catch (error) {
|
|
logger.error('Failed to check configuration', error);
|
|
res.status(500).json({ error: 'Failed to check configuration' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/schema-configuration/schemas
|
|
* Get all schemas with their search enabled status
|
|
*/
|
|
router.get('/schemas', async (req: Request, res: Response) => {
|
|
try {
|
|
const schemas = await schemaConfigurationService.getSchemas();
|
|
res.json({ schemas });
|
|
} catch (error) {
|
|
logger.error('Failed to get schemas', error);
|
|
res.status(500).json({ error: 'Failed to get schemas' });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* PATCH /api/schema-configuration/schemas/:schemaId/search-enabled
|
|
* Enable or disable search for a schema
|
|
*/
|
|
router.patch('/schemas/:schemaId/search-enabled', async (req: Request, res: Response) => {
|
|
try {
|
|
const schemaId = req.params.schemaId;
|
|
const { searchEnabled } = req.body;
|
|
|
|
if (typeof searchEnabled !== 'boolean') {
|
|
res.status(400).json({ error: 'searchEnabled must be a boolean' });
|
|
return;
|
|
}
|
|
|
|
const schemaIdStr = Array.isArray(schemaId) ? schemaId[0] : schemaId;
|
|
if (!schemaIdStr) {
|
|
res.status(400).json({ error: 'schemaId parameter required' });
|
|
return;
|
|
}
|
|
await schemaConfigurationService.setSchemaSearchEnabled(schemaIdStr, searchEnabled);
|
|
|
|
res.json({
|
|
status: 'success',
|
|
message: `Schema ${schemaId} search ${searchEnabled ? 'enabled' : 'disabled'}`,
|
|
});
|
|
} catch (error) {
|
|
logger.error('Failed to update schema search enabled status', error);
|
|
res.status(500).json({ error: 'Failed to update schema search enabled status' });
|
|
}
|
|
});
|
|
|
|
export default router;
|