Files
freeplanet_serverside/src/models/Chat.js
Surya Paolo cb965eaa27 - Parte 3 : Viaggi
- Chat
2025-12-24 00:26:38 +01:00

238 lines
5.6 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',
},
],
deletedBy: [
{
type: Schema.Types.ObjectId,
ref: 'User',
},
],
clearedBefore: {
type: Map,
of: Date,
},
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;