@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.
186 lines (167 loc) • 6.36 kB
JavaScript
import mongoose from 'mongoose';
// Import all models from shared/models directory
import User from '../models/User.js';
import Admin from '../models/Admin.js';
import AdminInvite from '../models/AdminInvite.js';
import RefreshToken from '../models/RefreshToken.js';
import Equipment from '../models/Equipment.js';
import Booking from '../models/Booking.js';
import Review from '../models/Review.js';
import Campaign from '../models/Campaign.js';
import Notification from '../models/Notification.js';
import Order from '../models/Order.js';
import Wishlist from '../models/Wishlist.js';
import Transaction from '../models/Transaction.js';
import AuditLog from '../models/AuditLog.js';
import Settings from '../models/Settings.js';
import BookingWorkflow, { WorkflowInstance } from '../models/BookingWorkflow.js';
import MakeoverOffer from '../models/MakeoverOffer.js';
import StudioSession from '../models/StudioSession.js';
import MinimartItem from '../models/MinimartItem.js';
import Cart from '../models/SimpleCart.js';
import UserPushSubscription from '../models/UserPushSubscription.js';
import AdminPushSubscription from '../models/AdminPushSubscription.js';
// Database connection helper
const connectDB = async (uri, options = {}) => {
try {
const defaultOptions = {
maxPoolSize: 10,
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
// Remove problematic options that aren't supported in this MongoDB driver version
};
await mongoose.connect(uri, { ...defaultOptions, ...options });
console.log('✅ MongoDB connected successfully');
return mongoose.connection;
} catch (error) {
console.error('❌ MongoDB connection error:', error);
throw error;
}
};
// Database initialization helper
const initializeDB = async () => {
try {
// Create default settings if they don't exist
const settingsCount = await Settings.countDocuments();
if (settingsCount === 0) {
await Settings.createDefaults();
console.log('✅ Default settings created');
}
// TODO: Temporarily disable index creation to avoid conflicts
// Create indexes for all models
// await Promise.all([
// User.createIndexes(),
// Product.createIndexes(),
// Booking.createIndexes(),
// Service.createIndexes(),
// Gallery.createIndexes(),
// Review.createIndexes(),
// Campaign.createIndexes(),
// Notification.createIndexes(),
// Order.createIndexes(),
// AuditLog.createIndexes(),
// Settings.createIndexes()
// ]);
// Seed first super admin if configured and none exists
const hasAnyAdmin = await Admin.countDocuments();
const defaultUser = process.env.DEFAULT_ADMIN_USER;
const defaultPass = process.env.DEFAULT_ADMIN_PASS;
if (!hasAnyAdmin && defaultUser && defaultPass) {
// Import permissions to get the correct permission values
const { getPermissionsForRole } = await import('../constants/permissions.js');
const admin = await Admin.create({
username: String(defaultUser).trim(),
password: String(defaultPass),
role: 'super_admin',
permissions: getPermissionsForRole('super_admin'),
isVerified: true,
isActive: true
});
console.log(`✅ Seeded default super admin '${admin.username}'`);
}
// Ensure all existing admins have correct permissions (migration)
await ensureCorrectPermissions();
console.log('✅ Database initialized (indexes skipped for development)');
} catch (error) {
console.error('❌ Database initialization error:', error);
throw error;
}
};
// Migration function to ensure all admins have correct permissions
const ensureCorrectPermissions = async () => {
try {
const { getPermissionsForRole } = await import('../constants/permissions.js');
// Get all admins
const admins = await Admin.find({});
for (const admin of admins) {
const correctPermissions = getPermissionsForRole(admin.role);
const missingPermissions = correctPermissions.filter(perm => !admin.permissions.includes(perm));
if (missingPermissions.length > 0) {
console.log(`🔄 Migrating permissions for ${admin.role} ${admin.username}: adding ${missingPermissions.length} missing permissions`);
admin.permissions = correctPermissions;
await admin.save();
}
}
console.log('✅ Permission migration completed');
} catch (error) {
console.error('❌ Permission migration error:', error);
// Don't throw error - this is a migration, not critical for startup
}
};
export {
mongoose,
connectDB,
initializeDB
};
export const models = {
User,
Admin,
AdminInvite,
RefreshToken,
Equipment,
Booking,
Review,
Campaign,
Notification,
Order,
Wishlist,
Transaction,
AuditLog,
Settings,
BookingWorkflow,
WorkflowInstance,
MakeoverOffer,
StudioSession,
MinimartItem,
Cart,
UserPushSubscription,
AdminPushSubscription,
};
// Convenience exports for common operations
export const utils = {
// Create audit log entry
createAuditLog: (action, actor, target, result, details = {}) => {
return AuditLog.create({
action,
actor,
target,
result,
details,
category: details.category || 'technical'
});
},
// Get setting value
getSetting: (key, defaultValue = null) => {
return Settings.get(key, defaultValue);
},
// Set setting value
setSetting: (key, value, changedBy, reason = '') => {
return Settings.set(key, value, changedBy, reason);
},
// Send notification
sendNotification: async (notificationData) => {
const notification = await Notification.create(notificationData);
// TODO: Integrate with actual notification delivery system
return notification;
}
};