mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 18:34:13 +00:00
feat(youtube): add auto status transition hook
Automatically transitions YouTube content status when conditions are met (e.g., upload_scheduled -> published when videoId is present) and sends notifications to assigned users. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9e7b433cd0
commit
8ae5841cc1
3 changed files with 111 additions and 1 deletions
|
|
@ -9,6 +9,7 @@ import {
|
||||||
} from '../lib/youtubeAccess'
|
} from '../lib/youtubeAccess'
|
||||||
import { createTasksOnStatusChange } from '../hooks/youtubeContent/createTasksOnStatusChange'
|
import { createTasksOnStatusChange } from '../hooks/youtubeContent/createTasksOnStatusChange'
|
||||||
import { downloadThumbnail } from '../hooks/youtubeContent/downloadThumbnail'
|
import { downloadThumbnail } from '../hooks/youtubeContent/downloadThumbnail'
|
||||||
|
import { autoStatusTransitions } from '../hooks/youtubeContent/autoStatusTransitions'
|
||||||
// TODO: ScriptSectionBlock causes admin UI rendering issues
|
// TODO: ScriptSectionBlock causes admin UI rendering issues
|
||||||
// import { ScriptSectionBlock } from '../blocks/ScriptSectionBlock'
|
// import { ScriptSectionBlock } from '../blocks/ScriptSectionBlock'
|
||||||
|
|
||||||
|
|
@ -39,7 +40,7 @@ export const YouTubeContent: CollectionConfig = {
|
||||||
delete: isYouTubeManager,
|
delete: isYouTubeManager,
|
||||||
},
|
},
|
||||||
hooks: {
|
hooks: {
|
||||||
afterChange: [createTasksOnStatusChange, downloadThumbnail],
|
afterChange: [createTasksOnStatusChange, downloadThumbnail, autoStatusTransitions],
|
||||||
beforeChange: [
|
beforeChange: [
|
||||||
// Auto-Slug generieren
|
// Auto-Slug generieren
|
||||||
({ data }) => {
|
({ data }) => {
|
||||||
|
|
|
||||||
77
src/hooks/youtubeContent/autoStatusTransitions.ts
Normal file
77
src/hooks/youtubeContent/autoStatusTransitions.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
import type { CollectionAfterChangeHook } from 'payload'
|
||||||
|
import { NotificationService } from '@/lib/jobs/NotificationService'
|
||||||
|
|
||||||
|
interface TransitionContext {
|
||||||
|
currentStatus: string
|
||||||
|
youtubeVideoId?: string | null
|
||||||
|
hasAllChecklistsComplete: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the next status based on current state and conditions
|
||||||
|
*/
|
||||||
|
export function getNextStatus(context: TransitionContext): string | null {
|
||||||
|
const { currentStatus, youtubeVideoId } = context
|
||||||
|
|
||||||
|
// Upload completed → published
|
||||||
|
if (currentStatus === 'upload_scheduled' && youtubeVideoId) {
|
||||||
|
return 'published'
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a manual transition should be suggested
|
||||||
|
*/
|
||||||
|
export function shouldTransitionStatus(
|
||||||
|
status: string,
|
||||||
|
context: { hasVideoFile?: boolean },
|
||||||
|
): boolean {
|
||||||
|
if (status === 'approved' && context.hasVideoFile) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook: Automatische Status-Übergänge nach Änderungen
|
||||||
|
*/
|
||||||
|
export const autoStatusTransitions: CollectionAfterChangeHook = async ({
|
||||||
|
doc,
|
||||||
|
previousDoc,
|
||||||
|
req,
|
||||||
|
operation,
|
||||||
|
}) => {
|
||||||
|
if (operation !== 'update') return doc
|
||||||
|
|
||||||
|
const nextStatus = getNextStatus({
|
||||||
|
currentStatus: doc.status,
|
||||||
|
youtubeVideoId: doc.youtube?.videoId,
|
||||||
|
hasAllChecklistsComplete: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (nextStatus && nextStatus !== doc.status) {
|
||||||
|
console.log(`[autoStatusTransitions] ${doc.id}: ${doc.status} → ${nextStatus}`)
|
||||||
|
|
||||||
|
await req.payload.update({
|
||||||
|
collection: 'youtube-content',
|
||||||
|
id: doc.id,
|
||||||
|
data: { status: nextStatus },
|
||||||
|
depth: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Notification
|
||||||
|
if (doc.assignedTo) {
|
||||||
|
const assignedToId = typeof doc.assignedTo === 'object' ? doc.assignedTo.id : doc.assignedTo
|
||||||
|
const notificationService = new NotificationService(req.payload)
|
||||||
|
await notificationService.createNotification({
|
||||||
|
recipientId: assignedToId,
|
||||||
|
type: 'system',
|
||||||
|
title: `Video-Status automatisch geändert: ${nextStatus}`,
|
||||||
|
link: `/admin/collections/youtube-content/${doc.id}`,
|
||||||
|
relatedVideoId: doc.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc
|
||||||
|
}
|
||||||
32
tests/unit/youtube/auto-status-transitions.unit.spec.ts
Normal file
32
tests/unit/youtube/auto-status-transitions.unit.spec.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import { getNextStatus, shouldTransitionStatus } from '@/hooks/youtubeContent/autoStatusTransitions'
|
||||||
|
|
||||||
|
describe('Auto Status Transitions', () => {
|
||||||
|
it('should transition to published when upload is complete', () => {
|
||||||
|
const result = getNextStatus({
|
||||||
|
currentStatus: 'upload_scheduled',
|
||||||
|
youtubeVideoId: 'VID123',
|
||||||
|
hasAllChecklistsComplete: false,
|
||||||
|
})
|
||||||
|
expect(result).toBe('published')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not transition if no video ID on upload_scheduled', () => {
|
||||||
|
const result = getNextStatus({
|
||||||
|
currentStatus: 'upload_scheduled',
|
||||||
|
youtubeVideoId: null,
|
||||||
|
hasAllChecklistsComplete: false,
|
||||||
|
})
|
||||||
|
expect(result).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should transition approved to upload_scheduled when video file exists', () => {
|
||||||
|
const result = shouldTransitionStatus('approved', { hasVideoFile: true })
|
||||||
|
expect(result).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not suggest transition for published status', () => {
|
||||||
|
const result = shouldTransitionStatus('published', { hasVideoFile: true })
|
||||||
|
expect(result).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Reference in a new issue