UNPKG

@ideal-photography/shared

Version:

Shared GraphQL (Apollo Server v5) and Mongoose logic for Ideal Photography PWAs: users, products, services, bookings, orders/cart, galleries, reviews, notifications, campaigns, settings, and audit logs.

296 lines (259 loc) 12.2 kB
import campaignService from '../../services/campaign.service.js'; import { AuthenticationError, UserInputError, ForbiddenError } from '../errors.js'; const campaignResolvers = { Query: { // Get all campaigns with optional filtering campaigns: async (_, { filter = {} }, { user }) => { try { const result = await campaignService.getCampaigns(filter, { populate: true, page: 1, limit: 1000 // Large limit for GraphQL queries }); return result.campaigns; } catch (error) { console.error('Error fetching campaigns:', error); throw new Error('Failed to fetch campaigns'); } }, // Get campaign by ID campaign: async (_, { id }, { user }) => { try { return await campaignService.getCampaignById(id); } catch (error) { console.error('Error fetching campaign:', error); throw new Error('Failed to fetch campaign'); } }, // Get currently active campaigns activeCampaigns: async (_, __, { user }) => { try { return await campaignService.getActiveCampaigns(); } catch (error) { console.error('Error fetching active campaigns:', error); throw new Error('Failed to fetch active campaigns'); } }, // Get scheduled campaigns (future campaigns) scheduledCampaigns: async (_, __, { user }) => { try { return await campaignService.getScheduledCampaigns(); } catch (error) { console.error('Error fetching scheduled campaigns:', error); throw new Error('Failed to fetch scheduled campaigns'); } }, // Get campaigns by placement campaignsByPlacement: async (_, { placement }, { user }) => { try { return await campaignService.getCampaignsByPlacement(placement); } catch (error) { console.error('Error fetching campaigns by placement:', error); throw new Error('Failed to fetch campaigns by placement'); } }, // Get campaigns by type campaignsByType: async (_, { type }, { user }) => { try { return await campaignService.getCampaignsByType(type); } catch (error) { console.error('Error fetching campaigns by type:', error); throw new Error('Failed to fetch campaigns by type'); } } }, Mutation: { // Create new campaign createCampaign: async (_, { input }, { user }) => { try { if (!user) { throw new AuthenticationError('Authentication required'); } return await campaignService.createCampaign(input, user._id); } catch (error) { console.error('Error creating campaign:', error); if (error.message.includes('required') || error.message.includes('Invalid')) { throw new UserInputError(error.message); } throw new Error('Failed to create campaign'); } }, // Update existing campaign updateCampaign: async (_, { id, input }, { user }) => { try { if (!user) { throw new AuthenticationError('Authentication required'); } // Check if user can edit this campaign const campaign = await campaignService.getCampaignById(id, { populate: false }); if (campaign.createdBy.toString() !== user._id.toString() && !['admin', 'manager', 'super_admin'].includes(user.role)) { throw new ForbiddenError('Insufficient permissions to edit this campaign'); } return await campaignService.updateCampaign(id, input, user._id); } catch (error) { console.error('Error updating campaign:', error); if (error.message.includes('required') || error.message.includes('Invalid')) { throw new UserInputError(error.message); } throw new Error('Failed to update campaign'); } }, // Delete campaign deleteCampaign: async (_, { id }, { user }) => { try { if (!user) { throw new AuthenticationError('Authentication required'); } // Check if user can delete this campaign const campaign = await campaignService.getCampaignById(id, { populate: false }); if (campaign.createdBy.toString() !== user._id.toString() && !['admin', 'manager', 'super_admin'].includes(user.role)) { throw new ForbiddenError('Insufficient permissions to delete this campaign'); } return await campaignService.deleteCampaign(id, user._id); } catch (error) { console.error('Error deleting campaign:', error); if (error.message.includes('active campaign')) { throw new UserInputError(error.message); } throw new Error('Failed to delete campaign'); } }, // Activate campaign activateCampaign: async (_, { id }, { user }) => { try { if (!user) { throw new AuthenticationError('Authentication required'); } // Check if user can activate this campaign const campaign = await campaignService.getCampaignById(id, { populate: false }); if (campaign.createdBy.toString() !== user._id.toString() && !['admin', 'manager', 'super_admin'].includes(user.role)) { throw new ForbiddenError('Insufficient permissions to activate this campaign'); } return await campaignService.activateCampaign(id, user._id); } catch (error) { console.error('Error activating campaign:', error); if (error.message.includes('approved') || error.message.includes('start date')) { throw new UserInputError(error.message); } throw new Error('Failed to activate campaign'); } }, // Deactivate campaign deactivateCampaign: async (_, { id }, { user }) => { try { if (!user) { throw new AuthenticationError('Authentication required'); } // Check if user can deactivate this campaign const campaign = await campaignService.getCampaignById(id, { populate: false }); if (campaign.createdBy.toString() !== user._id.toString() && !['admin', 'manager', 'super_admin'].includes(user.role)) { throw new ForbiddenError('Insufficient permissions to deactivate this campaign'); } return await campaignService.deactivateCampaign(id, user._id); } catch (error) { console.error('Error deactivating campaign:', error); throw new Error('Failed to deactivate campaign'); } }, // Approve campaign approveCampaign: async (_, { id }, { user }) => { try { if (!user) { throw new AuthenticationError('Authentication required'); } // Check if user has approval permissions if (!['admin', 'manager', 'super_admin'].includes(user.role)) { throw new ForbiddenError('Insufficient permissions to approve campaigns'); } return await campaignService.approveCampaign(id, user._id); } catch (error) { console.error('Error approving campaign:', error); throw new Error('Failed to approve campaign'); } }, // Duplicate campaign duplicateCampaign: async (_, { id }, { user }) => { try { if (!user) { throw new AuthenticationError('Authentication required'); } return await campaignService.duplicateCampaign(id, user._id); } catch (error) { console.error('Error duplicating campaign:', error); throw new Error('Failed to duplicate campaign'); } }, // Schedule campaign scheduleCampaign: async (_, { id, schedule }, { user }) => { try { if (!user) { throw new AuthenticationError('Authentication required'); } // Check if user can schedule this campaign const campaign = await campaignService.getCampaignById(id, { populate: false }); if (campaign.createdBy.toString() !== user._id.toString() && !['admin', 'manager', 'super_admin'].includes(user.role)) { throw new ForbiddenError('Insufficient permissions to schedule this campaign'); } return await campaignService.scheduleCampaign(id, schedule, user._id); } catch (error) { console.error('Error scheduling campaign:', error); if (error.message.includes('Invalid')) { throw new UserInputError(error.message); } throw new Error('Failed to schedule campaign'); } }, // Unschedule campaign unscheduleCampaign: async (_, { id }, { user }) => { try { if (!user) { throw new AuthenticationError('Authentication required'); } // Check if user can unschedule this campaign const campaign = await campaignService.getCampaignById(id, { populate: false }); if (campaign.createdBy.toString() !== user._id.toString() && !['admin', 'manager', 'super_admin'].includes(user.role)) { throw new ForbiddenError('Insufficient permissions to unschedule this campaign'); } return await campaignService.unscheduleCampaign(id, user._id); } catch (error) { console.error('Error unscheduling campaign:', error); throw new Error('Failed to unschedule campaign'); } } }, // Field resolvers for computed fields Campaign: { // Resolve computed fields that might not be in the database isScheduled: (campaign) => { const now = new Date(); return campaign.schedule.startDate > now; }, isExpired: (campaign) => { if (!campaign.schedule.endDate) return false; return campaign.schedule.endDate < new Date(); }, isCurrentlyActive: (campaign) => { const now = new Date(); const started = campaign.schedule.startDate <= now; const notExpired = !campaign.schedule.endDate || campaign.schedule.endDate > now; return campaign.isActive && started && notExpired; }, daysRemaining: (campaign) => { if (!campaign.schedule.endDate) return null; const now = new Date(); const diffTime = campaign.schedule.endDate - now; return Math.ceil(diffTime / (1000 * 60 * 60 * 24)); }, ctr: (campaign) => { if (campaign.analytics.impressions === 0) return 0; return parseFloat((campaign.analytics.clicks / campaign.analytics.impressions * 100).toFixed(2)); } } }; export default campaignResolvers;