ghostguild-org/server/models/event.js

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)