mcp-quiz-server
Version:
🧠AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.
216 lines • 7.22 kB
JavaScript
export class SettingsService {
constructor() {
this.listeners = new Set();
this.STORAGE_KEY = 'quiz-app-settings';
this.SESSION_KEY = 'quiz-app-session';
this.settings = this.getDefaultSettings();
this.loadSettings();
this.validateSession();
}
static getInstance() {
if (!SettingsService.instance) {
SettingsService.instance = new SettingsService();
}
return SettingsService.instance;
}
getDefaultSettings() {
return {
ui: {
hideDisabledNavButtons: false,
hideAllNavButtons: false,
autoAdvanceQuestions: false,
clickToAdvance: false,
showContinueButton: true,
announceSelections: true,
selectionFeedbackDuration: 2000,
showQuestionNumbers: true,
enableAnimations: true,
defaultViewMode: 'list',
sidebarExpanded: true,
theme: 'light',
accessibilityMode: false
},
quiz: {
showHints: false,
confirmBeforeSubmit: true,
highlightAnsweredQuestions: true,
timerEnabled: false,
maxAttempts: 3
},
user: {
role: 'guest',
permissions: ['view'],
sessionTimeout: 3600000,
lastLoginTime: Date.now()
}
};
}
getSettings() {
return { ...this.settings };
}
updateSettings(updates) {
if (!this.hasPermission('modify_settings')) {
throw new Error('Insufficient permissions to modify settings');
}
this.settings = this.mergeDeep(this.settings, updates);
this.saveSettings();
this.notifyListeners();
}
updateUISettings(uiSettings) {
this.updateSettings({ ui: { ...this.settings.ui, ...uiSettings } });
}
updateQuizSettings(quizSettings) {
this.updateSettings({ quiz: { ...this.settings.quiz, ...quizSettings } });
}
resetToDefaults() {
if (this.settings.user.role !== 'admin') {
throw new Error('Only administrators can reset settings to defaults');
}
const currentUser = this.settings.user;
this.settings = this.getDefaultSettings();
this.settings.user = currentUser;
this.saveSettings();
this.notifyListeners();
}
subscribe(callback) {
this.listeners.add(callback);
return () => {
this.listeners.delete(callback);
};
}
authenticateUser(username, password) {
const users = {
'admin': { password: 'admin123', role: 'admin', permissions: ['view', 'modify_settings', 'admin'] },
'user': { password: 'user123', role: 'user', permissions: ['view', 'modify_settings'] },
'guest': { password: '', role: 'guest', permissions: ['view'] }
};
const user = users[username];
if (user && (user.password === password || username === 'guest')) {
this.settings.user = {
role: user.role,
permissions: user.permissions,
sessionTimeout: 3600000,
lastLoginTime: Date.now()
};
this.saveSession();
this.saveSettings();
return true;
}
return false;
}
logout() {
this.settings.user = {
role: 'guest',
permissions: ['view'],
sessionTimeout: 3600000,
lastLoginTime: Date.now()
};
this.clearSession();
this.saveSettings();
this.notifyListeners();
}
hasPermission(permission) {
return this.settings.user.permissions.includes(permission);
}
getCurrentRole() {
return this.settings.user.role;
}
validateSession() {
const now = Date.now();
const sessionAge = now - this.settings.user.lastLoginTime;
if (sessionAge > this.settings.user.sessionTimeout) {
this.logout();
}
}
notifyListeners() {
this.listeners.forEach(callback => {
try {
callback(this.getSettings());
}
catch (error) {
console.error('Error in settings listener:', error);
}
});
}
loadSettings() {
try {
const saved = localStorage.getItem(this.STORAGE_KEY);
if (saved) {
const parsed = JSON.parse(saved);
this.settings = this.mergeDeep(this.getDefaultSettings(), parsed);
}
}
catch (error) {
console.warn('Failed to load settings from localStorage:', error);
this.settings = this.getDefaultSettings();
}
}
saveSettings() {
try {
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(this.settings));
}
catch (error) {
console.error('Failed to save settings to localStorage:', error);
}
}
saveSession() {
try {
const sessionData = {
role: this.settings.user.role,
lastLoginTime: this.settings.user.lastLoginTime
};
localStorage.setItem(this.SESSION_KEY, JSON.stringify(sessionData));
}
catch (error) {
console.error('Failed to save session:', error);
}
}
clearSession() {
try {
localStorage.removeItem(this.SESSION_KEY);
}
catch (error) {
console.error('Failed to clear session:', error);
}
}
mergeDeep(target, source) {
const result = { ...target };
for (const key in source) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
result[key] = this.mergeDeep(result[key] || {}, source[key]);
}
else {
result[key] = source[key];
}
}
return result;
}
get hideDisabledNavButtons() {
return this.settings.ui.hideDisabledNavButtons;
}
get autoAdvanceQuestions() {
return this.settings.ui.autoAdvanceQuestions;
}
get enableAnimations() {
return this.settings.ui.enableAnimations;
}
get defaultViewMode() {
return this.settings.ui.defaultViewMode;
}
get showContinueButton() {
return this.settings.ui.showContinueButton;
}
get announceSelections() {
return this.settings.ui.announceSelections;
}
get selectionFeedbackDuration() {
return this.settings.ui.selectionFeedbackDuration;
}
get theme() {
return this.settings.ui.theme;
}
get isTimerEnabled() {
return this.settings.quiz.timerEnabled;
}
}
//# sourceMappingURL=SettingsService-complex.js.map