- 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.
101 lines
3.0 KiB
TypeScript
101 lines
3.0 KiB
TypeScript
import type { PrismaClient } from '@prisma/client';
|
|
import {
|
|
DEFAULT_PREMIUM_TIER_CONFIGS,
|
|
featureKeyForResource,
|
|
isAssignmentActive,
|
|
limitKeyForResource,
|
|
parsePremiumFeatures,
|
|
PremiumTierSchema,
|
|
type PremiumLimitResource,
|
|
type PremiumTier,
|
|
type PremiumTierConfig
|
|
} from '@nexumi/shared';
|
|
|
|
export class PremiumLimitError extends Error {
|
|
constructor(
|
|
public readonly code: 'feature_disabled' | 'limit_reached',
|
|
public readonly resource: PremiumLimitResource,
|
|
public readonly limit: number,
|
|
public readonly current: number,
|
|
public readonly tier: PremiumTier
|
|
) {
|
|
super(code);
|
|
}
|
|
}
|
|
|
|
function toConfig(row: {
|
|
tier: string;
|
|
maxTags: number;
|
|
maxFeeds: number;
|
|
maxBackups: number;
|
|
features: unknown;
|
|
}): PremiumTierConfig {
|
|
return {
|
|
tier: PremiumTierSchema.parse(row.tier),
|
|
maxTags: row.maxTags,
|
|
maxFeeds: row.maxFeeds,
|
|
maxBackups: row.maxBackups,
|
|
features: parsePremiumFeatures(row.features)
|
|
};
|
|
}
|
|
|
|
export async function ensurePremiumTierConfigs(prisma: PrismaClient): Promise<PremiumTierConfig[]> {
|
|
const configs: PremiumTierConfig[] = [];
|
|
for (const tier of PremiumTierSchema.options) {
|
|
const defaults = DEFAULT_PREMIUM_TIER_CONFIGS[tier];
|
|
const row = await prisma.premiumTierConfig.upsert({
|
|
where: { tier },
|
|
create: {
|
|
tier,
|
|
maxTags: defaults.maxTags,
|
|
maxFeeds: defaults.maxFeeds,
|
|
maxBackups: defaults.maxBackups,
|
|
features: defaults.features
|
|
},
|
|
update: {}
|
|
});
|
|
configs.push(toConfig(row));
|
|
}
|
|
return configs;
|
|
}
|
|
|
|
export async function getPremiumTierConfigs(prisma: PrismaClient): Promise<PremiumTierConfig[]> {
|
|
return ensurePremiumTierConfigs(prisma);
|
|
}
|
|
|
|
export async function resolveGuildTier(prisma: PrismaClient, guildId: string): Promise<PremiumTier> {
|
|
const assignment = await prisma.guildPremiumAssignment.findUnique({ where: { guildId } });
|
|
if (!assignment || !isAssignmentActive(assignment.expiresAt)) {
|
|
return 'FREE';
|
|
}
|
|
const parsed = PremiumTierSchema.safeParse(assignment.tier);
|
|
return parsed.success ? parsed.data : 'FREE';
|
|
}
|
|
|
|
export async function resolveGuildPremiumConfig(
|
|
prisma: PrismaClient,
|
|
guildId: string
|
|
): Promise<PremiumTierConfig> {
|
|
const tier = await resolveGuildTier(prisma, guildId);
|
|
const configs = await ensurePremiumTierConfigs(prisma);
|
|
return configs.find((config) => config.tier === tier) ?? DEFAULT_PREMIUM_TIER_CONFIGS[tier];
|
|
}
|
|
|
|
export async function assertPremiumLimit(
|
|
prisma: PrismaClient,
|
|
guildId: string,
|
|
resource: PremiumLimitResource,
|
|
currentCount: number
|
|
): Promise<PremiumTierConfig> {
|
|
const config = await resolveGuildPremiumConfig(prisma, guildId);
|
|
const featureKey = featureKeyForResource(resource);
|
|
if (!config.features[featureKey]) {
|
|
throw new PremiumLimitError('feature_disabled', resource, 0, currentCount, config.tier);
|
|
}
|
|
const limit = config[limitKeyForResource(resource)];
|
|
if (currentCount >= limit) {
|
|
throw new PremiumLimitError('limit_reached', resource, limit, currentCount, config.tier);
|
|
}
|
|
return config;
|
|
}
|