- Added new models for premium tier configurations and assignments, enabling feature limits for free and premium users. - Introduced GDPR deletion logging and commands for user data management. - Enhanced logging configuration with retention days for audit logs. - Updated bot commands and job processing to include new premium and GDPR functionalities. - Improved localization with new keys for premium features and GDPR commands in both English and German. - Added UI components for managing premium settings and logging retention in the WebUI.
95 lines
3.1 KiB
TypeScript
95 lines
3.1 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
const snowflake = z.string().regex(/^\d{17,20}$/);
|
|
|
|
export const PremiumTierSchema = z.enum(['FREE', 'PREMIUM']);
|
|
export type PremiumTier = z.infer<typeof PremiumTierSchema>;
|
|
|
|
export const PremiumFeatureKeySchema = z.enum(['tags', 'feeds', 'guildbackup']);
|
|
export type PremiumFeatureKey = z.infer<typeof PremiumFeatureKeySchema>;
|
|
|
|
export const PremiumFeaturesSchema = z.object({
|
|
tags: z.boolean(),
|
|
feeds: z.boolean(),
|
|
guildbackup: z.boolean()
|
|
});
|
|
export type PremiumFeatures = z.infer<typeof PremiumFeaturesSchema>;
|
|
|
|
export const PremiumTierConfigSchema = z.object({
|
|
tier: PremiumTierSchema,
|
|
maxTags: z.number().int().min(0).max(10_000),
|
|
maxFeeds: z.number().int().min(0).max(10_000),
|
|
maxBackups: z.number().int().min(0).max(10_000),
|
|
features: PremiumFeaturesSchema
|
|
});
|
|
export type PremiumTierConfig = z.infer<typeof PremiumTierConfigSchema>;
|
|
|
|
export const PremiumTierConfigPatchSchema = PremiumTierConfigSchema.omit({ tier: true }).partial().refine(
|
|
(value) => Object.keys(value).length > 0,
|
|
{ message: 'At least one field is required' }
|
|
);
|
|
export type PremiumTierConfigPatch = z.infer<typeof PremiumTierConfigPatchSchema>;
|
|
|
|
export const DEFAULT_PREMIUM_TIER_CONFIGS: Record<PremiumTier, PremiumTierConfig> = {
|
|
FREE: {
|
|
tier: 'FREE',
|
|
maxTags: 15,
|
|
maxFeeds: 3,
|
|
maxBackups: 2,
|
|
features: { tags: true, feeds: true, guildbackup: true }
|
|
},
|
|
PREMIUM: {
|
|
tier: 'PREMIUM',
|
|
maxTags: 100,
|
|
maxFeeds: 25,
|
|
maxBackups: 25,
|
|
features: { tags: true, feeds: true, guildbackup: true }
|
|
}
|
|
};
|
|
|
|
export const GuildPremiumAssignSchema = z.object({
|
|
guildId: snowflake,
|
|
tier: PremiumTierSchema,
|
|
note: z.string().max(500).nullable().optional(),
|
|
expiresAt: z.string().datetime().nullable().optional()
|
|
});
|
|
export type GuildPremiumAssign = z.infer<typeof GuildPremiumAssignSchema>;
|
|
|
|
export const UserPremiumAssignSchema = z.object({
|
|
userId: snowflake,
|
|
tier: PremiumTierSchema,
|
|
note: z.string().max(500).nullable().optional(),
|
|
expiresAt: z.string().datetime().nullable().optional()
|
|
});
|
|
export type UserPremiumAssign = z.infer<typeof UserPremiumAssignSchema>;
|
|
|
|
export const PremiumLimitResourceSchema = z.enum(['tags', 'feeds', 'backups']);
|
|
export type PremiumLimitResource = z.infer<typeof PremiumLimitResourceSchema>;
|
|
|
|
export function limitKeyForResource(resource: PremiumLimitResource): 'maxTags' | 'maxFeeds' | 'maxBackups' {
|
|
if (resource === 'tags') return 'maxTags';
|
|
if (resource === 'feeds') return 'maxFeeds';
|
|
return 'maxBackups';
|
|
}
|
|
|
|
export function featureKeyForResource(resource: PremiumLimitResource): PremiumFeatureKey {
|
|
if (resource === 'backups') return 'guildbackup';
|
|
return resource;
|
|
}
|
|
|
|
export function parsePremiumFeatures(raw: unknown): PremiumFeatures {
|
|
const parsed = PremiumFeaturesSchema.safeParse(raw);
|
|
if (parsed.success) {
|
|
return parsed.data;
|
|
}
|
|
return { tags: true, feeds: true, guildbackup: true };
|
|
}
|
|
|
|
export function isAssignmentActive(expiresAt: Date | string | null | undefined, now = new Date()): boolean {
|
|
if (!expiresAt) {
|
|
return true;
|
|
}
|
|
const date = typeof expiresAt === 'string' ? new Date(expiresAt) : expiresAt;
|
|
return date.getTime() > now.getTime();
|
|
}
|