- Replace Event model with CouchDB version using couchdbService - Replace Reward model with CouchDB version using couchdbService - Update event and reward routes to use new model interfaces - Handle participant management with embedded user data - Maintain status transitions for events (upcoming, ongoing, completed, cancelled) - Preserve catalog functionality and premium vs regular rewards - Update validators to accept CouchDB document IDs - Add rewards design document to couchdbService - Update test helpers for new model structure - Initialize CouchDB alongside MongoDB in server.js for backward compatibility - Fix linting issues in migrated routes 🤖 Generated with [AI Assistant] Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
214 lines
5.5 KiB
JavaScript
214 lines
5.5 KiB
JavaScript
const couchdbService = require("../services/couchdbService");
|
|
|
|
class Event {
|
|
static async create(eventData) {
|
|
const event = {
|
|
_id: `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
type: "event",
|
|
title: eventData.title,
|
|
description: eventData.description,
|
|
date: eventData.date,
|
|
location: eventData.location,
|
|
participants: [],
|
|
participantsCount: 0,
|
|
status: eventData.status || "upcoming",
|
|
createdAt: new Date().toISOString(),
|
|
updatedAt: new Date().toISOString()
|
|
};
|
|
|
|
return await couchdbService.create(event);
|
|
}
|
|
|
|
static async findById(eventId) {
|
|
return await couchdbService.getById(eventId);
|
|
}
|
|
|
|
static async find(query = {}, options = {}) {
|
|
const defaultQuery = {
|
|
type: "event",
|
|
...query
|
|
};
|
|
|
|
return await couchdbService.find({
|
|
selector: defaultQuery,
|
|
...options
|
|
});
|
|
}
|
|
|
|
static async findOne(query) {
|
|
const events = await this.find(query, { limit: 1 });
|
|
return events[0] || null;
|
|
}
|
|
|
|
static async update(eventId, updateData) {
|
|
const event = await this.findById(eventId);
|
|
if (!event) {
|
|
throw new Error("Event not found");
|
|
}
|
|
|
|
const updatedEvent = {
|
|
...event,
|
|
...updateData,
|
|
updatedAt: new Date().toISOString()
|
|
};
|
|
|
|
return await couchdbService.update(eventId, updatedEvent);
|
|
}
|
|
|
|
static async delete(eventId) {
|
|
return await couchdbService.delete(eventId);
|
|
}
|
|
|
|
static async addParticipant(eventId, userId, userName, userProfilePicture) {
|
|
const event = await this.findById(eventId);
|
|
if (!event) {
|
|
throw new Error("Event not found");
|
|
}
|
|
|
|
// Check if user is already a participant
|
|
const existingParticipant = event.participants.find(p => p.userId === userId);
|
|
if (existingParticipant) {
|
|
throw new Error("User already participating in this event");
|
|
}
|
|
|
|
// Add participant with embedded user data
|
|
const newParticipant = {
|
|
userId: userId,
|
|
name: userName,
|
|
profilePicture: userProfilePicture || "",
|
|
joinedAt: new Date().toISOString()
|
|
};
|
|
|
|
event.participants.push(newParticipant);
|
|
event.participantsCount = event.participants.length;
|
|
event.updatedAt = new Date().toISOString();
|
|
|
|
return await couchdbService.update(eventId, event);
|
|
}
|
|
|
|
static async removeParticipant(eventId, userId) {
|
|
const event = await this.findById(eventId);
|
|
if (!event) {
|
|
throw new Error("Event not found");
|
|
}
|
|
|
|
// Remove participant
|
|
event.participants = event.participants.filter(p => p.userId !== userId);
|
|
event.participantsCount = event.participants.length;
|
|
event.updatedAt = new Date().toISOString();
|
|
|
|
return await couchdbService.update(eventId, event);
|
|
}
|
|
|
|
static async updateStatus(eventId, newStatus) {
|
|
const validStatuses = ["upcoming", "ongoing", "completed", "cancelled"];
|
|
if (!validStatuses.includes(newStatus)) {
|
|
throw new Error("Invalid status");
|
|
}
|
|
|
|
return await this.update(eventId, { status: newStatus });
|
|
}
|
|
|
|
static async findByStatus(status) {
|
|
return await this.find({ status });
|
|
}
|
|
|
|
static async findByDateRange(startDate, endDate) {
|
|
return await couchdbService.find({
|
|
selector: {
|
|
type: "event",
|
|
date: {
|
|
$gte: startDate.toISOString(),
|
|
$lte: endDate.toISOString()
|
|
}
|
|
},
|
|
sort: [{ date: "asc" }]
|
|
});
|
|
}
|
|
|
|
static async findByParticipant(userId) {
|
|
return await couchdbService.view("events", "by-participant", {
|
|
key: userId,
|
|
include_docs: true
|
|
});
|
|
}
|
|
|
|
static async getUpcomingEvents(limit = 10) {
|
|
const now = new Date().toISOString();
|
|
return await couchdbService.find({
|
|
selector: {
|
|
type: "event",
|
|
status: "upcoming",
|
|
date: { $gte: now }
|
|
},
|
|
sort: [{ date: "asc" }],
|
|
limit
|
|
});
|
|
}
|
|
|
|
static async getAllPaginated(page = 1, limit = 10) {
|
|
const skip = (page - 1) * limit;
|
|
|
|
const events = await couchdbService.find({
|
|
selector: { type: "event" },
|
|
sort: [{ date: "desc" }],
|
|
skip,
|
|
limit
|
|
});
|
|
|
|
// Get total count
|
|
const totalCount = await couchdbService.find({
|
|
selector: { type: "event" },
|
|
fields: ["_id"]
|
|
});
|
|
|
|
return {
|
|
events,
|
|
pagination: {
|
|
page,
|
|
limit,
|
|
totalCount: totalCount.length,
|
|
totalPages: Math.ceil(totalCount.length / limit)
|
|
}
|
|
};
|
|
}
|
|
|
|
static async getEventsByUser(userId) {
|
|
return await this.find({
|
|
"participants": { $elemMatch: { userId: userId } }
|
|
});
|
|
}
|
|
|
|
// Migration helper
|
|
static async migrateFromMongo(mongoEvent) {
|
|
const eventData = {
|
|
title: mongoEvent.title,
|
|
description: mongoEvent.description,
|
|
date: mongoEvent.date,
|
|
location: mongoEvent.location,
|
|
status: mongoEvent.status || "upcoming"
|
|
};
|
|
|
|
// Create event without participants first
|
|
const event = await this.create(eventData);
|
|
|
|
// If there are participants, add them with embedded user data
|
|
if (mongoEvent.participants && mongoEvent.participants.length > 0) {
|
|
for (const participantId of mongoEvent.participants) {
|
|
try {
|
|
// Get user data to embed
|
|
const user = await couchdbService.findUserById(participantId.toString());
|
|
if (user) {
|
|
await this.addParticipant(event._id, participantId.toString(), user.name, user.profilePicture);
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error migrating participant ${participantId}:`, error.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
return event;
|
|
}
|
|
}
|
|
|
|
module.exports = Event; |