UNPKG

@ideal-photography/shared

Version:

Shared MongoDB and utility logic for Ideal Photography PWAs: users, products, services, bookings, orders/cart, galleries, reviews, notifications, campaigns, settings, audit logs, minimart items/orders, and push notification subscriptions.

160 lines (136 loc) 4.44 kB
import mongoose from 'mongoose'; const adminPushSubscriptionSchema = new mongoose.Schema({ // Reference to Admin admin: { type: mongoose.Schema.Types.ObjectId, ref: 'Admin', required: [true, 'Admin reference is required'], index: true }, // Push subscription data from browser subscription: { endpoint: { type: String, required: [true, 'Subscription endpoint is required'], trim: true }, keys: { p256dh: { type: String, required: [true, 'P256DH key is required'], trim: true }, auth: { type: String, required: [true, 'Auth key is required'], trim: true } } }, // Subscription status and management isActive: { type: Boolean, default: true, index: true }, // Tracking lastSentAt: { type: Date, default: null }, // Device/browser information userAgent: { type: String, trim: true, maxlength: [500, 'User agent too long'] }, // Subscription metadata metadata: { type: mongoose.Schema.Types.Mixed, default: {} } }, { timestamps: true, toJSON: { virtuals: true }, toObject: { virtuals: true } }); // Indexes for performance adminPushSubscriptionSchema.index({ admin: 1, isActive: 1 }); adminPushSubscriptionSchema.index({ 'subscription.endpoint': 1 }); adminPushSubscriptionSchema.index({ lastSentAt: 1 }); adminPushSubscriptionSchema.index({ createdAt: -1 }); // Compound index for efficient queries adminPushSubscriptionSchema.index({ admin: 1, isActive: 1, lastSentAt: 1 }); // Virtual for subscription age adminPushSubscriptionSchema.virtual('ageInDays').get(function () { return Math.floor((Date.now() - this.createdAt) / (1000 * 60 * 60 * 24)); }); // Virtual for subscription status adminPushSubscriptionSchema.virtual('isStale').get(function () { // Consider subscription stale if no activity for 30 days const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); return this.lastSentAt && this.lastSentAt < thirtyDaysAgo; }); // Methods adminPushSubscriptionSchema.methods.markAsInactive = function () { this.isActive = false; return this.save(); }; adminPushSubscriptionSchema.methods.updateLastSent = function () { this.lastSentAt = new Date(); return this.save(); }; adminPushSubscriptionSchema.methods.isValid = function () { return this.isActive && this.subscription?.endpoint && this.subscription?.keys?.p256dh && this.subscription?.keys?.auth; }; // Static methods adminPushSubscriptionSchema.statics.findActiveByAdmin = function (adminId) { return this.find({ admin: adminId, isActive: true }).sort({ lastSentAt: -1 }); }; adminPushSubscriptionSchema.statics.findStaleSubscriptions = function (daysOld = 30) { const cutoffDate = new Date(Date.now() - daysOld * 24 * 60 * 60 * 1000); return this.find({ isActive: true, lastSentAt: { $lt: cutoffDate } }); }; adminPushSubscriptionSchema.statics.cleanupInactive = function () { return this.updateMany( { isActive: false }, { $set: { isActive: false } } ); }; adminPushSubscriptionSchema.statics.getAdminSubscriptionCount = function (adminId) { return this.countDocuments({ admin: adminId, isActive: true }); }; // Pre-save middleware adminPushSubscriptionSchema.pre('save', function (next) { // Ensure subscription data is valid if (!this.subscription?.endpoint || !this.subscription?.keys?.p256dh || !this.subscription?.keys?.auth) { return next(new Error('Invalid subscription data')); } // Set user agent if not provided if (!this.userAgent && this.isNew) { this.userAgent = 'Unknown'; } next(); }); // Pre-remove middleware adminPushSubscriptionSchema.pre('remove', function (next) { console.log(`Removing push subscription for admin ${this.admin}`); next(); }); export default mongoose.model('AdminPushSubscription', adminPushSubscriptionSchema);