92 lines
3.2 KiB
TypeScript
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' }
|
|
);
|
|
}
|
|
}
|