266 lines
10 KiB
JavaScript
266 lines
10 KiB
JavaScript
"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
|