randomayzer/src/core/validation/giveaway-schemas.ts

92 lines
3.2 KiB
TypeScript

import { z } from 'zod';
import { FilterRules } from '../types/giveaway';
import { ProviderCapabilities } from '../../providers/types';
import { ValidationError } from '../errors/http-errors';
export const filterRulesSchema = z.object({
requireLike: z.boolean().default(false),
requireComment: z.boolean().default(false),
requireRepost: z.boolean().default(false),
requireSubscription: z.boolean().default(false),
excludeAdmins: z.boolean().default(false),
excludeDuplicateComments: z.boolean().default(true),
excludeBlacklistedIds: z.array(z.string().max(128)).max(1000).default([]),
targetGroupId: z.string().max(128).optional(),
minEligibleParticipants: z.number().int().min(1).max(100000).default(1),
}).strict();
const defaultRulesObject = {
requireLike: true,
requireComment: false,
requireRepost: false,
requireSubscription: false,
excludeAdmins: false,
excludeDuplicateComments: true,
excludeBlacklistedIds: [] as string[],
minEligibleParticipants: 1,
};
export const postMetadataSchema = z.object({
platform: z.enum(['VK', 'TELEGRAM', 'YOUTUBE']),
ownerId: z.string().min(1).max(128),
postId: z.string().min(1).max(128),
sourceUrl: z.string().url().max(2048),
title: z.string().max(512),
text: z.string().max(10000).default(''),
imageUrl: z.string().url().max(2048).nullish().transform(v => v ?? undefined),
authorName: z.string().max(256).optional(),
authorAvatarUrl: z.string().url().max(2048).nullish().transform(v => v ?? undefined),
likesCount: z.number().int().min(0).default(0),
commentsCount: z.number().int().min(0).default(0),
repostsCount: z.number().int().min(0).default(0),
});
export const createGiveawaySchema = z.object({
sourceUrl: z.string().min(1).max(2048),
post: postMetadataSchema,
filterRules: filterRulesSchema.default(defaultRulesObject),
winnersCount: z.number().int().min(1).max(100).default(1),
reserveWinnersCount: z.number().int().min(0).max(100).default(0),
seed: z.string().max(512).optional(),
}).strip();
export const fetchParticipantsSchema = z.object({
filterRules: filterRulesSchema.default(defaultRulesObject),
}).strict();
export const createSnapshotSchema = z.object({
filterRules: filterRulesSchema.default(defaultRulesObject),
}).strict();
export const executeDrawSchema = z.object({
winnersCount: z.number().int().min(1).max(100).default(1),
reserveWinnersCount: z.number().int().min(0).max(100).default(0),
seed: z.string().max(512).optional(),
}).strict();
export const postPreviewSchema = z.object({
url: z.string().min(1).max(2048),
platform: z.enum(['VK', 'TELEGRAM', 'YOUTUBE']).default('VK'),
}).strict();
/**
* Validates requested filter rules against provider capabilities
*/
export function validateProviderCapabilities(
rules: FilterRules,
capabilities: ProviderCapabilities
): void {
if (rules.requireRepost && !capabilities.reposts) {
throw new ValidationError(
'Repost verification is not supported due to VK API privacy limitations',
{ condition: 'requireRepost' }
);
}
if (rules.excludeAdmins && !capabilities.adminDetection) {
throw new ValidationError(
'Admin detection requires VK ID organizer authorization',
{ condition: 'excludeAdmins' }
);
}
}