Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 56 additions & 36 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
import { Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import { TypeOrmModule } from "@nestjs/typeorm";
import { ScheduleModule } from "@nestjs/schedule";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { UsersModule } from "./users/users.module";
import { AuthModule } from "./auth/auth.module";
import { ApiKeysModule } from "./api-keys/api-keys.module";
import { OrganizationUnitsModule } from "./organization-units/organization-units.module";
import { ChangeLogModule } from "./change-log/change-log.module";
import { BarcodeModule } from "./barcode/barcode.module";
import { ComplianceModule } from "./compliance/compliance.module";
import { MobileDevicesModule } from "./mobile-devices/mobile-devices.module";
import { PolicyDocumentsModule } from "./policy-documents/policy-documents.module";
import { DeviceHealthModule } from "./device-health/device-health.module";
import { QRCodeModule } from "./QR-Code/qrcode.module";
import { NotificationsModule } from "./notifications/notifications.module";
import { StatusHistoryModule } from "./status-history/status-history.module";
import { DisposalRegistryModule } from "./disposal-registry/disposal-registry.module";
import { VendorDirectoryModule } from "./vendor-directory/vendor-directory.module";
import { WebhooksModule } from "./webhooks/webhooks.module";
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ScheduleModule } from '@nestjs/schedule';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';
import { AuthModule } from './auth/auth.module';
// import { ApiKeysModule } from "./api-keys/api-keys.module";
// import { OrganizationUnitsModule } from "./organization-units/organization-units.module";
// import { ChangeLogModule } from "./change-log/change-log.module";
// import { BarcodeModule } from "./barcode/barcode.module";
// import { ComplianceModule } from "./compliance/compliance.module";
// import { MobileDevicesModule } from "./mobile-devices/mobile-devices.module";
// import { PolicyDocumentsModule } from "./policy-documents/policy-documents.module";
// import { DeviceHealthModule } from "./device-health/device-health.module";
// import { QRCodeModule } from "./QR-Code/qrcode.module";
// import { NotificationsModule } from "./notifications/notifications.module";
// import { StatusHistoryModule } from "./status-history/status-history.module";
// import { DisposalRegistryModule } from "./disposal-registry/disposal-registry.module";
// import { VendorDirectoryModule } from "./vendor-directory/vendor-directory.module";
import { WebhooksModule } from './webhooks/webhooks.module';
import { AuditLogsModule } from './audit-logs/audit-logs.module';
import { AuditLoggingInterceptor } from './audit-logs/audit-logging.interceptor';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { AssetCategory } from './asset-categories/asset-category.entity';
import { Department } from './departments/department.entity';
import { User } from './users/entities/user.entity';
import { FileUpload } from './file-uploads/entities/file-upload.entity';
import { Asset } from './assets/entities/assest.entity';
import { Supplier } from './suppliers/entities/supplier.entity';
import { AssetCategoriesModule } from './asset-categories/asset-categories.module';
import { DepartmentsModule } from './departments/departments.module';
import { AssetTransfersModule } from './asset-transfers/asset-transfers.module';
import { SearchModule } from './search/search.module';

@Module({
imports: [
Expand Down Expand Up @@ -54,22 +67,29 @@ import { WebhooksModule } from "./webhooks/webhooks.module";
UsersModule,
SearchModule,
AuthModule,
ApiKeysModule,
OrganizationUnitsModule,
ChangeLogModule,
BarcodeModule,
ComplianceModule,
MobileDevicesModule,
PolicyDocumentsModule,
DeviceHealthModule,
QRCodeModule,
NotificationsModule,
StatusHistoryModule,
DisposalRegistryModule,
VendorDirectoryModule,
// ApiKeysModule,
// OrganizationUnitsModule,
// ChangeLogModule,
// BarcodeModule,
// ComplianceModule,
// MobileDevicesModule,
// PolicyDocumentsModule,
// DeviceHealthModule,
// QRCodeModule,
// NotificationsModule,
// StatusHistoryModule,
// DisposalRegistryModule,
// VendorDirectoryModule,
WebhooksModule,
AuditLogsModule,
],
controllers: [AppController],
providers: [AppService],
providers: [
{
provide: APP_INTERCEPTOR,
useClass: AuditLoggingInterceptor,
},
AppService,
],
})
export class AppModule {}
54 changes: 54 additions & 0 deletions backend/src/audit-logs/audit-logging.interceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { AuditLogsService } from './audit-logs.service';

@Injectable()
export class AuditLoggingInterceptor implements NestInterceptor {
constructor(private readonly auditLogsService: AuditLogsService) {}

intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const req = context.switchToHttp().getRequest();

const user = req.user; // Assumes authentication middleware adds user info
const userId = user ? user.id : null;

const method = req.method;
const url = req.url;

// Customize this logic to map HTTP verbs to action names:
const actionMap = {
GET: 'Read',
POST: 'Create',
PATCH: 'Update',
PUT: 'Replace',
DELETE: 'Delete',
};
const action = actionMap[method] || method;

// Extract entity info from URL, e.g., /branches, /assets/123
const entity = url.split('/')[1] || 'unknown';

return next.handle().pipe(
tap(async () => {
// Optionally, you can add more metadata like request params or body here
await this.auditLogsService.createLog({
action,
entity,
userId,
timestamp: new Date(),
metadata: {
params: req.params,
query: req.query,
body: req.body,
},
});
}),
);
}
}
11 changes: 11 additions & 0 deletions backend/src/audit-logs/audit-logs.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuditLog } from './entities/audit-log.entity';
import { AuditLogsService } from './audit-logs.service';

@Module({
imports: [TypeOrmModule.forFeature([AuditLog])],
providers: [AuditLogsService],
exports: [AuditLogsService],
})
export class AuditLogsModule {}
17 changes: 17 additions & 0 deletions backend/src/audit-logs/audit-logs.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { AuditLog } from './entities/audit-log.entity';

@Injectable()
export class AuditLogsService {
constructor(
@InjectRepository(AuditLog)
private auditLogRepository: Repository<AuditLog>,
) {}

async createLog(data: Partial<AuditLog>): Promise<AuditLog> {
const log = this.auditLogRepository.create(data);
return this.auditLogRepository.save(log);
}
}
27 changes: 27 additions & 0 deletions backend/src/audit-logs/entities/audit-log.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
Entity,
Column,
PrimaryGeneratedColumn,
CreateDateColumn,
} from 'typeorm';

@Entity('audit_logs')
export class AuditLog {
@PrimaryGeneratedColumn()
id: number;

@Column()
action: string;

@Column()
entity: string;

@Column({ nullable: true })
userId: number;

@CreateDateColumn()
timestamp: Date;

@Column({ type: 'jsonb', nullable: true })
metadata?: Record<string, any>; // Optional JSON metadata about the action
}