- Trasporti- Passo 2
This commit is contained in:
@@ -1,86 +1,94 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const LastMessageSchema = new Schema({
|
||||
text: {
|
||||
const LastMessageSchema = new Schema(
|
||||
{
|
||||
text: {
|
||||
type: String,
|
||||
trim: true,
|
||||
},
|
||||
senderId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: 'User',
|
||||
},
|
||||
timestamp: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
},
|
||||
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 });
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const ChatSchema = new Schema({
|
||||
idapp: {
|
||||
type: String,
|
||||
required: true,
|
||||
index: true
|
||||
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,
|
||||
},
|
||||
},
|
||||
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 },
|
||||
}
|
||||
}, {
|
||||
timestamps: true,
|
||||
toJSON: { virtuals: true },
|
||||
toObject: { virtuals: true }
|
||||
});
|
||||
);
|
||||
|
||||
// Indici
|
||||
ChatSchema.index({ participants: 1 });
|
||||
@@ -88,71 +96,89 @@ ChatSchema.index({ idapp: 1, participants: 1 });
|
||||
ChatSchema.index({ idapp: 1, updatedAt: -1 });
|
||||
|
||||
// Virtual per contare messaggi non letti totali
|
||||
ChatSchema.virtual('totalUnread').get(function() {
|
||||
ChatSchema.virtual('totalUnread').get(function () {
|
||||
if (!this.unreadCount) return 0;
|
||||
let total = 0;
|
||||
this.unreadCount.forEach(count => {
|
||||
this.unreadCount.forEach((count) => {
|
||||
total += count;
|
||||
});
|
||||
return total;
|
||||
});
|
||||
|
||||
// Metodo per ottenere unread count per un utente specifico
|
||||
ChatSchema.methods.getUnreadForUser = function(userId) {
|
||||
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()) {
|
||||
// ✅ 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) {
|
||||
ChatSchema.methods.markAsRead = function (userId) {
|
||||
this.unreadCount.set(userId.toString(), 0);
|
||||
return this.save();
|
||||
};
|
||||
|
||||
// Metodo per aggiornare ultimo messaggio
|
||||
ChatSchema.methods.updateLastMessage = function(message) {
|
||||
ChatSchema.methods.updateLastMessage = function (message) {
|
||||
this.lastMessage = {
|
||||
text: message.text,
|
||||
senderId: message.senderId,
|
||||
timestamp: message.createdAt || new Date(),
|
||||
type: message.type || 'text'
|
||||
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()
|
||||
);
|
||||
// ✅ 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
|
||||
ChatSchema.methods.isBlockedFor = function(userId) {
|
||||
return this.blockedBy.some(
|
||||
id => id.toString() === userId.toString()
|
||||
);
|
||||
// ✅ 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) {
|
||||
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 }
|
||||
participants: { $all: [userId1, userId2], $size: 2 },
|
||||
});
|
||||
|
||||
if (!chat) {
|
||||
@@ -161,7 +187,7 @@ ChatSchema.statics.findOrCreateDirect = async function(idapp, userId1, userId2,
|
||||
type: 'direct',
|
||||
participants: [userId1, userId2],
|
||||
rideId,
|
||||
unreadCount: new Map()
|
||||
unreadCount: new Map(),
|
||||
});
|
||||
await chat.save();
|
||||
} else if (rideId && !chat.rideId) {
|
||||
@@ -174,31 +200,31 @@ ChatSchema.statics.findOrCreateDirect = async function(idapp, userId1, userId2,
|
||||
};
|
||||
|
||||
// Metodo statico per ottenere tutte le chat di un utente
|
||||
ChatSchema.statics.getChatsForUser = function(idapp, userId) {
|
||||
ChatSchema.statics.getChatsForUser = function (idapp, userId) {
|
||||
return this.find({
|
||||
idapp,
|
||||
participants: userId,
|
||||
isActive: true,
|
||||
blockedBy: { $ne: userId }
|
||||
blockedBy: { $ne: userId },
|
||||
})
|
||||
.populate('participants', 'username name surname profile.avatar')
|
||||
.populate('rideId', 'departure destination dateTime')
|
||||
.sort({ updatedAt: -1 });
|
||||
.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) {
|
||||
ChatSchema.statics.createRideGroupChat = async function (idapp, rideId, title, participantIds) {
|
||||
const chat = new this({
|
||||
idapp,
|
||||
type: 'group',
|
||||
rideId,
|
||||
title,
|
||||
participants: participantIds,
|
||||
unreadCount: new Map()
|
||||
unreadCount: new Map(),
|
||||
});
|
||||
return chat.save();
|
||||
};
|
||||
|
||||
const Chat = mongoose.model('Chat', ChatSchema);
|
||||
|
||||
module.exports = Chat;
|
||||
module.exports = Chat;
|
||||
|
||||
Reference in New Issue
Block a user