feat(opsserver,web): replace the Angular UI and REST management layer with a TypedRequest-based ops server and bundled web frontend

This commit is contained in:
2026-03-20 16:43:44 +00:00
parent 0fc74ff995
commit d4f758ce0f
159 changed files with 12465 additions and 14861 deletions

View File

@@ -0,0 +1,105 @@
import * as plugins from '../../plugins.ts';
import * as interfaces from '../../../ts_interfaces/index.ts';
import type { OpsServer } from '../classes.opsserver.ts';
import { requireValidIdentity } from '../helpers/guards.ts';
import { AuditLog } from '../../models/auditlog.ts';
import { PermissionService } from '../../services/permission.service.ts';
export class AuditHandler {
public typedrouter = new plugins.typedrequest.TypedRouter();
private permissionService = new PermissionService();
constructor(private opsServerRef: OpsServer) {
this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
this.registerHandlers();
}
private registerHandlers(): void {
// Query Audit Logs
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_QueryAudit>(
'queryAudit',
async (dataArg) => {
await requireValidIdentity(this.opsServerRef.authHandler, dataArg);
try {
const {
organizationId,
repositoryId,
resourceType,
actions,
success,
startDate: startDateStr,
endDate: endDateStr,
limit: limitParam,
offset: offsetParam,
} = dataArg;
const limit = limitParam || 100;
const offset = offsetParam || 0;
const startDate = startDateStr ? new Date(startDateStr) : undefined;
const endDate = endDateStr ? new Date(endDateStr) : undefined;
// Determine actor filter based on permissions
let actorId: string | undefined;
if (dataArg.identity.isSystemAdmin) {
// System admins can see all
actorId = dataArg.actorId;
} else if (organizationId) {
// Check if user can manage this org
const canManage = await this.permissionService.canManageOrganization(
dataArg.identity.userId,
organizationId,
);
if (!canManage) {
// User can only see their own actions in this org
actorId = dataArg.identity.userId;
}
} else {
// Non-admins without org filter can only see their own actions
actorId = dataArg.identity.userId;
}
const result = await AuditLog.query({
actorId,
organizationId,
repositoryId,
resourceType: resourceType as any,
action: actions as any[],
success,
startDate,
endDate,
limit,
offset,
});
return {
logs: result.logs.map((log) => ({
id: log.id,
actorId: log.actorId,
actorType: log.actorType as interfaces.data.IAuditEntry['actorType'],
action: log.action as interfaces.data.TAuditAction,
resourceType: log.resourceType as interfaces.data.TAuditResourceType,
resourceId: log.resourceId,
resourceName: log.resourceName,
organizationId: log.organizationId,
repositoryId: log.repositoryId,
success: log.success,
errorCode: log.errorCode,
timestamp: log.timestamp instanceof Date ? log.timestamp.toISOString() : String(log.timestamp),
metadata: log.metadata || {},
})),
total: result.total,
limit,
offset,
};
} catch (error) {
if (error instanceof plugins.typedrequest.TypedResponseError) throw error;
throw new plugins.typedrequest.TypedResponseError('Failed to query audit logs');
}
},
),
);
}
}