Files
registry/ts/models/auditlog.ts
Juergen Kunz ab88ac896f feat: implement account settings and API tokens management
- 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.
2025-11-27 22:15:38 +00:00

172 lines
4.7 KiB
TypeScript

/**
* AuditLog model for Stack.Gallery Registry
*/
import * as plugins from '../plugins.ts';
import type { IAuditLog, TAuditAction, TAuditResourceType } from '../interfaces/audit.interfaces.ts';
import { getDb } from './db.ts';
@plugins.smartdata.Collection(() => getDb())
export class AuditLog
extends plugins.smartdata.SmartDataDbDoc<AuditLog, AuditLog>
implements IAuditLog
{
@plugins.smartdata.unI()
public id: string = '';
@plugins.smartdata.svDb()
@plugins.smartdata.index()
public actorId?: string;
@plugins.smartdata.svDb()
@plugins.smartdata.index()
public actorType: 'user' | 'api_token' | 'system' | 'anonymous' = 'anonymous';
@plugins.smartdata.svDb()
public actorTokenId?: string;
@plugins.smartdata.svDb()
public actorIp?: string;
@plugins.smartdata.svDb()
public actorUserAgent?: string;
@plugins.smartdata.svDb()
@plugins.smartdata.index()
public action: TAuditAction = 'USER_CREATED';
@plugins.smartdata.svDb()
@plugins.smartdata.index()
public resourceType: TAuditResourceType = 'user';
@plugins.smartdata.svDb()
@plugins.smartdata.index()
public resourceId?: string;
@plugins.smartdata.svDb()
public resourceName?: string;
@plugins.smartdata.svDb()
@plugins.smartdata.index()
public organizationId?: string;
@plugins.smartdata.svDb()
@plugins.smartdata.index()
public repositoryId?: string;
@plugins.smartdata.svDb()
public metadata: Record<string, unknown> = {};
@plugins.smartdata.svDb()
@plugins.smartdata.index()
public success: boolean = true;
@plugins.smartdata.svDb()
public errorCode?: string;
@plugins.smartdata.svDb()
public errorMessage?: string;
@plugins.smartdata.svDb()
public durationMs?: number;
@plugins.smartdata.svDb()
@plugins.smartdata.index()
public timestamp: Date = new Date();
/**
* Create an audit log entry
*/
public static async log(data: {
actorId?: string;
actorType?: 'user' | 'api_token' | 'system' | 'anonymous';
actorTokenId?: string;
actorIp?: string;
actorUserAgent?: string;
action: TAuditAction;
resourceType: TAuditResourceType;
resourceId?: string;
resourceName?: string;
organizationId?: string;
repositoryId?: string;
metadata?: Record<string, unknown>;
success?: boolean;
errorCode?: string;
errorMessage?: string;
durationMs?: number;
}): Promise<AuditLog> {
const log = new AuditLog();
log.id = await AuditLog.getNewId();
log.actorId = data.actorId;
log.actorType = data.actorType || (data.actorId ? 'user' : 'anonymous');
log.actorTokenId = data.actorTokenId;
log.actorIp = data.actorIp;
log.actorUserAgent = data.actorUserAgent;
log.action = data.action;
log.resourceType = data.resourceType;
log.resourceId = data.resourceId;
log.resourceName = data.resourceName;
log.organizationId = data.organizationId;
log.repositoryId = data.repositoryId;
log.metadata = data.metadata || {};
log.success = data.success ?? true;
log.errorCode = data.errorCode;
log.errorMessage = data.errorMessage;
log.durationMs = data.durationMs;
log.timestamp = new Date();
await log.save();
return log;
}
/**
* Query audit logs with filters
*/
public static async query(filters: {
actorId?: string;
organizationId?: string;
repositoryId?: string;
resourceType?: TAuditResourceType;
action?: TAuditAction[];
success?: boolean;
startDate?: Date;
endDate?: Date;
offset?: number;
limit?: number;
}): Promise<{ logs: AuditLog[]; total: number }> {
const query: Record<string, unknown> = {};
if (filters.actorId) query.actorId = filters.actorId;
if (filters.organizationId) query.organizationId = filters.organizationId;
if (filters.repositoryId) query.repositoryId = filters.repositoryId;
if (filters.resourceType) query.resourceType = filters.resourceType;
if (filters.action) query.action = { $in: filters.action };
if (filters.success !== undefined) query.success = filters.success;
if (filters.startDate || filters.endDate) {
query.timestamp = {};
if (filters.startDate) (query.timestamp as Record<string, unknown>).$gte = filters.startDate;
if (filters.endDate) (query.timestamp as Record<string, unknown>).$lte = filters.endDate;
}
// Get total count
const allLogs = await AuditLog.getInstances(query);
const total = allLogs.length;
// Apply pagination
const offset = filters.offset || 0;
const limit = filters.limit || 100;
const logs = allLogs.slice(offset, offset + limit);
return { logs, total };
}
/**
* Lifecycle hook
*/
public async beforeSave(): Promise<void> {
if (!this.id) {
this.id = await AuditLog.getNewId();
}
}
}