fix: clarify client amounts and log date filters
This commit is contained in:
@@ -431,10 +431,12 @@ export class AdminSystemLogsController {
|
||||
@Query('status') status?: string,
|
||||
@Query('keyword') keyword?: string,
|
||||
@Query('range') range?: string,
|
||||
@Query('createdAtFrom') createdAtFrom?: string,
|
||||
@Query('createdAtTo') createdAtTo?: string,
|
||||
@Query('page') page?: string,
|
||||
@Query('pageSize') pageSize?: string,
|
||||
) {
|
||||
return this.protocolLogs.list({ protocol, direction, eventType, status, keyword, range, page: Number(page), pageSize: Number(pageSize) });
|
||||
return this.protocolLogs.list({ protocol, direction, eventType, status, keyword, range, createdAtFrom, createdAtTo, page: Number(page), pageSize: Number(pageSize) });
|
||||
}
|
||||
|
||||
@Get()
|
||||
@@ -445,14 +447,16 @@ export class AdminSystemLogsController {
|
||||
@Query('level') level?: string,
|
||||
@Query('module') module?: string,
|
||||
@Query('range') range?: string,
|
||||
@Query('createdAtFrom') createdAtFrom?: string,
|
||||
@Query('createdAtTo') createdAtTo?: string,
|
||||
@Query('page') page?: string,
|
||||
@Query('pageSize') pageSize?: string,
|
||||
) {
|
||||
return this.operations.systemLogs({ tenantId, userId, keyword, level, module, range, page: Number(page), pageSize: Number(pageSize) });
|
||||
return this.operations.systemLogs({ tenantId, userId, keyword, level, module, range, createdAtFrom, createdAtTo, page: Number(page), pageSize: Number(pageSize) });
|
||||
}
|
||||
|
||||
@Post('exports')
|
||||
export(@Body() body: { tenantId?: string; userId?: string; keyword?: string; level?: string; module?: string; range?: string }) {
|
||||
export(@Body() body: { tenantId?: string; userId?: string; keyword?: string; level?: string; module?: string; range?: string; createdAtFrom?: string; createdAtTo?: string }) {
|
||||
return this.operations.exportSystemLogs(body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,16 +67,18 @@ export class ClientOperationsController {
|
||||
@Query('level') level?: string,
|
||||
@Query('module') module?: string,
|
||||
@Query('range') range?: string,
|
||||
@Query('createdAtFrom') createdAtFrom?: string,
|
||||
@Query('createdAtTo') createdAtTo?: string,
|
||||
@Query('page') page?: string,
|
||||
@Query('pageSize') pageSize?: string,
|
||||
) {
|
||||
return this.operations.systemLogs({ tenantId, keyword, level, module, range, page: Number(page), pageSize: Number(pageSize) });
|
||||
return this.operations.systemLogs({ tenantId, keyword, level, module, range, createdAtFrom, createdAtTo, page: Number(page), pageSize: Number(pageSize) });
|
||||
}
|
||||
|
||||
@Post('system-logs/exports')
|
||||
exportSystemLogs(
|
||||
@CurrentSessionUserId() userId: string | undefined,
|
||||
@Body() body: { keyword?: string; level?: string; module?: string; range?: string },
|
||||
@Body() body: { keyword?: string; level?: string; module?: string; range?: string; createdAtFrom?: string; createdAtTo?: string },
|
||||
) {
|
||||
return this.operations.exportSystemLogs(body, userId);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ export interface OperationLogQuery {
|
||||
level?: string;
|
||||
module?: string;
|
||||
range?: string;
|
||||
createdAtFrom?: string;
|
||||
createdAtTo?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
@@ -890,6 +890,22 @@ describe('OperationsService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('applies an explicit Beijing date interval to operation logs', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
const service = new OperationsService(prisma as never);
|
||||
|
||||
await service.systemLogs({ createdAtFrom: '2026-08-21', createdAtTo: '2026-08-27' });
|
||||
|
||||
expect(prisma.operationLog.findMany).toHaveBeenCalledWith(expect.objectContaining({
|
||||
where: expect.objectContaining({
|
||||
createdAt: {
|
||||
gte: new Date('2026-08-20T16:00:00.000Z'),
|
||||
lte: new Date('2026-08-27T15:59:59.999Z'),
|
||||
},
|
||||
}),
|
||||
}));
|
||||
});
|
||||
|
||||
it('exports filtered operation logs with a traceable operation id', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
const service = new OperationsService(prisma as never);
|
||||
|
||||
@@ -31,7 +31,7 @@ async systemLogs(query: OperationLogQuery) {
|
||||
const where: Prisma.OperationLogWhereInput = {
|
||||
tenantId: query.tenantId,
|
||||
userId: query.userId,
|
||||
createdAt: createdAtRange(query.range),
|
||||
createdAt: this.operationLogDateRange(query),
|
||||
resource: query.module && query.module !== 'all' ? query.module : undefined,
|
||||
AND: query.level && query.level !== 'all' ? operationLogLevelWhere(query.level) : undefined,
|
||||
OR: query.keyword ? [
|
||||
@@ -73,7 +73,7 @@ async exportSystemLogs(query: OperationLogQuery, clientUserId?: string) {
|
||||
const where: Prisma.OperationLogWhereInput = {
|
||||
tenantId: effectiveQuery.tenantId,
|
||||
userId: effectiveQuery.userId,
|
||||
createdAt: createdAtRange(effectiveQuery.range),
|
||||
createdAt: this.operationLogDateRange(effectiveQuery),
|
||||
resource: effectiveQuery.module && effectiveQuery.module !== 'all' ? effectiveQuery.module : undefined,
|
||||
AND: effectiveQuery.level && effectiveQuery.level !== 'all' ? operationLogLevelWhere(effectiveQuery.level) : undefined,
|
||||
OR: effectiveQuery.keyword ? [
|
||||
@@ -107,9 +107,14 @@ async exportSystemLogs(query: OperationLogQuery, clientUserId?: string) {
|
||||
recordCount: exportedRows.length,
|
||||
truncated,
|
||||
content: [headers, ...values].map((row) => row.map((cell) => escapeCsvCell(String(cell ?? ''))).join(',')).join('\n'),
|
||||
filters: { keyword: effectiveQuery.keyword, level: effectiveQuery.level, module: effectiveQuery.module, range: effectiveQuery.range },
|
||||
filters: { keyword: effectiveQuery.keyword, level: effectiveQuery.level, module: effectiveQuery.module, range: effectiveQuery.range, createdAtFrom: effectiveQuery.createdAtFrom, createdAtTo: effectiveQuery.createdAtTo },
|
||||
};
|
||||
}
|
||||
private operationLogDateRange(query: OperationLogQuery) {
|
||||
const createdAtFrom = parseDateBoundary(query.createdAtFrom, false);
|
||||
const createdAtTo = parseDateBoundary(query.createdAtTo, true);
|
||||
return createdAtFrom || createdAtTo ? { gte: createdAtFrom, lte: createdAtTo } : createdAtRange(query.range);
|
||||
}
|
||||
private async resolveClientTenantId(userId: string) {
|
||||
const user = await this.prisma.user.findFirst({
|
||||
where: { id: userId, status: 'active', deletedAt: null, tenantId: { not: null } },
|
||||
|
||||
@@ -76,4 +76,18 @@ describe('ProtocolLogsService', () => {
|
||||
}),
|
||||
}));
|
||||
});
|
||||
|
||||
it('applies an explicit Beijing date interval to protocol logs', async () => {
|
||||
const service = new ProtocolLogsService(prisma as never);
|
||||
await service.list({ createdAtFrom: '2026-08-21', createdAtTo: '2026-08-27' });
|
||||
|
||||
expect(prisma.protocolInteractionLog.findMany).toHaveBeenCalledWith(expect.objectContaining({
|
||||
where: expect.objectContaining({
|
||||
createdAt: {
|
||||
gte: new Date('2026-08-20T16:00:00.000Z'),
|
||||
lte: new Date('2026-08-27T15:59:59.999Z'),
|
||||
},
|
||||
}),
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { parseDateBoundary } from '../operations/operations.helpers';
|
||||
|
||||
export type ProtocolLogInput = {
|
||||
protocol: 'cmpp' | 'http';
|
||||
@@ -34,6 +35,8 @@ export type ProtocolLogQuery = {
|
||||
status?: string;
|
||||
keyword?: string;
|
||||
range?: string;
|
||||
createdAtFrom?: string;
|
||||
createdAtTo?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
};
|
||||
@@ -115,7 +118,7 @@ export class ProtocolLogsService implements OnModuleInit, OnModuleDestroy {
|
||||
direction: selected(query.direction),
|
||||
eventType: selected(query.eventType),
|
||||
status: selected(query.status),
|
||||
createdAt: rangeWhere(query.range),
|
||||
createdAt: protocolLogDateRange(query),
|
||||
OR: query.keyword ? [
|
||||
{ messageId: { contains: query.keyword } },
|
||||
{ gatewayMessageId: { contains: query.keyword } },
|
||||
@@ -197,6 +200,12 @@ function rangeWhere(range?: string): Prisma.DateTimeFilter | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function protocolLogDateRange(query: ProtocolLogQuery): Prisma.DateTimeFilter | undefined {
|
||||
const createdAtFrom = parseDateBoundary(query.createdAtFrom, false);
|
||||
const createdAtTo = parseDateBoundary(query.createdAtTo, true);
|
||||
return createdAtFrom || createdAtTo ? { gte: createdAtFrom, lte: createdAtTo } : rangeWhere(query.range);
|
||||
}
|
||||
|
||||
function sanitizeDetail(detail?: Record<string, unknown> | null): Prisma.InputJsonValue | undefined {
|
||||
if (!detail) return undefined;
|
||||
const blocked = /password|secret|token|signature|authorization|content|raw|body/i;
|
||||
|
||||
Reference in New Issue
Block a user