test: harden business boundary conditions

This commit is contained in:
2026-07-15 00:03:55 +08:00
parent 17a5046ea0
commit b1f35f9d1a
65 changed files with 2311 additions and 293 deletions

View File

@@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common';
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Subject, Observable } from 'rxjs';
@@ -18,7 +18,10 @@ export class NotificationsService {
) {}
async create(dto: CreateNotificationDto): Promise<Notification[]> {
const notifications = dto.recipientIds.map((recipientId) => ({
const recipientIds = [...new Set(dto.recipientIds)];
if (recipientIds.length === 0) throw new BadRequestException('通知接收人不能为空');
const notifications = recipientIds.map((recipientId) => ({
recipientId,
type: dto.type,
title: dto.title,
@@ -36,16 +39,13 @@ export class NotificationsService {
return saved;
}
async findByUser(
userId: number,
after?: number,
limit: number = 20,
): Promise<Notification[]> {
async findByUser(userId: number, after?: number, limit: number = 20): Promise<Notification[]> {
const safeLimit = Math.min(Math.max(limit, 1), 100);
const qb = this.repo
.createQueryBuilder('n')
.where('n.recipientId = :userId', { userId })
.orderBy('n.createdAt', 'DESC')
.take(limit);
.take(safeLimit);
if (after !== undefined) {
qb.andWhere('n.id < :after', { after });
@@ -61,10 +61,10 @@ export class NotificationsService {
}
async markRead(id: number, userId: number): Promise<void> {
await this.repo.update(
{ id, recipientId: userId },
{ isRead: true, readAt: new Date() },
);
const notification = await this.repo.findOne({ where: { id, recipientId: userId } });
if (!notification) throw new NotFoundException('通知不存在');
if (notification.isRead) return;
await this.repo.update({ id, recipientId: userId }, { isRead: true, readAt: new Date() });
}
async markAllRead(userId: number): Promise<void> {