Files
v3-api/src/api/user/user.service.ts

936 lines
29 KiB
TypeScript

import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { FilterQuery, Model, Types, UpdateQuery } from 'mongoose';
import { BaseResponseDTO } from 'src/common/dto/base-response.dto';
import { TimeHelper } from 'src/common/tools/time-helper';
import { Sender } from 'src/common/types/sender.type';
import { ReactEnum } from 'src/common/types/react.type';
import { AdminModel } from 'src/database/model/admin.model';
import { DictionariesModel } from 'src/database/model/dictionaries.model';
import { SessionModel } from 'src/database/model/sessions.model';
import { UserModel } from 'src/database/model/user.model';
import { ReactsModel } from 'src/database/model/botReact.model';
import { AiServiceService } from '../../ai-service/ai-service.service';
import { PoliciesService } from 'src/policies/policies.service';
import {
UserAskQuestion,
UserRateTheExpert,
UserReactToMessage,
} from './dto/user.dto';
@Injectable()
export class UserService {
constructor(
@InjectModel(UserModel.name) private readonly user: Model<UserModel>,
@InjectModel(SessionModel.name)
private readonly session: Model<SessionModel>,
@InjectModel(AdminModel.name) private readonly admin: Model<AdminModel>,
@InjectModel(DictionariesModel.name)
private readonly dictionaries: Model<DictionariesModel>,
@InjectModel(ReactsModel.name)
private readonly reacts: Model<ReactsModel>,
private readonly aiService: AiServiceService,
private readonly policiesService: PoliciesService,
) {}
private normalizeReactValue(value: string | ReactEnum): ReactEnum {
if (value === ReactEnum.like || value === ReactEnum.dislike || value === ReactEnum.nothing) {
return value as ReactEnum;
}
if (typeof value === 'string') {
const v = value.toLowerCase();
if (v === 'like') return ReactEnum.like;
if (v === 'dislike') return ReactEnum.dislike;
if (v === 'nothing') return ReactEnum.nothing;
}
return ReactEnum.nothing;
}
async getMyPolicies(user) {
try {
const userId =
typeof user._id === 'string' ? new Types.ObjectId(user._id) : user._id;
const data = await this.policiesService.getUserPoliciesWithInstallments(
userId,
);
return new BaseResponseDTO(HttpStatus.OK, 'SUCCESS', data);
} catch (err) {
console.log(err);
throw new BaseResponseDTO(
HttpStatus.INTERNAL_SERVER_ERROR,
'Failed to fetch policies',
null,
);
}
}
async getProfile(user) {
try {
const userId =
typeof user._id === 'string' ? new Types.ObjectId(user._id) : user._id;
const userDoc = await this.user.findOne({ _id: userId });
if (!userDoc)
throw new HttpException('user_not_found', HttpStatus.NOT_FOUND);
return new BaseResponseDTO(HttpStatus.OK, 'SUCCESS', {
_id: userDoc._id,
name: userDoc.name || null,
family: userDoc.family || null,
birthDate: userDoc.birthDate || null,
nationalCode: userDoc.nationalCode || null,
mobile: userDoc.mobile || null,
email: userDoc.email || null,
address: userDoc.address || null,
username: userDoc.username || null,
});
} catch (err) {
console.log(err);
if (err instanceof HttpException) {
throw err;
}
throw new BaseResponseDTO(err.status, err.response, null);
}
}
async getUserLastQuestionsHistory(user) {
try {
const now = Date.now() / 1000;
const userId =
typeof user._id === 'string' ? new Types.ObjectId(user._id) : user._id;
const sessions = await this.session
.find({ userId: userId })
.select('chatTitle _id createdAt createdISO')
.lean()
.exec();
// Calculate date boundaries
const nowMs = Date.now();
const nowDate = new Date(nowMs);
// 7 days ago
const sevenDaysAgo = nowMs - (7 * 24 * 60 * 60 * 1000);
// 6 months ago (using actual month calculation)
const sixMonthsAgoDate = new Date(nowDate);
sixMonthsAgoDate.setMonth(sixMonthsAgoDate.getMonth() - 6);
const sixMonthsAgo = sixMonthsAgoDate.getTime();
// 12 months ago (using actual month calculation)
const twelveMonthsAgoDate = new Date(nowDate);
twelveMonthsAgoDate.setMonth(twelveMonthsAgoDate.getMonth() - 12);
const twelveMonthsAgo = twelveMonthsAgoDate.getTime();
// Initialize categorized arrays
const recent: any[] = []; // Last 7 days
const lastSixMonths: any[] = []; // Last 6 months (excluding last 7 days)
const previousSixMonths: any[] = []; // 6-12 months ago
if (sessions && sessions.length > 0) {
for (let session of sessions) {
const sessionData = {
title: session["chatTitle"],
sessionId: session["_id"],
time: session["createdAt"][0],
date: session["createdAt"][1],
};
// Use createdISO for accurate date comparison
const sessionDate = session["createdISO"]
? new Date(session["createdISO"]).getTime()
: null;
if (sessionDate) {
if (sessionDate >= sevenDaysAgo) {
// Last 7 days (recent)
recent.push(sessionData);
} else if (sessionDate >= sixMonthsAgo) {
// Last 6 months (excluding last 7 days)
lastSixMonths.push(sessionData);
} else if (sessionDate >= twelveMonthsAgo) {
// Previous 6 months (6-12 months ago)
previousSixMonths.push(sessionData);
}
// Sessions older than 12 months are not included
} else {
// Fallback: if createdISO is missing, include in recent (shouldn't happen normally)
recent.push(sessionData);
}
}
}
return new BaseResponseDTO(HttpStatus.OK, 'SUCCESS', {
recent, // Last 7 days
lastSixMonths, // Last 6 months (excluding last 7 days)
previousSixMonths, // 6-12 months ago
now: TimeHelper.unix2PersianTimeAndDate(now),
});
} catch (err) {
console.log(err);
if (err instanceof HttpException) {
throw err;
}
throw new BaseResponseDTO(err.status, err.response, null);
}
}
async userSessionHistory(user, sessionId) {
try {
console.log('userSessionHistory called with sessionId:', sessionId);
if (!sessionId || !Types.ObjectId.isValid(sessionId)) {
console.error('Invalid sessionId provided to userSessionHistory:', sessionId);
throw new HttpException('invalid_session_id', HttpStatus.BAD_REQUEST);
}
const newSession = await this.session
.findOne({
_id: new Types.ObjectId(sessionId),
// userId: user._id,
})
.exec();
if (!newSession) {
throw new HttpException('session_not_found', HttpStatus.NOT_FOUND);
}
return new BaseResponseDTO(HttpStatus.OK, 'SUCCESS', {
sessionId: newSession._id,
chatTitle: newSession.chatTitle,
connectedToExpert: newSession.connectedToExpert,
onlineChatClosed: newSession.onlineChatClosed,
chatClosed: newSession.chatClosed,
count: `${newSession.messages.filter((message) => message.sender === Sender.Bot).length}/20`,
time: newSession.createdAt[0],
date: newSession.createdAt[1],
messages: newSession.messages,
});
} catch (err) {
console.log(err);
if (err instanceof HttpException) {
throw err;
}
throw new BaseResponseDTO(err.status, err.response, null);
}
}
async rateTheExpert(body: UserRateTheExpert, user) {
try {
const now = Date.now() / 1000;
const userId =
typeof user._id === 'string' ? new Types.ObjectId(user._id) : user._id;
// Fetch the session from the `sessions` collection
const sessionIdToFind = new Types.ObjectId(body.sessionId);
const newSession = await this.session
.findOne({
_id: sessionIdToFind,
userId: userId, // Ensure the session belongs to the user
})
.exec();
if (!newSession) {
throw new HttpException('session_not_found', HttpStatus.NOT_FOUND);
}
if (!newSession.connectedToExpert) {
throw new HttpException('expert_not_connected', HttpStatus.BAD_REQUEST);
}
// Check if the expert field is empty or null
if (!newSession.expert || newSession.expert.trim() === '') {
throw new HttpException('expert_not_assigned', HttpStatus.BAD_REQUEST);
}
// Update the expert rate in the `sessions` collection
await this.session.updateOne(
{ _id: sessionIdToFind },
{
$set: {
expertRate: body.rate,
},
},
);
// Update the admin's rate in the `admin` collection
await this.admin.updateOne(
{ username: newSession.expert },
{
$push: {
rate: {
sessionId: body.sessionId,
rate: body.rate,
createdAt: TimeHelper.unix2PersianTimeAndDate(now),
createdAtDate: Date.now(),
},
},
},
);
// Return success response
return new BaseResponseDTO(HttpStatus.OK, 'SUCCESS', null);
} catch (err) {
console.log(err);
if (err instanceof HttpException) {
throw err;
}
throw new BaseResponseDTO(err.status, err.response, null);
}
}
async getUsersFaq(user) {
try {
const dictionaries = await this.dictionaries.find({
isActive: true,
aiCollectionName: { $ne: 'agents' }
});
// Combine all questions from all dictionaries into a single array
const allQuestions = dictionaries.flatMap(
(dictionary) => dictionary.questions,
);
// Filter out questions where deleted is true
const filteredQuestions = allQuestions.filter(
(question) => question.deleted !== true,
);
// Extract only the `question` field from each question object
const questionsOnly = filteredQuestions.map(
(question) => question.question,
);
// Function to shuffle an array using Fisher-Yates algorithm
const shuffleArray = (array) => {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
};
// Shuffle the questions and pick the first 3
const shuffledQuestions = shuffleArray(questionsOnly);
const randomQuestions = shuffledQuestions.slice(0, 3);
return new BaseResponseDTO(HttpStatus.OK, 'SUCCESS', randomQuestions);
} catch (err) {
console.log(err);
if (err instanceof HttpException) {
throw err;
}
throw new BaseResponseDTO(err.status, err.response, null);
}
}
async react(body: UserReactToMessage, userData) {
try {
const { sessionId, messageId } = body;
const normalizedReact = this.normalizeReactValue((body as any).react);
const sessionObjectId = new Types.ObjectId(sessionId);
const userObjectId = new Types.ObjectId(userData._id);
const storedMessageId = this.toStoredMessageId(messageId);
// Update the message's react field in the session
// Use updateOne first to ensure the update happens, then fetch the result
const updateResult = await this.session.updateOne(
{
_id: sessionObjectId,
'messages.messageId': storedMessageId,
},
{
$set: {
'messages.$.react': normalizedReact,
},
},
);
if (updateResult.matchedCount === 0) {
throw new HttpException('message_not_found', HttpStatus.NOT_FOUND);
}
// Fetch the updated session to get the reacted message
const result = await this.session.findById(sessionObjectId);
if (!result) {
throw new HttpException('session_not_found', HttpStatus.NOT_FOUND);
}
const reactedMessage = result.messages.find(
(message) => String(message.messageId) === String(messageId),
);
// Verify the update actually happened
if (reactedMessage && reactedMessage.react !== normalizedReact) {
console.warn(`[react] Warning: React update may have failed. Expected: ${normalizedReact}, Got: ${reactedMessage.react}`);
}
if (reactedMessage) {
const botMessageIndex = result.messages.findIndex(
(message) => String(message.messageId) === String(messageId),
);
let questionText = null;
if (botMessageIndex > 0) {
for (let i = botMessageIndex - 1; i >= 0; i--) {
if (result.messages[i].sender === Sender.User) {
questionText = result.messages[i].text;
break;
}
}
}
// Update or create the react entry in the reacts collection
// This ensures we only have one react per user per message (the latest one)
await this.reacts.findOneAndUpdate(
{
sessionId: sessionObjectId,
messageId: storedMessageId,
userId: userObjectId,
},
{
$set: {
question: questionText,
answer: reactedMessage.text,
sender: reactedMessage.sender,
react: normalizedReact,
createdAt: TimeHelper.unix2PersianTimeAndDate(Date.now() / 1000),
createdISO: new Date(),
},
},
{
upsert: true, // Create if doesn't exist, update if it does
new: true,
},
);
}
return new BaseResponseDTO(HttpStatus.OK, 'SUCCESS', {
sessionId: result._id,
chatTitle: result.chatTitle,
count: `${result.messages.filter((message) => message.sender === Sender.Bot).length}/20`,
time: result.createdAt[0],
date: result.createdAt[1],
messages: result.messages,
});
} catch (err) {
console.log(err);
if (err instanceof HttpException) {
throw err;
}
throw new BaseResponseDTO(err.status, err.response, null);
}
}
private toStoredMessageId(messageId: string): Types.ObjectId | string {
if (
Types.ObjectId.isValid(messageId) &&
String(new Types.ObjectId(messageId)) === String(messageId)
) {
return new Types.ObjectId(messageId);
}
return messageId;
}
public async insertNewChatNewStructure(sessionId, text, sender, now) {
const newMessage = {
messageId: new Types.ObjectId(),
text: text,
sender: sender,
react: sender === Sender.User ? 'Nothing' : null,
createdAt: TimeHelper.unix2PersianTimeAndDate(now),
createdISO: Date.now(),
};
await this.session.updateOne(
{ _id: sessionId },
{
$push: {
messages: newMessage,
},
},
);
}
public async editChatMessage(
sessionId: string,
messageId: string,
newMessageText: string,
): Promise<any> {
const sessionObjectId = new Types.ObjectId(sessionId);
const storedMessageId = this.toStoredMessageId(messageId);
const result = await this.session.findOneAndUpdate(
{
_id: sessionObjectId,
'messages.messageId': storedMessageId,
},
{
$set: {
'messages.$.text': newMessageText,
'messages.$.edited': true,
},
},
{ new: true },
);
if (!result) {
return null;
}
// Find the updated message within the session's messages array
const updatedMessage = result.messages.find(
(msg) => msg.messageId.toString() === messageId,
);
return {
...updatedMessage,
sender: updatedMessage.sender, // Ensure sender role is explicitly returned
}; }
async ask(body: UserAskQuestion, user) {
try {
if (!body.question) {
throw new HttpException('question_required', HttpStatus.BAD_REQUEST);
}
const now = Date.now() / 1000;
if (!body.sessionId) {
return await this.handleNewSession(body, user, now);
} else {
return await this.handleExistingSession(body, user, now);
}
} catch (err) {
console.log(err);
if (err instanceof HttpException) {
throw err;
}
throw new BaseResponseDTO(err.status, err.response, null);
}
}
async handleNewSession(body, user, now) {
try {
console.log('new session');
let aiResponse;
let isAiServiceAvailable = true;
try {
const timeoutMs = parseInt(process.env.AI_SERVICE_TIMEOUT || '65000', 10); // Default 60 seconds
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
reject(
new HttpException('ai_service_timeout', HttpStatus.GATEWAY_TIMEOUT),
);
}, timeoutMs);
});
const aiRequest = await this.buildAiRequestPayload(body, user, []);
aiResponse = await Promise.race([
this.aiService.ask(aiRequest, null),
timeoutPromise,
]);
if (aiResponse.statusCode == 500) {
isAiServiceAvailable = false;
}
} catch (aiError) {
// Catch any AI service errors (timeout, network errors, 500 errors, etc.)
console.log('AI service error caught:', aiError);
isAiServiceAvailable = false;
}
let messages;
if (!isAiServiceAvailable) {
// AI service is unavailable, insert fallback message
messages = [
{
messageId: new Types.ObjectId(),
text: body.question,
sender: Sender.User,
react: 'Nothing',
createdAt: TimeHelper.unix2PersianTimeAndDate(now),
createdISO: Date.now(),
},
{
messageId: new Types.ObjectId(),
text: "به دلیل اختلال در سیستم زیر ساخت های کشور سرویس هوش مصنوعی در دسترس نیست. لطفا جهت دریافت راهنمایی به کارشناس متصل شوید. ",
sender: Sender.Bot,
react: null,
createdAt: TimeHelper.unix2PersianTimeAndDate(now),
createdISO: Date.now(),
},
];
} else {
// AI service responded successfully
messages = [
{
messageId: new Types.ObjectId(),
text: body.question,
sender: Sender.User,
react: 'Nothing',
createdAt: TimeHelper.unix2PersianTimeAndDate(now),
createdISO: Date.now(),
},
{
messageId: new Types.ObjectId(),
text: aiResponse,
sender: Sender.Bot,
react: null,
createdAt: TimeHelper.unix2PersianTimeAndDate(now),
createdISO: Date.now(),
},
];
}
const userId =
typeof user._id === 'string' ? new Types.ObjectId(user._id) : user._id;
const newSession = {
_id: new Types.ObjectId(),
userId: userId,
chatTitle: body.question, // TODO: AI wrap-up needed
connectedToExpert: false,
onlineChatClosed: false,
chatClosed: false,
expert: '',
expertRate: null,
createdAt: TimeHelper.unix2PersianTimeAndDate(now),
createdISO: Date.now(),
messages: messages,
};
await this.session.create(newSession);
return new BaseResponseDTO(HttpStatus.OK, 'SUCCESS', {
sessionId: newSession._id,
count: `1/20`,
date: TimeHelper.unix2PersianTimeAndDate(now)[1],
time: TimeHelper.unix2PersianTimeAndDate(now)[0],
question: body.question,
answer: messages[1].text,
history: newSession.messages,
});
} catch (err) {
console.log(err);
if (err instanceof HttpException) {
throw err;
}
throw new BaseResponseDTO(err.status, err.response, null);
}
}
async handleExistingSession(body, user, now) {
try {
const sessionIdToFind = new Types.ObjectId(body.sessionId);
const userId =
typeof user._id === 'string' ? new Types.ObjectId(user._id) : user._id;
const newSession = await this.session
.findOne({
_id: sessionIdToFind,
userId: userId,
})
.exec();
if (!newSession) {
throw new HttpException('session_not_found', HttpStatus.NOT_FOUND);
}
if (newSession.chatClosed) {
throw new HttpException(
'session_limit_reached',
HttpStatus.BAD_REQUEST,
);
}
let aiResponse;
let isAiServiceAvailable = true;
const fallbackMessage = "به دلیل اختلال در سیستم زیر ساخت های کشور سرویس هوش مصنوعی در دسترس نیست. لطفا جهت دریافت راهنمایی به کارشناس متصل شوید. ";
try {
// Take last 6 messages (3 complete user-assistant pairs) instead of 7
// to ensure we have complete pairs for chat_history_raw
const historyToSend = newSession.messages.slice(-6); // Get the last 6 messages (3 pairs)
const transformedData = await this.buildAiRequestPayload(
body,
user,
this.transformChatHistory(historyToSend),
);
aiResponse = await this.aiService.ask(
transformedData,
body.sessionId,
);
if (aiResponse.statusCode == 500) {
isAiServiceAvailable = false;
}
} catch (aiError) {
// Catch any AI service errors (network errors, 500 errors, etc.)
console.log('AI service error caught in existing session:', aiError);
isAiServiceAvailable = false;
}
// Insert user question
await this.insertNewChatNewStructure(
sessionIdToFind,
body.question,
Sender.User,
now,
);
// Insert AI response or fallback message
const responseText = isAiServiceAvailable ? aiResponse : fallbackMessage;
await this.insertNewChatNewStructure(
sessionIdToFind,
responseText,
Sender.Bot,
now,
);
const updatedSession = await this.session
.findOne({
_id: sessionIdToFind,
userId: userId,
})
.exec();
const botMessageCount = updatedSession.messages.filter(
(message) => message.sender === Sender.Bot,
).length;
if (botMessageCount >= 20) {
await this.session.updateOne(
{ _id: sessionIdToFind },
{ $set: { chatClosed: true } },
);
}
return new BaseResponseDTO(HttpStatus.OK, 'SUCCESS', {
sessionId: updatedSession._id,
count: `${botMessageCount}/20`,
createdAt: TimeHelper.unix2PersianTimeAndDate(now),
question: body.question,
answer: responseText,
history: updatedSession.messages,
});
} catch (err) {
console.log(err);
if (err instanceof HttpException) {
throw err;
}
throw new BaseResponseDTO(err.status, err.response, null);
}
}
transformChatHistory(messages) {
const history = [];
for (let i = 0; i < messages.length; i += 2) {
const userMessage = messages[i];
const botMessage = messages[i + 1];
if (userMessage && botMessage) {
history.push({
user: userMessage.text,
assistant: botMessage.text,
// userCreatedAt: userMessage.createdAt,
// botCreatedAt: botMessage.createdAt,
});
}
}
return history;
}
private async buildAiRequestPayload(
body: UserAskQuestion,
user: { _id: Types.ObjectId | string },
chatHistory: { user: string; assistant: string }[],
) {
const userId =
typeof user._id === 'string' ? new Types.ObjectId(user._id) : user._id;
const userDoc = await this.user
.findById(userId)
.select('nationalCode')
.lean()
.exec();
const { user_insurance_data, user_installments_data } =
await this.policiesService.getUserDataForAi(
userId,
userDoc?.nationalCode,
);
return {
user_input: body.question,
chat_history_raw: chatHistory,
user_insurance_data,
user_installments_data,
};
}
async closeChatSession(userId, sessionId) {
// ? migrated
try {
// Close the chat session in the old structure ** old-struc **
await this.user.updateOne(
{ _id: userId },
{
$set: {
'chat.$[chatElement].chatClosed': true,
},
},
{
arrayFilters: [
{ 'chatElement.sessionId': new Types.ObjectId(sessionId) },
],
},
);
// ** old-struc **
// Close the chat session in the new structure ** new-struc **
const sessionIdToFind = new Types.ObjectId(sessionId);
await this.session.updateOne(
{ _id: sessionIdToFind, userId: userId },
{ $set: { chatClosed: true } },
);
// Log the new structure data for verification ** new-struc **
await this.session
.findOne({
_id: sessionIdToFind,
userId: userId,
})
.exec();
} catch (err) {
console.log(err);
if (err instanceof HttpException) {
throw err;
}
throw new BaseResponseDTO(err.status, err.response, null);
}
}
async findOneUser(filter: FilterQuery<UserModel>): Promise<UserModel> {
return await this.user.findOne(filter);
}
async updateOneUser(
filter: FilterQuery<UserModel>,
update: UpdateQuery<UserModel>,
): Promise<any> {
return await this.user.updateOne(filter, update).lean();
}
// public async toggleExpertActions(
// userId: string,
// sessionId: string,
// field: string,
// ): Promise<void> {
// try {
// // Validate the field
// if (!['connectedToExpert', 'onlineChatClosed'].includes(field)) {
// throw new Error('Invalid field specified');
// }
// // Toggle the field in the new structure
// const sessionIdToFind = new Types.ObjectId(sessionId);
// const result = await this.session.updateOne(
// { _id: sessionIdToFind, userId: userId },
// { $set: { [field]: true } },
// );
// // Check if the update was successful
// if (result.matchedCount === 0) {
// throw new HttpException('session_not_found', HttpStatus.NOT_FOUND);
// }
// // Log the new structure data for verification
// const updatedSession = await this.session
// .findOne({
// _id: sessionIdToFind,
// userId: userId,
// })
// .exec();
// } catch (err) {
// console.log(err);
// throw new BaseResponseDTO(err.status, err.response, null);
// }
// }
public async toggleExpertActions(
userId: string,
sessionId: string,
field: string,
expertId?: string,
): Promise<void> {
try {
console.log('toggleExpertActions called with:', { userId, sessionId, field, expertId });
if (!['connectedToExpert', 'onlineChatClosed'].includes(field)) {
throw new Error('Invalid field specified');
}
// Additional validation for expertId when field is connectedToExpert
if (field === 'connectedToExpert' && !expertId) {
throw new Error('expertId is required when field is connectedToExpert');
}
const sessionIdToFind = new Types.ObjectId(sessionId);
const userID =
typeof userId === 'string' ? new Types.ObjectId(userId) : userId;
const session = await this.session.findOne({ _id: sessionIdToFind, userId: userID }).exec();
if (!session) {
throw new HttpException('session_not_found', HttpStatus.NOT_FOUND);
}
// New validation logic
if (field === 'connectedToExpert' && session.connectedToExpert && session.chatClosed) {
console.error('User already connected to expert in a closed session for sessionId:', sessionId);
throw new HttpException('you_have_connected_to_expert_once', HttpStatus.BAD_REQUEST);
}
let updateData: any = { [field]: true };
// If connecting to expert, get expert username and add to update
if (field === 'connectedToExpert' && expertId) {
console.log('Attempting to find expert with expertId:', expertId);
const expert = await this.admin
.findOne({ _id: new Types.ObjectId(expertId) }, { username: 1 })
.exec();
if (!expert) {
console.error('Expert not found for expertId:', expertId);
throw new HttpException('expert_not_found', HttpStatus.NOT_FOUND);
}
updateData.expert = expert.username;
}
// Update the session
console.log('Updating session with sessionIdToFind:', sessionIdToFind, 'and userID:', userID);
const result = await this.session.updateOne(
{ _id: sessionIdToFind, userId: userID },
{ $set: updateData },
);
if (result.matchedCount === 0) {
throw new HttpException('session_not_found', HttpStatus.NOT_FOUND);
}
await this.session
.findOne({
_id: sessionIdToFind,
userId: userID,
})
.exec();
} catch (err) {
console.log(err);
if (err instanceof HttpException) {
throw err;
}
throw new BaseResponseDTO(err.status, err.response, null);
}
}
}