Files
Nexumi/apps/webui/src/lib/module-configs/feeds.ts
smueller 08af99ed52 Implement premium features and GDPR compliance in bot and WebUI
- 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.
2026-07-22 16:59:23 +02:00

93 lines
2.6 KiB
TypeScript

import type {
SocialFeedDashboard,
SocialFeedDashboardCreate,
SocialFeedDashboardUpdate
} from '@nexumi/shared';
import type { SocialFeed } from '@prisma/client';
import { prisma } from '../prisma';
import { assertPremiumLimit, PremiumLimitError } from '../premium';
export class FeedPremiumError extends Error {
constructor(public readonly code: 'premium_limit' | 'premium_feature') {
super(code);
}
}
function toDashboard(feed: SocialFeed): SocialFeedDashboard {
return {
id: feed.id,
type: feed.type as SocialFeedDashboard['type'],
sourceId: feed.sourceId,
channelId: feed.channelId,
rolePingId: feed.rolePingId ?? '',
template: feed.template,
enabled: feed.enabled
};
}
export async function listFeeds(guildId: string): Promise<SocialFeedDashboard[]> {
const feeds = await prisma.socialFeed.findMany({
where: { guildId },
orderBy: { createdAt: 'asc' }
});
return feeds.map(toDashboard);
}
export async function createFeed(
guildId: string,
input: SocialFeedDashboardCreate
): Promise<SocialFeedDashboard> {
await prisma.guild.upsert({ where: { id: guildId }, update: {}, create: { id: guildId } });
const currentCount = await prisma.socialFeed.count({ where: { guildId } });
try {
await assertPremiumLimit(prisma, guildId, 'feeds', currentCount);
} catch (error) {
if (error instanceof PremiumLimitError) {
throw new FeedPremiumError(error.code === 'feature_disabled' ? 'premium_feature' : 'premium_limit');
}
throw error;
}
const feed = await prisma.socialFeed.create({
data: {
guildId,
type: input.type,
sourceId: input.sourceId,
channelId: input.channelId,
rolePingId: input.rolePingId || null,
template: input.template ?? null,
enabled: input.enabled
}
});
return toDashboard(feed);
}
export async function updateFeed(
guildId: string,
feedId: string,
patch: SocialFeedDashboardUpdate
): Promise<SocialFeedDashboard | null> {
const existing = await prisma.socialFeed.findFirst({ where: { id: feedId, guildId } });
if (!existing) {
return null;
}
const { rolePingId, ...rest } = patch;
const updated = await prisma.socialFeed.update({
where: { id: feedId },
data: {
...rest,
...(rolePingId !== undefined ? { rolePingId: rolePingId === '' ? null : rolePingId } : {})
}
});
return toDashboard(updated);
}
export async function deleteFeed(guildId: string, feedId: string): Promise<boolean> {
const existing = await prisma.socialFeed.findFirst({ where: { id: feedId, guildId } });
if (!existing) {
return false;
}
await prisma.socialFeed.delete({ where: { id: feedId } });
return true;
}