99 lines
No EOL
2.9 KiB
JavaScript
99 lines
No EOL
2.9 KiB
JavaScript
import mongoose from 'mongoose'
|
|
|
|
const eventSchema = new mongoose.Schema({
|
|
title: { type: String, required: true },
|
|
slug: { type: String, required: true, unique: true },
|
|
tagline: String,
|
|
description: { type: String, required: true },
|
|
content: String,
|
|
featureImage: {
|
|
url: String, // Cloudinary URL
|
|
publicId: String, // Cloudinary public ID for transformations
|
|
alt: String // Alt text for accessibility
|
|
},
|
|
startDate: { type: Date, required: true },
|
|
endDate: { type: Date, required: true },
|
|
eventType: {
|
|
type: String,
|
|
enum: ['community', 'workshop', 'social', 'showcase'],
|
|
default: 'community'
|
|
},
|
|
// Online-first location handling
|
|
location: {
|
|
type: String,
|
|
required: true,
|
|
// This will typically be a Slack channel or video conference link
|
|
validate: {
|
|
validator: function(v) {
|
|
// Must be either a valid URL or a Slack channel reference
|
|
const urlPattern = /^https?:\/\/.+/;
|
|
const slackPattern = /^#[a-zA-Z0-9-_]+$/;
|
|
return urlPattern.test(v) || slackPattern.test(v);
|
|
},
|
|
message: 'Location must be a valid URL (video conference link) or Slack channel (starting with #)'
|
|
}
|
|
},
|
|
isOnline: { type: Boolean, default: true }, // Default to online-first
|
|
// Visibility and status controls
|
|
isVisible: { type: Boolean, default: true }, // Hide from public calendar when false
|
|
isCancelled: { type: Boolean, default: false },
|
|
cancellationMessage: String, // Custom message for cancelled events
|
|
membersOnly: { type: Boolean, default: false },
|
|
// Circle targeting
|
|
targetCircles: [{
|
|
type: String,
|
|
enum: ['community', 'founder', 'practitioner'],
|
|
required: false
|
|
}],
|
|
maxAttendees: Number,
|
|
registrationRequired: { type: Boolean, default: false },
|
|
registrationDeadline: Date,
|
|
agenda: [String],
|
|
speakers: [{
|
|
name: String,
|
|
role: String,
|
|
bio: String
|
|
}],
|
|
registrations: [{
|
|
name: String,
|
|
email: String,
|
|
membershipLevel: String,
|
|
registeredAt: { type: Date, default: Date.now }
|
|
}],
|
|
createdBy: { type: String, required: true },
|
|
createdAt: { type: Date, default: Date.now },
|
|
updatedAt: { type: Date, default: Date.now }
|
|
})
|
|
|
|
// Generate slug from title
|
|
function generateSlug(title) {
|
|
return title
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.replace(/^-+|-+$/g, '')
|
|
}
|
|
|
|
// Pre-save hook to generate slug
|
|
eventSchema.pre('save', async function(next) {
|
|
try {
|
|
if (this.isNew || this.isModified('title')) {
|
|
let baseSlug = generateSlug(this.title)
|
|
let slug = baseSlug
|
|
let counter = 1
|
|
|
|
// Ensure slug is unique
|
|
while (await this.constructor.findOne({ slug, _id: { $ne: this._id } })) {
|
|
slug = `${baseSlug}-${counter}`
|
|
counter++
|
|
}
|
|
|
|
this.slug = slug
|
|
}
|
|
next()
|
|
} catch (error) {
|
|
console.error('Error in pre-save hook:', error)
|
|
next(error)
|
|
}
|
|
})
|
|
|
|
export default mongoose.models.Event || mongoose.model('Event', eventSchema) |