- Added SettingsComponent for user profile management, including display name and password change functionality. - Introduced TokensComponent for managing API tokens, including creation and revocation. - Created LayoutComponent for consistent application layout with navigation and user information. - Established main application structure in index.html and main.ts. - Integrated Tailwind CSS for styling and responsive design. - Configured TypeScript settings for strict type checking and module resolution.
110 lines
3.6 KiB
TypeScript
110 lines
3.6 KiB
TypeScript
/**
|
|
* Audit API handlers
|
|
*/
|
|
|
|
import type { IApiContext, IApiResponse } from '../router.ts';
|
|
import { PermissionService } from '../../services/permission.service.ts';
|
|
import { AuditLog } from '../../models/auditlog.ts';
|
|
import type { TAuditAction, TAuditResourceType } from '../../interfaces/audit.interfaces.ts';
|
|
|
|
export class AuditApi {
|
|
private permissionService: PermissionService;
|
|
|
|
constructor(permissionService: PermissionService) {
|
|
this.permissionService = permissionService;
|
|
}
|
|
|
|
/**
|
|
* GET /api/v1/audit
|
|
*/
|
|
public async query(ctx: IApiContext): Promise<IApiResponse> {
|
|
if (!ctx.actor?.userId) {
|
|
return { status: 401, body: { error: 'Authentication required' } };
|
|
}
|
|
|
|
try {
|
|
// Parse query parameters
|
|
const organizationId = ctx.url.searchParams.get('organizationId') || undefined;
|
|
const repositoryId = ctx.url.searchParams.get('repositoryId') || undefined;
|
|
const resourceType = ctx.url.searchParams.get('resourceType') as TAuditResourceType | undefined;
|
|
const actionsParam = ctx.url.searchParams.get('actions');
|
|
const actions = actionsParam ? (actionsParam.split(',') as TAuditAction[]) : undefined;
|
|
const success = ctx.url.searchParams.has('success')
|
|
? ctx.url.searchParams.get('success') === 'true'
|
|
: undefined;
|
|
const startDateParam = ctx.url.searchParams.get('startDate');
|
|
const endDateParam = ctx.url.searchParams.get('endDate');
|
|
const startDate = startDateParam ? new Date(startDateParam) : undefined;
|
|
const endDate = endDateParam ? new Date(endDateParam) : undefined;
|
|
const limit = parseInt(ctx.url.searchParams.get('limit') || '100', 10);
|
|
const offset = parseInt(ctx.url.searchParams.get('offset') || '0', 10);
|
|
|
|
// Check permissions
|
|
// Users can view audit logs for:
|
|
// 1. Their own actions (actorId = userId)
|
|
// 2. Organizations they manage
|
|
// 3. System admins can view all
|
|
|
|
let actorId: string | undefined;
|
|
|
|
if (ctx.actor.user?.isSystemAdmin) {
|
|
// System admins can see all
|
|
actorId = ctx.url.searchParams.get('actorId') || undefined;
|
|
} else if (organizationId) {
|
|
// Check if user can manage this org
|
|
const canManage = await this.permissionService.canManageOrganization(
|
|
ctx.actor.userId,
|
|
organizationId
|
|
);
|
|
if (!canManage) {
|
|
// User can only see their own actions in this org
|
|
actorId = ctx.actor.userId;
|
|
}
|
|
} else {
|
|
// Non-admins without org filter can only see their own actions
|
|
actorId = ctx.actor.userId;
|
|
}
|
|
|
|
const result = await AuditLog.query({
|
|
actorId,
|
|
organizationId,
|
|
repositoryId,
|
|
resourceType,
|
|
action: actions,
|
|
success,
|
|
startDate,
|
|
endDate,
|
|
limit,
|
|
offset,
|
|
});
|
|
|
|
return {
|
|
status: 200,
|
|
body: {
|
|
logs: result.logs.map((log) => ({
|
|
id: log.id,
|
|
actorId: log.actorId,
|
|
actorType: log.actorType,
|
|
action: log.action,
|
|
resourceType: log.resourceType,
|
|
resourceId: log.resourceId,
|
|
resourceName: log.resourceName,
|
|
organizationId: log.organizationId,
|
|
repositoryId: log.repositoryId,
|
|
success: log.success,
|
|
errorCode: log.errorCode,
|
|
timestamp: log.timestamp,
|
|
metadata: log.metadata,
|
|
})),
|
|
total: result.total,
|
|
limit,
|
|
offset,
|
|
},
|
|
};
|
|
} catch (error) {
|
|
console.error('[AuditApi] Query error:', error);
|
|
return { status: 500, body: { error: 'Failed to query audit logs' } };
|
|
}
|
|
}
|
|
}
|