231 lines
5.4 KiB
JavaScript
231 lines
5.4 KiB
JavaScript
const mongoose = require('mongoose');
|
|
const Schema = mongoose.Schema;
|
|
|
|
const LastMessageSchema = new Schema(
|
|
{
|
|
text: {
|
|
type: String,
|
|
trim: true,
|
|
},
|
|
senderId: {
|
|
type: Schema.Types.ObjectId,
|
|
ref: 'User',
|
|
},
|
|
timestamp: {
|
|
type: Date,
|
|
default: Date.now,
|
|
},
|
|
type: String,
|
|
},
|
|
{ _id: false }
|
|
);
|
|
|
|
const ChatSchema = new Schema(
|
|
{
|
|
idapp: {
|
|
type: String,
|
|
required: true,
|
|
index: true,
|
|
},
|
|
participants: [
|
|
{
|
|
type: Schema.Types.ObjectId,
|
|
ref: 'User',
|
|
required: true,
|
|
},
|
|
],
|
|
rideId: {
|
|
type: Schema.Types.ObjectId,
|
|
ref: 'Ride',
|
|
index: true,
|
|
// Opzionale: chat collegata a un viaggio specifico
|
|
},
|
|
rideRequestId: {
|
|
type: Schema.Types.ObjectId,
|
|
ref: 'RideRequest',
|
|
},
|
|
type: {
|
|
type: String,
|
|
enum: ['direct', 'ride', 'group'],
|
|
default: 'direct',
|
|
},
|
|
title: {
|
|
type: String,
|
|
trim: true,
|
|
// Solo per chat di gruppo
|
|
},
|
|
lastMessage: {
|
|
type: LastMessageSchema,
|
|
},
|
|
unreadCount: {
|
|
type: Map,
|
|
of: Number,
|
|
default: new Map(),
|
|
// { odIdUtente: numeroMessaggiNonLetti }
|
|
},
|
|
isActive: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
mutedBy: [
|
|
{
|
|
type: Schema.Types.ObjectId,
|
|
ref: 'User',
|
|
},
|
|
],
|
|
blockedBy: [
|
|
{
|
|
type: Schema.Types.ObjectId,
|
|
ref: 'User',
|
|
},
|
|
],
|
|
metadata: {
|
|
type: Schema.Types.Mixed,
|
|
},
|
|
},
|
|
{
|
|
timestamps: true,
|
|
toJSON: { virtuals: true },
|
|
toObject: { virtuals: true },
|
|
}
|
|
);
|
|
|
|
// Indici
|
|
ChatSchema.index({ participants: 1 });
|
|
ChatSchema.index({ idapp: 1, participants: 1 });
|
|
ChatSchema.index({ idapp: 1, updatedAt: -1 });
|
|
|
|
// Virtual per contare messaggi non letti totali
|
|
ChatSchema.virtual('totalUnread').get(function () {
|
|
if (!this.unreadCount) return 0;
|
|
let total = 0;
|
|
this.unreadCount.forEach((count) => {
|
|
total += count;
|
|
});
|
|
return total;
|
|
});
|
|
|
|
// Metodo per ottenere unread count per un utente specifico
|
|
ChatSchema.methods.getUnreadForUser = function (userId) {
|
|
if (!this.unreadCount) return 0;
|
|
return this.unreadCount.get(userId.toString()) || 0;
|
|
};
|
|
|
|
// ✅ FIX: incrementUnread (assicura conversione corretta)
|
|
ChatSchema.methods.incrementUnread = function (excludeUserId) {
|
|
const excludeIdStr = excludeUserId.toString();
|
|
|
|
this.participants.forEach((participantId) => {
|
|
// Gestisci sia ObjectId che oggetti popolati
|
|
const id = participantId._id
|
|
? participantId._id.toString()
|
|
: participantId.toString();
|
|
|
|
if (id !== excludeIdStr) {
|
|
const current = this.unreadCount.get(id) || 0;
|
|
this.unreadCount.set(id, current + 1);
|
|
}
|
|
});
|
|
|
|
return this.save();
|
|
};
|
|
|
|
// Metodo per resettare unread count per un utente
|
|
ChatSchema.methods.markAsRead = function (userId) {
|
|
this.unreadCount.set(userId.toString(), 0);
|
|
return this.save();
|
|
};
|
|
|
|
// Metodo per aggiornare ultimo messaggio
|
|
ChatSchema.methods.updateLastMessage = function (message) {
|
|
this.lastMessage = {
|
|
text: message.text,
|
|
senderId: message.senderId,
|
|
timestamp: message.createdAt || new Date(),
|
|
type: message.type || 'text',
|
|
};
|
|
return this.save();
|
|
};
|
|
|
|
// Metodo per verificare se un utente è partecipante
|
|
// ✅ FIX: Gestisce sia ObjectId che oggetti User popolati
|
|
ChatSchema.methods.hasParticipant = function (userId) {
|
|
const userIdStr = userId.toString();
|
|
|
|
return this.participants.some((p) => {
|
|
// Se p è un oggetto popolato (ha _id), usa p._id
|
|
// Altrimenti p è già un ObjectId
|
|
const participantId = p._id ? p._id.toString() : p.toString();
|
|
return participantId === userIdStr;
|
|
});
|
|
};
|
|
|
|
// Metodo per verificare se la chat è bloccata per un utente
|
|
// ✅ FIX: Metodo isBlockedFor (stesso problema)
|
|
ChatSchema.methods.isBlockedFor = function (userId) {
|
|
const userIdStr = userId.toString();
|
|
|
|
return this.blockedBy.some((id) => {
|
|
const blockedId = id._id ? id._id.toString() : id.toString();
|
|
return blockedId === userIdStr;
|
|
});
|
|
};
|
|
|
|
|
|
// Metodo statico per trovare o creare una chat diretta
|
|
ChatSchema.statics.findOrCreateDirect = async function (idapp, userId1, userId2, rideId = null) {
|
|
// Cerca chat esistente tra i due utenti
|
|
let chat = await this.findOne({
|
|
idapp,
|
|
type: 'direct',
|
|
participants: { $all: [userId1, userId2], $size: 2 },
|
|
});
|
|
|
|
if (!chat) {
|
|
chat = new this({
|
|
idapp,
|
|
type: 'direct',
|
|
participants: [userId1, userId2],
|
|
rideId,
|
|
unreadCount: new Map(),
|
|
});
|
|
await chat.save();
|
|
} else if (rideId && !chat.rideId) {
|
|
// Aggiorna con rideId se fornito
|
|
chat.rideId = rideId;
|
|
await chat.save();
|
|
}
|
|
|
|
return chat;
|
|
};
|
|
|
|
// Metodo statico per ottenere tutte le chat di un utente
|
|
ChatSchema.statics.getChatsForUser = function (idapp, userId) {
|
|
return this.find({
|
|
idapp,
|
|
participants: userId,
|
|
isActive: true,
|
|
blockedBy: { $ne: userId },
|
|
})
|
|
.populate('participants', 'username name surname profile.avatar')
|
|
.populate('rideId', 'departure destination dateTime')
|
|
.sort({ updatedAt: -1 });
|
|
};
|
|
|
|
// Metodo statico per creare chat di gruppo per un viaggio
|
|
ChatSchema.statics.createRideGroupChat = async function (idapp, rideId, title, participantIds) {
|
|
const chat = new this({
|
|
idapp,
|
|
type: 'group',
|
|
rideId,
|
|
title,
|
|
participants: participantIds,
|
|
unreadCount: new Map(),
|
|
});
|
|
return chat.save();
|
|
};
|
|
|
|
const Chat = mongoose.model('Chat', ChatSchema);
|
|
|
|
module.exports = Chat;
|