Files
Edu/services/msg/src/notifications/notifications.controller.ts
SpecialX 416e1bc0b2 feat(msg): 修复通知服务并添加ES降级与Push Gateway推送
database.ts 导出db常量替代getDb()函数

env.ts JWT_SECRET/ES_URL改optional加DEV_MODE/PUSH_GATEWAY_URL

elasticsearch.ts ES降级: ES_URL未设置时esClient=null

notifications.service.ts 加createBatch+分页查询+Push Gateway推送调用

新建msg-init.sql创建2张表
2026-07-09 09:08:57 +08:00

103 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
Body,
Controller,
Get,
HttpException,
HttpStatus,
Param,
Post,
Put,
Query,
Req,
} from "@nestjs/common";
import { NotificationsService } from "./notifications.service.js";
import type { SendNotificationDto } from "./notifications.service.js";
interface AuthedRequest {
headers: Record<string, string | string[] | undefined>;
}
/**
* 从请求头读取用户身份。
* Gateway 在通过鉴权后会注入 x-user-id如未注入开发模式或匿名请求返回 null。
*/
function getUserIdFromRequest(req: AuthedRequest): string | null {
const raw = req.headers["x-user-id"];
if (typeof raw === "string" && raw.length > 0) return raw;
return null;
}
@Controller("notifications")
export class NotificationsController {
constructor(private readonly service: NotificationsService) {}
@Post()
async send(@Body() body: unknown): Promise<{ success: true; data: unknown }> {
const result = await this.service.send(body as SendNotificationDto);
return { success: true, data: result };
}
@Post("batch")
async createBatch(
@Body() body: unknown,
): Promise<{ success: true; data: unknown }> {
const dtos = (body as SendNotificationDto[]) ?? [];
const result = await this.service.createBatch(dtos);
return { success: true, data: result };
}
@Get("user/:userId")
async listByUser(
@Param("userId") userId: string,
@Query("unread") unread: string,
): Promise<{ success: true; data: unknown }> {
const result = await this.service.listByUser(userId, unread === "true");
return { success: true, data: result };
}
@Get("user/:userId/page")
async listByUserPaginated(
@Param("userId") userId: string,
@Query("page") page: string,
@Query("pageSize") pageSize: string,
): Promise<{ success: true; data: unknown }> {
const pageNum = Number(page) > 0 ? Number(page) : 1;
const pageSizeNum = Number(pageSize) > 0 ? Number(pageSize) : 20;
const result = await this.service.listByUserWithPagination(
userId,
pageNum,
pageSizeNum,
);
return { success: true, data: result };
}
@Put(":id/read")
async markAsRead(@Param("id") id: string): Promise<{ success: true }> {
await this.service.markAsRead(id);
return { success: true };
}
@Get("search")
async search(
@Req() req: AuthedRequest,
@Query("q") q: string,
@Query("userId") userIdParam: string,
): Promise<{ success: true; data: unknown }> {
const userId = getUserIdFromRequest(req) ?? userIdParam;
if (!userId) {
throw new HttpException(
{
success: false,
error: {
code: "MSG_PERMISSION_DENIED",
message: "Missing user identity",
},
},
HttpStatus.FORBIDDEN,
);
}
const result = await this.service.search(userId, q);
return { success: true, data: result };
}
}