feat: tíng năng trò chuyện giữa các thành viên và tin nhắn trực tiếp cho bạn bè
This commit is contained in:
1 parent
392a4d4766
commit
8d79cd76f6
15 files changed
+3932
-234
No files matched your search
Vendored
+12
-8
@@ -6,6 +6,18 @@ import { ParticipantRole } from '@prisma/client';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { CanActivate, ExecutionContext } from '@nestjs/common';
|
||||
import { Cache } from 'cache-manager';
|
||||
export declare class CommentGateway implements OnGatewayConnection {
|
||||
server: Server;
|
||||
handleConnection(client: Socket): void;
|
||||
handleJoinTour(client: Socket, tourId: string): void;
|
||||
handleJoinPhoto(client: Socket, photoId: string): void;
|
||||
notifyNewComment(tourId: string, data: any): void;
|
||||
notifyNewPhotoComment(photoId: string, data: any): void;
|
||||
handleJoinUser(client: Socket, userId: string): void;
|
||||
notifyNewMessage(receiverId: string, data: any): void;
|
||||
notifyConnectionAccepted(requesterId: string, data: any): void;
|
||||
notifyJoinRequestAccepted(userId: string, data: any): void;
|
||||
}
|
||||
export declare const ROLES_KEY = "roles";
|
||||
export declare const Roles: (...roles: ParticipantRole[]) => import("@nestjs/common").CustomDecorator<string>;
|
||||
export declare class TourRoleGuard implements CanActivate {
|
||||
@@ -21,11 +33,3 @@ export declare class EmailService {
|
||||
sendOTP(email: string, otp: string): Promise<any>;
|
||||
sendTourInvitation(email: string, tourTitle: string, inviteLink: string): Promise<any>;
|
||||
}
|
||||
export declare class CommentGateway implements OnGatewayConnection {
|
||||
server: Server;
|
||||
handleConnection(client: Socket): void;
|
||||
handleJoinTour(client: Socket, tourId: string): void;
|
||||
handleJoinPhoto(client: Socket, photoId: string): void;
|
||||
notifyNewComment(tourId: string, data: any): void;
|
||||
notifyNewPhotoComment(photoId: string, data: any): void;
|
||||
}
|
||||
Vendored
+484
-43
@@ -48,7 +48,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CommentGateway = exports.EmailService = exports.TourRoleGuard = exports.Roles = exports.ROLES_KEY = void 0;
|
||||
exports.EmailService = exports.TourRoleGuard = exports.Roles = exports.ROLES_KEY = exports.CommentGateway = void 0;
|
||||
const path = __importStar(require("path"));
|
||||
const fs = __importStar(require("fs"));
|
||||
const crypto = __importStar(require("crypto"));
|
||||
@@ -80,6 +80,64 @@ const compress_cache_interceptor_1 = require("./common/compress-cache.intercepto
|
||||
const gzip = (0, util_1.promisify)(zlib.gzip);
|
||||
const gunzip = (0, util_1.promisify)(zlib.gunzip);
|
||||
const UPLOAD_ROOT = path.join(process.cwd(), 'uploads');
|
||||
let CommentGateway = class CommentGateway {
|
||||
handleConnection(client) {
|
||||
console.log(`[WS] Client connected: ${client.id}`);
|
||||
}
|
||||
handleJoinTour(client, tourId) {
|
||||
client.join(`tour_${tourId}`);
|
||||
console.log(`[WS] Client ${client.id} joined room: tour_${tourId}`);
|
||||
}
|
||||
handleJoinPhoto(client, photoId) {
|
||||
client.join(`photo_${photoId}`);
|
||||
console.log(`[WS] Client ${client.id} joined room: photo_${photoId}`);
|
||||
}
|
||||
notifyNewComment(tourId, data) {
|
||||
this.server.to(`tour_${tourId}`).emit('commentAdded', data);
|
||||
}
|
||||
notifyNewPhotoComment(photoId, data) {
|
||||
this.server.to(`photo_${photoId}`).emit('photoCommentAdded', data);
|
||||
}
|
||||
handleJoinUser(client, userId) {
|
||||
client.join(`user_${userId}`);
|
||||
console.log(`[WS] Client ${client.id} joined user room: user_${userId}`);
|
||||
}
|
||||
notifyNewMessage(receiverId, data) {
|
||||
this.server.to(`user_${receiverId}`).emit('messageReceived', data);
|
||||
}
|
||||
notifyConnectionAccepted(requesterId, data) {
|
||||
this.server.to(`user_${requesterId}`).emit('connectionAccepted', data);
|
||||
}
|
||||
notifyJoinRequestAccepted(userId, data) {
|
||||
this.server.to(`user_${userId}`).emit('joinRequestAccepted', data);
|
||||
}
|
||||
};
|
||||
exports.CommentGateway = CommentGateway;
|
||||
__decorate([
|
||||
(0, websockets_1.WebSocketServer)(),
|
||||
__metadata("design:type", socket_io_1.Server)
|
||||
], CommentGateway.prototype, "server", void 0);
|
||||
__decorate([
|
||||
(0, websockets_1.SubscribeMessage)('joinTour'),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [socket_io_1.Socket, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CommentGateway.prototype, "handleJoinTour", null);
|
||||
__decorate([
|
||||
(0, websockets_1.SubscribeMessage)('joinPhoto'),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [socket_io_1.Socket, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CommentGateway.prototype, "handleJoinPhoto", null);
|
||||
__decorate([
|
||||
(0, websockets_1.SubscribeMessage)('joinUser'),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [socket_io_1.Socket, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CommentGateway.prototype, "handleJoinUser", null);
|
||||
exports.CommentGateway = CommentGateway = __decorate([
|
||||
(0, websockets_1.WebSocketGateway)({ cors: { origin: '*' } })
|
||||
], CommentGateway);
|
||||
const CACHE_TTL = {
|
||||
DEFAULT: 600000,
|
||||
RESOURCE_TO_TOUR: 3600000,
|
||||
@@ -454,6 +512,7 @@ let AuthController = class AuthController {
|
||||
name: user.name,
|
||||
avatar: user.avatar,
|
||||
isAdmin: user.isAdmin,
|
||||
isGoogle: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -653,10 +712,11 @@ PublicTourController = __decorate([
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
|
||||
], PublicTourController);
|
||||
let TourController = class TourController {
|
||||
constructor(prisma, emailService, cacheManager) {
|
||||
constructor(prisma, emailService, cacheManager, commentGateway) {
|
||||
this.prisma = prisma;
|
||||
this.emailService = emailService;
|
||||
this.cacheManager = cacheManager;
|
||||
this.commentGateway = commentGateway;
|
||||
}
|
||||
async createTour(body, req) {
|
||||
const { title, description, startDate, endDate, adultCount, childCount, childDiscount, tags, members } = body;
|
||||
@@ -1213,6 +1273,15 @@ let TourController = class TourController {
|
||||
data: { status: 'ACCEPTED' },
|
||||
}),
|
||||
]);
|
||||
const tour = await this.prisma.tour.findUnique({
|
||||
where: { id: tourId },
|
||||
select: { title: true }
|
||||
});
|
||||
this.commentGateway.notifyJoinRequestAccepted(joinRequest.userId, {
|
||||
tourId,
|
||||
tourTitle: tour?.title || 'Hành trình',
|
||||
requestId
|
||||
});
|
||||
return { success: true, message: 'Đã chấp nhận yêu cầu tham gia.' };
|
||||
}
|
||||
async rejectJoinRequest(tourId, requestId, req) {
|
||||
@@ -1707,7 +1776,7 @@ TourController = __decorate([
|
||||
(0, common_1.Controller)('tours'),
|
||||
__param(2, (0, common_1.Inject)(cache_manager_1.CACHE_MANAGER)),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
|
||||
EmailService, Object])
|
||||
EmailService, Object, CommentGateway])
|
||||
], TourController);
|
||||
let LocationController = class LocationController {
|
||||
constructor(prisma, cacheManager) {
|
||||
@@ -2361,45 +2430,6 @@ UserController = __decorate([
|
||||
(0, exports.Roles)(client_1.ParticipantRole.OWNER, client_1.ParticipantRole.MANAGER),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
|
||||
], UserController);
|
||||
let CommentGateway = class CommentGateway {
|
||||
handleConnection(client) {
|
||||
console.log(`[WS] Client connected: ${client.id}`);
|
||||
}
|
||||
handleJoinTour(client, tourId) {
|
||||
client.join(`tour_${tourId}`);
|
||||
console.log(`[WS] Client ${client.id} joined room: tour_${tourId}`);
|
||||
}
|
||||
handleJoinPhoto(client, photoId) {
|
||||
client.join(`photo_${photoId}`);
|
||||
console.log(`[WS] Client ${client.id} joined room: photo_${photoId}`);
|
||||
}
|
||||
notifyNewComment(tourId, data) {
|
||||
this.server.to(`tour_${tourId}`).emit('commentAdded', data);
|
||||
}
|
||||
notifyNewPhotoComment(photoId, data) {
|
||||
this.server.to(`photo_${photoId}`).emit('photoCommentAdded', data);
|
||||
}
|
||||
};
|
||||
exports.CommentGateway = CommentGateway;
|
||||
__decorate([
|
||||
(0, websockets_1.WebSocketServer)(),
|
||||
__metadata("design:type", socket_io_1.Server)
|
||||
], CommentGateway.prototype, "server", void 0);
|
||||
__decorate([
|
||||
(0, websockets_1.SubscribeMessage)('joinTour'),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [socket_io_1.Socket, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CommentGateway.prototype, "handleJoinTour", null);
|
||||
__decorate([
|
||||
(0, websockets_1.SubscribeMessage)('joinPhoto'),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [socket_io_1.Socket, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CommentGateway.prototype, "handleJoinPhoto", null);
|
||||
exports.CommentGateway = CommentGateway = __decorate([
|
||||
(0, websockets_1.WebSocketGateway)({ cors: { origin: '*' } })
|
||||
], CommentGateway);
|
||||
let CommentController = class CommentController {
|
||||
constructor(prisma, commentGateway) {
|
||||
this.prisma = prisma;
|
||||
@@ -2961,6 +2991,417 @@ PublicPhotoController = __decorate([
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
|
||||
CommentGateway])
|
||||
], PublicPhotoController);
|
||||
let ConnectionController = class ConnectionController {
|
||||
constructor(prisma, commentGateway) {
|
||||
this.prisma = prisma;
|
||||
this.commentGateway = commentGateway;
|
||||
}
|
||||
async getConnections(req) {
|
||||
const currentUserId = req.user.id;
|
||||
const connections = await this.prisma.userConnection.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{ requesterId: currentUserId },
|
||||
{ receiverId: currentUserId }
|
||||
],
|
||||
status: 'ACCEPTED'
|
||||
},
|
||||
include: {
|
||||
requester: { select: { id: true, name: true, email: true, avatar: true } },
|
||||
receiver: { select: { id: true, name: true, email: true, avatar: true } }
|
||||
}
|
||||
});
|
||||
const formattedConnections = connections.map(conn => {
|
||||
const isRequester = conn.requesterId === currentUserId;
|
||||
const targetUser = isRequester ? conn.receiver : conn.requester;
|
||||
return {
|
||||
id: conn.id,
|
||||
targetUser,
|
||||
type: conn.type,
|
||||
status: conn.status,
|
||||
createdAt: conn.createdAt
|
||||
};
|
||||
});
|
||||
const receivedRequests = await this.prisma.userConnection.findMany({
|
||||
where: {
|
||||
receiverId: currentUserId,
|
||||
status: 'PENDING'
|
||||
},
|
||||
include: {
|
||||
requester: { select: { id: true, name: true, email: true, avatar: true } }
|
||||
}
|
||||
});
|
||||
const sentRequests = await this.prisma.userConnection.findMany({
|
||||
where: {
|
||||
requesterId: currentUserId,
|
||||
status: 'PENDING'
|
||||
},
|
||||
include: {
|
||||
receiver: { select: { id: true, name: true, email: true, avatar: true } }
|
||||
}
|
||||
});
|
||||
return {
|
||||
connections: formattedConnections,
|
||||
receivedRequests: receivedRequests.map(r => ({ id: r.id, requester: r.requester, type: r.type, createdAt: r.createdAt })),
|
||||
sentRequests: sentRequests.map(r => ({ id: r.id, receiver: r.receiver, type: r.type, createdAt: r.createdAt }))
|
||||
};
|
||||
}
|
||||
async sendRequest(req, body) {
|
||||
const requesterId = req.user.id;
|
||||
const { receiverId } = body;
|
||||
if (requesterId === receiverId) {
|
||||
throw new common_1.BadRequestException('Bạn không thể gửi lời mời kết nối cho chính mình.');
|
||||
}
|
||||
const receiver = await this.prisma.user.findUnique({ where: { id: receiverId } });
|
||||
if (!receiver) {
|
||||
throw new common_1.NotFoundException('Không tìm thấy người nhận.');
|
||||
}
|
||||
const existing = await this.prisma.userConnection.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{ requesterId, receiverId },
|
||||
{ requesterId: receiverId, receiverId }
|
||||
]
|
||||
}
|
||||
});
|
||||
if (existing) {
|
||||
if (existing.status === 'ACCEPTED') {
|
||||
throw new common_1.BadRequestException('Hai bạn đã kết nối với nhau.');
|
||||
}
|
||||
if (existing.status === 'PENDING') {
|
||||
throw new common_1.BadRequestException('Yêu cầu kết nối đang chờ xử lý.');
|
||||
}
|
||||
await this.prisma.userConnection.delete({ where: { id: existing.id } });
|
||||
}
|
||||
const newConn = await this.prisma.userConnection.create({
|
||||
data: {
|
||||
requesterId,
|
||||
receiverId,
|
||||
status: 'PENDING',
|
||||
type: 'FRIEND'
|
||||
}
|
||||
});
|
||||
return { success: true, connection: newConn };
|
||||
}
|
||||
async updateRequest(id, body, req) {
|
||||
const currentUserId = req.user.id;
|
||||
const conn = await this.prisma.userConnection.findUnique({ where: { id } });
|
||||
if (!conn) {
|
||||
throw new common_1.NotFoundException('Không tìm thấy bản ghi kết nối.');
|
||||
}
|
||||
if (body.status) {
|
||||
if (conn.receiverId !== currentUserId) {
|
||||
throw new common_1.ForbiddenException('Bạn không có quyền thực hiện hành động này.');
|
||||
}
|
||||
const updated = await this.prisma.userConnection.update({
|
||||
where: { id },
|
||||
data: { status: body.status }
|
||||
});
|
||||
if (body.status === 'ACCEPTED') {
|
||||
const receiverUser = await this.prisma.user.findUnique({
|
||||
where: { id: currentUserId },
|
||||
select: { name: true }
|
||||
});
|
||||
this.commentGateway.notifyConnectionAccepted(conn.requesterId, {
|
||||
connectionId: conn.id,
|
||||
acceptedByName: receiverUser?.name || 'Ai đó',
|
||||
acceptedById: currentUserId
|
||||
});
|
||||
}
|
||||
return { success: true, connection: updated };
|
||||
}
|
||||
if (body.type) {
|
||||
if (conn.requesterId !== currentUserId && conn.receiverId !== currentUserId) {
|
||||
throw new common_1.ForbiddenException('Bạn không có quyền thực hiện hành động này.');
|
||||
}
|
||||
if (conn.status !== 'ACCEPTED') {
|
||||
throw new common_1.BadRequestException('Chỉ có thể thay đổi phân nhóm sau khi đã chấp nhận kết nối.');
|
||||
}
|
||||
const updated = await this.prisma.userConnection.update({
|
||||
where: { id },
|
||||
data: { type: body.type }
|
||||
});
|
||||
return { success: true, connection: updated };
|
||||
}
|
||||
throw new common_1.BadRequestException('Yêu cầu không hợp lệ.');
|
||||
}
|
||||
async deleteConnection(id, req) {
|
||||
const currentUserId = req.user.id;
|
||||
const conn = await this.prisma.userConnection.findUnique({ where: { id } });
|
||||
if (!conn) {
|
||||
throw new common_1.NotFoundException('Không tìm thấy bản ghi kết nối.');
|
||||
}
|
||||
if (conn.requesterId !== currentUserId && conn.receiverId !== currentUserId) {
|
||||
throw new common_1.ForbiddenException('Bạn không có quyền thực hiện hành động này.');
|
||||
}
|
||||
await this.prisma.userConnection.delete({ where: { id } });
|
||||
return { success: true, message: 'Đã hủy kết nối thành công.' };
|
||||
}
|
||||
};
|
||||
__decorate([
|
||||
(0, common_1.Get)(),
|
||||
__param(0, (0, common_1.Req)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], ConnectionController.prototype, "getConnections", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)(),
|
||||
__param(0, (0, common_1.Req)()),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], ConnectionController.prototype, "sendRequest", null);
|
||||
__decorate([
|
||||
(0, common_1.Patch)(':id'),
|
||||
__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__param(2, (0, common_1.Req)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, Object, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], ConnectionController.prototype, "updateRequest", null);
|
||||
__decorate([
|
||||
(0, common_1.Delete)(':id'),
|
||||
__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
|
||||
__param(1, (0, common_1.Req)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], ConnectionController.prototype, "deleteConnection", null);
|
||||
ConnectionController = __decorate([
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, common_1.Controller)('connections'),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
|
||||
CommentGateway])
|
||||
], ConnectionController);
|
||||
let DirectMessageController = class DirectMessageController {
|
||||
constructor(prisma, commentGateway) {
|
||||
this.prisma = prisma;
|
||||
this.commentGateway = commentGateway;
|
||||
}
|
||||
async getMessages(userId, req) {
|
||||
const currentUserId = req.user.id;
|
||||
const conn = await this.prisma.userConnection.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{ requesterId: currentUserId, receiverId: userId },
|
||||
{ requesterId: userId, receiverId: currentUserId }
|
||||
],
|
||||
status: 'ACCEPTED'
|
||||
}
|
||||
});
|
||||
if (!conn) {
|
||||
throw new common_1.ForbiddenException('Bạn chỉ có thể nhắn tin với người đã kết nối.');
|
||||
}
|
||||
const messages = await this.prisma.directMessage.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{ senderId: currentUserId, receiverId: userId },
|
||||
{ senderId: userId, receiverId: currentUserId }
|
||||
]
|
||||
},
|
||||
orderBy: { createdAt: 'asc' }
|
||||
});
|
||||
return messages;
|
||||
}
|
||||
async sendMessage(req, body) {
|
||||
const senderId = req.user.id;
|
||||
const { receiverId, content, attachmentUrl, latitude, longitude } = body;
|
||||
if ((!content || !content.trim()) && !attachmentUrl && latitude === undefined) {
|
||||
throw new common_1.BadRequestException('Tin nhắn phải có nội dung, ảnh đính kèm hoặc vị trí.');
|
||||
}
|
||||
const conn = await this.prisma.userConnection.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{ requesterId: senderId, receiverId: receiverId },
|
||||
{ requesterId: receiverId, receiverId: senderId }
|
||||
],
|
||||
status: 'ACCEPTED'
|
||||
}
|
||||
});
|
||||
if (!conn) {
|
||||
throw new common_1.ForbiddenException('Bạn chỉ có thể nhắn tin với người đã kết nối.');
|
||||
}
|
||||
const message = await this.prisma.directMessage.create({
|
||||
data: {
|
||||
senderId,
|
||||
receiverId,
|
||||
content: content || '',
|
||||
attachmentUrl,
|
||||
latitude,
|
||||
longitude
|
||||
},
|
||||
include: {
|
||||
sender: { select: { id: true, name: true, avatar: true } }
|
||||
}
|
||||
});
|
||||
this.commentGateway.notifyNewMessage(receiverId, message);
|
||||
return message;
|
||||
}
|
||||
};
|
||||
__decorate([
|
||||
(0, common_1.Get)(':userId'),
|
||||
__param(0, (0, common_1.Param)('userId', common_1.ParseUUIDPipe)),
|
||||
__param(1, (0, common_1.Req)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], DirectMessageController.prototype, "getMessages", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)(),
|
||||
__param(0, (0, common_1.Req)()),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], DirectMessageController.prototype, "sendMessage", null);
|
||||
DirectMessageController = __decorate([
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, common_1.Controller)('messages'),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
|
||||
CommentGateway])
|
||||
], DirectMessageController);
|
||||
let UploadController = class UploadController {
|
||||
async uploadAttachment(files) {
|
||||
if (!files || files.length === 0) {
|
||||
throw new common_1.BadRequestException('Vui lòng chọn ảnh.');
|
||||
}
|
||||
const file = files[0];
|
||||
const attachmentsDir = path.join(UPLOAD_ROOT, 'attachments');
|
||||
if (!fs.existsSync(attachmentsDir)) {
|
||||
fs.mkdirSync(attachmentsDir, { recursive: true });
|
||||
}
|
||||
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
|
||||
const extension = path.extname(file.originalname).toLowerCase() || '.jpg';
|
||||
const filename = `${uniqueSuffix}${extension}`;
|
||||
const filePath = path.join(attachmentsDir, filename);
|
||||
fs.writeFileSync(filePath, file.buffer);
|
||||
return {
|
||||
url: `/uploads/attachments/${filename}`
|
||||
};
|
||||
}
|
||||
};
|
||||
__decorate([
|
||||
(0, common_1.Post)(),
|
||||
(0, common_1.UseInterceptors)((0, platform_express_1.FilesInterceptor)('image', 1)),
|
||||
__param(0, (0, common_1.UploadedFiles)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Array]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], UploadController.prototype, "uploadAttachment", null);
|
||||
UploadController = __decorate([
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, common_1.Controller)('upload')
|
||||
], UploadController);
|
||||
let TourMessageController = class TourMessageController {
|
||||
constructor(prisma, commentGateway) {
|
||||
this.prisma = prisma;
|
||||
this.commentGateway = commentGateway;
|
||||
}
|
||||
async getTourMessages(tourId, req) {
|
||||
const userId = req.user.id;
|
||||
const participant = await this.prisma.tourParticipant.findFirst({
|
||||
where: { tourId, userId }
|
||||
});
|
||||
if (!participant) {
|
||||
throw new common_1.ForbiddenException('Bạn không phải là thành viên của hành trình này.');
|
||||
}
|
||||
const messages = await this.prisma.tourMessage.findMany({
|
||||
where: { tourId },
|
||||
include: {
|
||||
sender: { select: { id: true, name: true, avatar: true } }
|
||||
},
|
||||
orderBy: { createdAt: 'asc' }
|
||||
});
|
||||
return messages;
|
||||
}
|
||||
async sendTourMessage(tourId, req, body) {
|
||||
const senderId = req.user.id;
|
||||
const { content, attachmentUrl, latitude, longitude, taggedUserIds } = body;
|
||||
console.log(`[sendTourMessage] senderId=${senderId}, tourId=${tourId}, taggedUserIds=`, taggedUserIds);
|
||||
if ((!content || !content.trim()) && !attachmentUrl && latitude === undefined) {
|
||||
throw new common_1.BadRequestException('Tin nhắn phải có nội dung, ảnh đính kèm hoặc vị trí.');
|
||||
}
|
||||
const participant = await this.prisma.tourParticipant.findFirst({
|
||||
where: { tourId, userId: senderId }
|
||||
});
|
||||
if (!participant) {
|
||||
throw new common_1.ForbiddenException('Bạn không phải là thành viên của hành trình này.');
|
||||
}
|
||||
const tourMessage = await this.prisma.tourMessage.create({
|
||||
data: {
|
||||
tourId,
|
||||
senderId,
|
||||
content: content || '',
|
||||
attachmentUrl,
|
||||
latitude,
|
||||
longitude
|
||||
},
|
||||
include: {
|
||||
sender: { select: { id: true, name: true, avatar: true } }
|
||||
}
|
||||
});
|
||||
this.commentGateway.server.to(`tour_${tourId}`).emit('tourMessageReceived', {
|
||||
tourId,
|
||||
message: tourMessage
|
||||
});
|
||||
const hasTags = Array.isArray(taggedUserIds) && taggedUserIds.length > 0;
|
||||
const otherParticipants = await this.prisma.tourParticipant.findMany({
|
||||
where: {
|
||||
tourId,
|
||||
userId: {
|
||||
not: senderId,
|
||||
in: hasTags ? taggedUserIds : undefined
|
||||
},
|
||||
NOT: { userId: null }
|
||||
}
|
||||
});
|
||||
console.log(`[sendTourMessage] otherParticipants found count: ${otherParticipants.length}`, otherParticipants.map(o => o.userId));
|
||||
const tour = await this.prisma.tour.findUnique({
|
||||
where: { id: tourId },
|
||||
select: { title: true }
|
||||
});
|
||||
for (const p of otherParticipants) {
|
||||
if (p.userId) {
|
||||
const isTagged = hasTags && taggedUserIds.includes(p.userId);
|
||||
console.log(`[sendTourMessage] Emitting tourMessageNotification to user_${p.userId}, isTagged: ${isTagged}`);
|
||||
this.commentGateway.server.to(`user_${p.userId}`).emit('tourMessageNotification', {
|
||||
tourId,
|
||||
senderName: req.user.name || 'Thành viên',
|
||||
tourTitle: tour?.title || 'Hành trình',
|
||||
content: isTagged ? `@Bạn: ${content || ''}` : content || (attachmentUrl ? '[Hình ảnh]' : '[Vị trí]'),
|
||||
isTagged
|
||||
});
|
||||
}
|
||||
}
|
||||
return tourMessage;
|
||||
}
|
||||
};
|
||||
__decorate([
|
||||
(0, common_1.Get)(),
|
||||
__param(0, (0, common_1.Param)('tourId', common_1.ParseUUIDPipe)),
|
||||
__param(1, (0, common_1.Req)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TourMessageController.prototype, "getTourMessages", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)(),
|
||||
__param(0, (0, common_1.Param)('tourId', common_1.ParseUUIDPipe)),
|
||||
__param(1, (0, common_1.Req)()),
|
||||
__param(2, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, Object, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TourMessageController.prototype, "sendTourMessage", null);
|
||||
TourMessageController = __decorate([
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, common_1.Controller)('tours/:tourId/messages'),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
|
||||
CommentGateway])
|
||||
], TourMessageController);
|
||||
let AppModule = class AppModule {
|
||||
};
|
||||
AppModule = __decorate([
|
||||
@@ -2985,7 +3426,7 @@ AppModule = __decorate([
|
||||
signOptions: { expiresIn: '1d' },
|
||||
}),
|
||||
],
|
||||
controllers: [AppController, AuthController, PublicTourController, TourController, UserController, RoutingController, LegController, LocationController, CommentController, PhotoController, PublicPhotoController, AdminOtpController, AdminController],
|
||||
controllers: [AppController, AuthController, PublicTourController, TourController, UserController, RoutingController, LegController, LocationController, CommentController, PhotoController, PublicPhotoController, AdminOtpController, AdminController, ConnectionController, DirectMessageController, UploadController, TourMessageController],
|
||||
providers: [prisma_service_1.PrismaService, jwt_strategy_1.JwtStrategy, TourRoleGuard, jwt_auth_guard_1.JwtAuthGuard, admin_guard_1.AdminGuard, CommentGateway, core_2.Reflector, EmailService, config_1.ConfigService],
|
||||
exports: [prisma_service_1.PrismaService]
|
||||
})
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA6B;AAC7B,uCAAyB;AACzB,+CAAiC;AACjC,2CAA6D;AAE7D,4BAA0B;AAC1B,2CAA6B;AAC7B,+BAAiC;AACjC,kDAA0B;AAC1B,kDAA0B;AAC1B,gEAAuC;AACvC,uCAA2C;AAC3C,2CAAwS;AAExS,+DAA4D;AAE5D,mDAAmI;AACnI,yCAA2C;AAC3C,6DAAyD;AACzD,2CAAiD;AACjD,+CAAiC;AACjC,oDAAgD;AAChD,uDAAyC;AACzC,qCAAoD;AACpD,0DAAqD;AACrD,sDAAkD;AAClD,uCAAyC;AACzC,2CAA4E;AAC5E,yDAAmE;AAEnE,qEAAqD;AAErD,oFAA+E;AAG/E,MAAM,IAAI,GAAG,IAAA,gBAAS,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClC,MAAM,MAAM,GAAG,IAAA,gBAAS,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAGtC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;AAGxD,MAAM,SAAS,GAAG;IAChB,OAAO,EAAE,MAAM;IACf,gBAAgB,EAAE,OAAO;IACzB,SAAS,EAAE,MAAM;CAClB,CAAC;AAEF,KAAK,UAAU,SAAS;IAGtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAyB,SAAS,CAAC,CAAC;IACxE,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;IAE9B,GAAG,CAAC,UAAU,EAAE,CAAC;IAGjB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;IAGD,GAAG,CAAC,eAAe,CAAC,WAAW,EAAE;QAC/B,MAAM,EAAE,WAAW;KACpB,CAAC,CAAC;IAEH,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;AAChE,CAAC;AAGY,QAAA,SAAS,GAAG,OAAO,CAAC;AAC1B,MAAM,KAAK,GAAG,CAAC,GAAG,KAAwB,EAAE,EAAE,CAAC,IAAA,oBAAW,EAAC,iBAAS,EAAE,KAAK,CAAC,CAAC;AAAvE,QAAA,KAAK,SAAkE;AAK7E,IAAM,aAAa,GAAnB,MAAM,aAAa;IACxB,YACU,SAAoB,EACpB,MAAqB,EACE,YAAmB;QAF1C,cAAS,GAAT,SAAS,CAAW;QACpB,WAAM,GAAN,MAAM,CAAe;QACE,iBAAY,GAAZ,YAAY,CAAO;IACjD,CAAC;IAEJ,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAoB,iBAAS,EAAE;YACnF,OAAO,CAAC,UAAU,EAAE;YACpB,OAAO,CAAC,QAAQ,EAAE;SACnB,CAAC,CAAC;QAGH,MAAM,YAAY,GAAG,CAAC,wBAAe,CAAC,KAAK,EAAE,wBAAe,CAAC,OAAO,CAAC,CAAC;QACtE,MAAM,YAAY,GAAG,aAAa,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC;QAE9F,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QACpD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAE1B,IAAI,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;QACnC,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC;QAG1F,IAAI,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;YAC1B,MAAM,WAAW,GAAG,eAAe,UAAU,EAAE,CAAC;YAChD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAS,WAAW,CAAC,CAAC;YAExE,IAAI,cAAc,EAAE,CAAC;gBACnB,IAAI,CAAC;oBACH,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;oBAClD,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC;gBACnC,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAC;gBAC1C,CAAC;YACH,CAAC;iBAAM,CAAC;gBAER,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;gBACtG,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,GAAG,UAAU,CAAC;gBACtB,CAAC;qBAAM,CAAC;oBAEN,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;oBACtG,IAAI,GAAG,EAAE,CAAC;wBACR,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;oBACtB,CAAC;yBAAM,CAAC;wBAEN,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;4BAChD,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE;4BACzB,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;yBAC/C,CAAC,CAAC;wBACH,IAAI,GAAG,EAAE,CAAC;4BACR,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;wBAC1B,CAAC;6BAAM,CAAC;4BAEN,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;4BAC5H,IAAI,KAAK,EAAE,CAAC;gCACV,IAAI,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC,EAAE;oCAAE,OAAO,IAAI,CAAC;gCACtD,IAAI,CAAC,KAAK,CAAC,MAAM;oCAAE,OAAO,IAAI,CAAC;gCAC/B,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;4BACxB,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;gBAEC,IAAI,MAAM,EAAE,CAAC;oBACX,IAAI,CAAC;wBACH,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;wBACnD,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,SAAS,CAAC,gBAAgB,CAAC,CAAC;oBACnF,CAAC;oBAAC,OAAO,CAAC,EAAE,CAAC;wBACX,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,gBAAgB,CAAC,CAAC;oBAC/E,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAGrB,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM;gBAAE,OAAO,IAAI,CAAC;YACvD,OAAO,KAAK,CAAC;QACf,CAAC;QAGD,MAAM,YAAY,GAAG,aAAa,IAAI,CAAC,EAAE,IAAI,MAAM,EAAE,CAAC;QACtD,IAAI,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAkB,YAAY,CAAC,CAAC;QAEtE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC;gBACjE,KAAK,EAAE,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE;aACtD,CAAC,CAAC;YACH,IAAI,CAAC,aAAa;gBAAE,OAAO,KAAK,CAAC;YACjC,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC;YAC1B,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QACvE,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC;YACxC,MAAM,IAAI,2BAAkB,CAAC,4DAA4D,CAAC,CAAC;QAC7F,CAAC;QAGD,IAAI,MAAM,EAAE,CALine truncated
|
||||
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":"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 truncated
|
||||
Reference in new issue
Block a user