204 lines
4.7 KiB
JavaScript
204 lines
4.7 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: {
|
|
type: String,
|
|
enum: ['text', 'ride_share', 'location', 'image', 'system'],
|
|
default: 'text'
|
|
}
|
|
}, { _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;
|
|
};
|
|
|
|
// Metodo per incrementare unread count
|
|
ChatSchema.methods.incrementUnread = function(excludeUserId) {
|
|
this.participants.forEach(participantId => {
|
|
const id = participantId.toString();
|
|
if (id !== excludeUserId.toString()) {
|
|
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
|
|
ChatSchema.methods.hasParticipant = function(userId) {
|
|
return this.participants.some(
|
|
p => p.toString() === userId.toString()
|
|
);
|
|
};
|
|
|
|
// Metodo per verificare se la chat è bloccata per un utente
|
|
ChatSchema.methods.isBlockedFor = function(userId) {
|
|
return this.blockedBy.some(
|
|
id => id.toString() === userId.toString()
|
|
);
|
|
};
|
|
|
|
// 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; |