Skip to main content
Glama
config.service.ts5.92 kB
import { Injectable } from '@nestjs/common'; import { ConfigService as NestConfigService } from '@nestjs/config'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; export interface Project { id: number; name: string; } export interface Module { id: number; name: string; project_id: number; description?: string; } export interface Activity { id: number; name: string; } export interface UserConfig { apiUrl?: string; token?: string; user?: { id: number; username: string; name: string; email?: string; roles?: string[]; managerId?: number; reporting_manager_id?: number; }; // Available data (fetched from API on login) availableProjects?: Project[]; availableModules?: Module[]; availableActivities?: Activity[]; // User configured assignments userAssignedProject?: Project; userAssignedModules?: Module[]; // Other geminiApiKey?: string; } @Injectable() export class TimesheetConfigService { private readonly configDir: string; private readonly configFile: string; private userConfig: UserConfig = {}; constructor(private readonly nestConfigService: NestConfigService) { this.configDir = path.join(os.homedir(), '.config', 'timesheet-mcp'); this.configFile = path.join(this.configDir, 'config.json'); this.loadUserConfig(); } /** * Load user configuration from ~/.config/timesheet-mcp/config.json */ private loadUserConfig(): void { try { if (fs.existsSync(this.configFile)) { const data = fs.readFileSync(this.configFile, 'utf-8'); this.userConfig = JSON.parse(data); } } catch (error) { console.warn('Failed to load user config:', error.message); } } /** * Save user configuration to file */ saveUserConfig(config: Partial<UserConfig>): void { try { // Ensure directory exists if (!fs.existsSync(this.configDir)) { fs.mkdirSync(this.configDir, { recursive: true, mode: 0o700 }); } // Merge with existing config this.userConfig = { ...this.userConfig, ...config }; // Write to file fs.writeFileSync( this.configFile, JSON.stringify(this.userConfig, null, 2), { mode: 0o600 }, ); } catch (error) { throw new Error(`Failed to save user config: ${error.message}`); } } /** * Get the full user configuration */ getUserConfig(): UserConfig { return this.userConfig; } /** * Get JWT token */ getToken(): string | undefined { return this.userConfig.token; } /** * Set JWT token */ setToken(token: string): void { this.saveUserConfig({ token }); } /** * Get user profile */ getUser(): UserConfig['user'] | undefined { return this.userConfig.user; } /** * Set user profile */ setUser(user: UserConfig['user']): void { this.saveUserConfig({ user }); } /** * Get API URL */ getApiUrl(): string { return ( this.userConfig.apiUrl || this.nestConfigService.get<string>('API_BASE_URL') || 'https://timesheet.pinnacle.in:3000/api' ); } /** * Get Gemini API key */ getGeminiApiKey(): string | undefined { return ( this.userConfig.geminiApiKey || this.nestConfigService.get<string>('GEMINI_API_KEY') ); } /** * Get available projects (fetched from API) */ getAvailableProjects(): Project[] { return this.userConfig.availableProjects || []; } /** * Set available projects */ setAvailableProjects(projects: Project[]): void { this.saveUserConfig({ availableProjects: projects }); } /** * Get available modules (fetched from API) */ getAvailableModules(): Module[] { return this.userConfig.availableModules || []; } /** * Set available modules */ setAvailableModules(modules: Module[]): void { this.saveUserConfig({ availableModules: modules }); } /** * Get available activities (fetched from API) */ getAvailableActivities(): Activity[] { return this.userConfig.availableActivities || []; } /** * Set available activities */ setAvailableActivities(activities: Activity[]): void { this.saveUserConfig({ availableActivities: activities }); } /** * Get user's assigned project */ getUserAssignedProject(): Project | undefined { return this.userConfig.userAssignedProject; } /** * Set user's assigned project */ setUserAssignedProject(project: Project): void { this.saveUserConfig({ userAssignedProject: project }); } /** * Get user's assigned modules */ getUserAssignedModules(): Module[] { return this.userConfig.userAssignedModules || []; } /** * Set user's assigned modules */ setUserAssignedModules(modules: Module[]): void { this.saveUserConfig({ userAssignedModules: modules }); } /** * Check if user is authenticated (has token) */ isConfigured(): boolean { return !!this.userConfig.token; } /** * Check if user has configured their project and modules */ isUserConfigured(): boolean { return ( !!this.userConfig.userAssignedProject && !!this.userConfig.userAssignedModules && this.userConfig.userAssignedModules.length > 0 ); } /** * Check what configuration is missing */ needsConfiguration(): { project: boolean; modules: boolean } { return { project: !this.userConfig.userAssignedProject, modules: !this.userConfig.userAssignedModules || this.userConfig.userAssignedModules.length === 0, }; } /** * Clear all configuration (logout) */ clearConfig(): void { this.userConfig = {}; try { if (fs.existsSync(this.configFile)) { fs.unlinkSync(this.configFile); } } catch (error) { console.warn('Failed to clear config:', error.message); } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/arshad-khan1/Timesheet-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server