"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.videoScheduleRoutes = videoScheduleRoutes; const database_1 = require("../../../config/database"); const auth_1 = require("../middleware/auth"); const video_schedule_queue_service_1 = require("../../../services/video-schedule-queue.service"); const logger_1 = require("../../../utils/logger"); const zod_1 = require("zod"); // Validation schemas const schedulePublishSchema = zod_1.z.object({ publishAt: zod_1.z.string().datetime(), timezone: zod_1.z.string().optional().default('UTC'), }); const scheduleUnpublishSchema = zod_1.z.object({ unpublishAt: zod_1.z.string().datetime(), timezone: zod_1.z.string().optional().default('UTC'), }); async function videoScheduleRoutes(fastify) { /** * POST /videos/:id/schedule-publish * Schedule a video to be published at a specific time */ fastify.post('/:id/schedule-publish', { preHandler: auth_1.requireAdminRole, }, async (request, reply) => { const videoId = parseInt(request.params.id); const { publishAt, timezone } = request.body; // Validate input try { schedulePublishSchema.parse(request.body); } catch (error) { return reply.code(400).send({ message: 'Invalid input', error }); } try { // Verify video exists const video = await database_1.prisma.video.findUnique({ where: { id: videoId }, }); if (!video) { return reply.code(404).send({ message: 'Video not found' }); } // Parse publish time const publishDate = new Date(publishAt); const now = new Date(); if (publishDate <= now) { return reply.code(400).send({ message: 'Publish time must be in the future' }); } // Get user ID from request (set by auth middleware) const userId = request.user?.id; if (!userId) { return reply.code(401).send({ message: 'Unauthorized' }); } // Schedule the publish const result = await video_schedule_queue_service_1.videoScheduleQueueService.schedulePublish(videoId, publishDate, userId); logger_1.logger.info(`Scheduled video ${videoId} to publish at ${publishDate.toISOString()}`); return { success: true, message: 'Video scheduled for publish', scheduledFor: result.scheduledFor, jobId: result.jobId, }; } catch (error) { logger_1.logger.error('Failed to schedule video publish', { error, videoId }); return reply.code(500).send({ message: error instanceof Error ? error.message : 'Failed to schedule video', }); } }); /** * POST /videos/:id/schedule-unpublish * Schedule a video to be unpublished at a specific time */ fastify.post('/:id/schedule-unpublish', { preHandler: auth_1.requireAdminRole, }, async (request, reply) => { const videoId = parseInt(request.params.id); const { unpublishAt, timezone } = request.body; // Validate input try { scheduleUnpublishSchema.parse(request.body); } catch (error) { return reply.code(400).send({ message: 'Invalid input', error }); } try { // Verify video exists const video = await database_1.prisma.video.findUnique({ where: { id: videoId }, }); if (!video) { return reply.code(404).send({ message: 'Video not found' }); } // Parse unpublish time const unpublishDate = new Date(unpublishAt); const now = new Date(); if (unpublishDate <= now) { return reply.code(400).send({ message: 'Unpublish time must be in the future' }); } // Get user ID from request const userId = request.user?.id; if (!userId) { return reply.code(401).send({ message: 'Unauthorized' }); } // Schedule the unpublish const result = await video_schedule_queue_service_1.videoScheduleQueueService.scheduleUnpublish(videoId, unpublishDate, userId); logger_1.logger.info(`Scheduled video ${videoId} to unpublish at ${unpublishDate.toISOString()}`); return { success: true, message: 'Video scheduled for unpublish', scheduledFor: result.scheduledFor, jobId: result.jobId, }; } catch (error) { logger_1.logger.error('Failed to schedule video unpublish', { error, videoId }); return reply.code(500).send({ message: error instanceof Error ? error.message : 'Failed to schedule video', }); } }); /** * DELETE /videos/:id/schedule/:action * Cancel a scheduled publish or unpublish */ fastify.delete('/:id/schedule/:action', { preHandler: auth_1.requireAdminRole, }, async (request, reply) => { const videoId = parseInt(request.params.id); const action = request.params.action; if (!['publish', 'unpublish'].includes(action)) { return reply.code(400).send({ message: 'Invalid action. Must be "publish" or "unpublish"' }); } try { await video_schedule_queue_service_1.videoScheduleQueueService.cancelSchedule(videoId, action); logger_1.logger.info(`Cancelled ${action} schedule for video ${videoId}`); return { success: true, message: `${action} schedule cancelled`, }; } catch (error) { logger_1.logger.error(`Failed to cancel ${action} schedule`, { error, videoId }); return reply.code(500).send({ message: `Failed to cancel ${action} schedule`, }); } }); /** * GET /videos/schedules/upcoming * Get all upcoming scheduled publish/unpublish operations */ fastify.get('/schedules/upcoming', { preHandler: auth_1.requireAdminRole, }, async (request, reply) => { const limit = parseInt(request.query.limit || '50'); try { const schedules = await video_schedule_queue_service_1.videoScheduleQueueService.getUpcomingSchedules(limit); return { schedules, total: schedules.length, }; } catch (error) { logger_1.logger.error('Failed to get upcoming schedules', { error }); return reply.code(500).send({ message: 'Failed to fetch schedules' }); } }); /** * GET /videos/:id/schedule-history * Get schedule history for a specific video */ fastify.get('/:id/schedule-history', { preHandler: auth_1.requireAdminRole, }, async (request, reply) => { const videoId = parseInt(request.params.id); const limit = parseInt(request.query.limit || '10'); try { const history = await video_schedule_queue_service_1.videoScheduleQueueService.getScheduleHistory(videoId, limit); return { videoId, history, }; } catch (error) { logger_1.logger.error('Failed to get schedule history', { error, videoId }); return reply.code(500).send({ message: 'Failed to fetch schedule history' }); } }); /** * GET /videos/schedules/stats * Get queue statistics */ fastify.get('/schedules/stats', { preHandler: auth_1.requireAdminRole, }, async (request, reply) => { try { const stats = await video_schedule_queue_service_1.videoScheduleQueueService.getStats(); return stats; } catch (error) { logger_1.logger.error('Failed to get schedule stats', { error }); return reply.code(500).send({ message: 'Failed to fetch stats' }); } }); /** * POST /videos/schedules/pause * Pause the schedule queue */ fastify.post('/schedules/pause', { preHandler: auth_1.requireAdminRole, }, async (request, reply) => { try { await video_schedule_queue_service_1.videoScheduleQueueService.pause(); return { success: true, message: 'Schedule queue paused', }; } catch (error) { logger_1.logger.error('Failed to pause schedule queue', { error }); return reply.code(500).send({ message: 'Failed to pause queue' }); } }); /** * POST /videos/schedules/resume * Resume the schedule queue */ fastify.post('/schedules/resume', { preHandler: auth_1.requireAdminRole, }, async (request, reply) => { try { await video_schedule_queue_service_1.videoScheduleQueueService.resume(); return { success: true, message: 'Schedule queue resumed', }; } catch (error) { logger_1.logger.error('Failed to resume schedule queue', { error }); return reply.code(500).send({ message: 'Failed to resume queue' }); } }); /** * POST /videos/schedules/cleanup * Clean up old completed jobs */ fastify.post('/schedules/cleanup', { preHandler: auth_1.requireAdminRole, }, async (request, reply) => { try { const cleaned = await video_schedule_queue_service_1.videoScheduleQueueService.cleanup(); return { success: true, message: `Cleaned ${cleaned} old jobs`, cleaned, }; } catch (error) { logger_1.logger.error('Failed to cleanup schedule queue', { error }); return reply.code(500).send({ message: 'Failed to cleanup queue' }); } }); } //# sourceMappingURL=video-schedule.routes.js.map