mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-25 23:54:37 +02:00
Projects included: - maerchenzauber (NestJS backend + Expo mobile + SvelteKit web + Astro landing) - manacore (Expo mobile + SvelteKit web + Astro landing) - manadeck (NestJS backend + Expo mobile + SvelteKit web) - memoro (Expo mobile + SvelteKit web + Astro landing) This commit preserves the current state before monorepo restructuring. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
278 lines
6.7 KiB
TypeScript
278 lines
6.7 KiB
TypeScript
import {
|
|
Controller,
|
|
Get,
|
|
Put,
|
|
Body,
|
|
UseGuards,
|
|
UsePipes,
|
|
ValidationPipe,
|
|
Param,
|
|
} from '@nestjs/common';
|
|
import { AuthGuard, CurrentUser } from '@mana-core/nestjs-integration';
|
|
import { UserToken } from '../decorators/user.decorator';
|
|
import { SettingsClientService, UserSettings } from './settings-client.service';
|
|
import { SettingsService } from '../core/services/settings.service';
|
|
import { JwtPayload } from '../types/jwt-payload.interface';
|
|
import { UpdateUserSettingsDto } from './dto/settings.dto';
|
|
import { ImageModelId } from '../core/models/image-models';
|
|
|
|
@Controller('settings')
|
|
@UseGuards(AuthGuard)
|
|
export class SettingsController {
|
|
constructor(
|
|
private readonly settingsClientService: SettingsClientService,
|
|
private readonly settingsService: SettingsService,
|
|
) {}
|
|
|
|
/**
|
|
* Get user-specific settings
|
|
*/
|
|
@Get('user')
|
|
async getUserSettings(
|
|
@CurrentUser() user: JwtPayload,
|
|
@UserToken() token: string,
|
|
): Promise<{ userId: string; settings: UserSettings }> {
|
|
const settings = await this.settingsClientService.getUserSettings(token);
|
|
return {
|
|
userId: user.sub,
|
|
settings: settings || {
|
|
// Default settings if none exist
|
|
preferences: {
|
|
language: 'en',
|
|
timezone: 'UTC',
|
|
dateFormat: 'MM/DD/YYYY',
|
|
},
|
|
maerchenzauber: {
|
|
language: 'de',
|
|
storyLength: 'medium',
|
|
ageGroup: '4-6',
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get available image generation models
|
|
*/
|
|
@Get('image-models')
|
|
async getAvailableImageModels() {
|
|
const models = this.settingsService.getAvailableImageModels();
|
|
return {
|
|
models,
|
|
default: 'imagen-4-fast',
|
|
categories: {
|
|
budget: models.filter((m) => m.category === 'budget'),
|
|
standard: models.filter((m) => m.category === 'standard'),
|
|
premium: models.filter((m) => m.category === 'premium'),
|
|
specialty: models.filter((m) => m.category === 'specialty'),
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get user's selected image model
|
|
*/
|
|
@Get('user/image-model')
|
|
async getUserImageModel(@CurrentUser() user: JwtPayload) {
|
|
const result = await this.settingsService.getUserImageModel(user.sub);
|
|
if (result.error) {
|
|
return {
|
|
model: 'imagen-4-fast',
|
|
error: result.error.message,
|
|
};
|
|
}
|
|
return {
|
|
model: result.data,
|
|
modelInfo: this.settingsService.getImageModelInfo(result.data!),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Update user's selected image model
|
|
*/
|
|
@Put('user/image-model')
|
|
async updateUserImageModel(
|
|
@CurrentUser() user: JwtPayload,
|
|
@Body('model') modelId: ImageModelId,
|
|
) {
|
|
const result = await this.settingsService.setUserImageModel(
|
|
user.sub,
|
|
modelId,
|
|
);
|
|
if (result.error) {
|
|
return {
|
|
success: false,
|
|
error: result.error.message,
|
|
};
|
|
}
|
|
return {
|
|
success: true,
|
|
model: modelId,
|
|
modelInfo: this.settingsService.getImageModelInfo(modelId),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Update user-specific settings
|
|
*/
|
|
@Put('user')
|
|
@UsePipes(ValidationPipe)
|
|
async updateUserSettings(
|
|
@CurrentUser() user: JwtPayload,
|
|
@UserToken() token: string,
|
|
@Body() settings: UpdateUserSettingsDto,
|
|
) {
|
|
await this.settingsClientService.updateServiceSettings(
|
|
settings as any,
|
|
token,
|
|
);
|
|
|
|
return {
|
|
success: true,
|
|
userId: user.sub,
|
|
settings,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get app-wide settings (public)
|
|
*/
|
|
@Get('app')
|
|
async getAppSettings() {
|
|
const settings = this.settingsService.getAllSettings();
|
|
return {
|
|
app: 'storyteller',
|
|
version: '1.0.0',
|
|
settings: {
|
|
features: {
|
|
aiStoryGeneration: true,
|
|
characterCreation: true,
|
|
imageGeneration: true,
|
|
collaborativeStories: false, // Coming soon
|
|
voiceNarration: false, // Coming soon
|
|
},
|
|
limits: {
|
|
maxCharactersPerUser: 50,
|
|
maxStoriesPerUser: 100,
|
|
maxPagesPerStory: 20,
|
|
maxImageGenerationsPerDay: 10,
|
|
},
|
|
costs: {
|
|
characterCreation: 5,
|
|
storyGeneration: 10,
|
|
imageGeneration: 3,
|
|
voiceNarration: 15,
|
|
},
|
|
...settings,
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get feature flags
|
|
*/
|
|
@Get('features')
|
|
async getFeatureFlags(@CurrentUser() user: JwtPayload) {
|
|
// Check user-specific feature flags
|
|
const userRole = user.role || 'user';
|
|
|
|
return {
|
|
userId: user.sub,
|
|
role: userRole,
|
|
features: {
|
|
// Core features
|
|
createCharacter: true,
|
|
createStory: true,
|
|
generateImages: true,
|
|
|
|
// Premium features (role-based)
|
|
unlimitedStories: userRole === 'premium' || userRole === 'admin',
|
|
voiceNarration: userRole === 'premium' || userRole === 'admin',
|
|
collaborativeMode: false, // Not implemented yet
|
|
|
|
// Beta features
|
|
betaFeatures: userRole === 'admin',
|
|
debugMode: userRole === 'admin',
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get creators list (for story creation)
|
|
*/
|
|
@Get('creators')
|
|
async getCreators() {
|
|
const creators = this.settingsService.getCreators();
|
|
const authors = creators.filter((c) => c.type === 'author');
|
|
const illustrators = creators.filter((c) => c.type === 'illustrator');
|
|
|
|
return {
|
|
authors,
|
|
illustrators,
|
|
total: creators.length,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get creators by type
|
|
*/
|
|
@Get('creators/:type')
|
|
async getCreatorsByType(@Param('type') type: 'author' | 'illustrator') {
|
|
if (type !== 'author' && type !== 'illustrator') {
|
|
return {
|
|
error: 'Invalid creator type. Must be "author" or "illustrator"',
|
|
};
|
|
}
|
|
|
|
const creators = this.settingsService.getCreatorsByType(type);
|
|
return {
|
|
creators,
|
|
type,
|
|
count: creators.length,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get supported languages
|
|
*/
|
|
@Get('languages')
|
|
async getSupportedLanguages() {
|
|
return {
|
|
languages: [
|
|
{ code: 'en', name: 'English', flag: '🇺🇸' },
|
|
{ code: 'de', name: 'Deutsch', flag: '🇩🇪' },
|
|
{ code: 'es', name: 'Español', flag: '🇪🇸' },
|
|
{ code: 'fr', name: 'Français', flag: '🇫🇷' },
|
|
{ code: 'it', name: 'Italiano', flag: '🇮🇹' },
|
|
],
|
|
default: 'en',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get theme options
|
|
*/
|
|
@Get('themes')
|
|
async getThemeOptions() {
|
|
return {
|
|
themes: [
|
|
{
|
|
id: 'light',
|
|
name: 'Light Mode',
|
|
description: 'Default light theme',
|
|
},
|
|
{
|
|
id: 'dark',
|
|
name: 'Dark Mode',
|
|
description: 'Easy on the eyes',
|
|
},
|
|
{
|
|
id: 'kids',
|
|
name: 'Kids Mode',
|
|
description: 'Colorful and playful',
|
|
},
|
|
],
|
|
default: 'light',
|
|
};
|
|
}
|
|
}
|