Implementierung Wissensmanagement

Dieser Commit ist enthalten in:
HG
2025-12-30 22:49:56 +00:00
committet von Server Deploy
Ursprung 9bf298c26b
Commit 395598c2b0
51 geänderte Dateien mit 7598 neuen und 32 gelöschten Zeilen

Datei anzeigen

@ -14,19 +14,23 @@ class ApiClient {
// Token Management
setToken(token) {
console.log('[API] setToken:', token ? token.substring(0, 20) + '...' : 'NULL');
this.token = token;
if (token) {
localStorage.setItem('auth_token', token);
} else {
this.token = null;
localStorage.removeItem('auth_token');
localStorage.removeItem('current_user');
}
}
getToken() {
if (!this.token) {
this.token = localStorage.getItem('auth_token');
}
return this.token;
// IMMER aus localStorage lesen um Synchronisationsprobleme zu vermeiden
// (z.B. wenn Token nach Login gesetzt wird während andere Requests laufen)
const token = localStorage.getItem('auth_token');
this.token = token; // Cache aktualisieren
return token;
}
setCsrfToken(token) {
@ -39,10 +43,10 @@ class ApiClient {
}
getCsrfToken() {
if (!this.csrfToken) {
this.csrfToken = sessionStorage.getItem('csrf_token');
}
return this.csrfToken;
// IMMER aus sessionStorage lesen um Synchronisationsprobleme zu vermeiden
const token = sessionStorage.getItem('csrf_token');
this.csrfToken = token; // Cache aktualisieren
return token;
}
// Base Request Method
@ -56,6 +60,7 @@ class ApiClient {
// Add auth token
const token = this.getToken();
console.log('[API] Request:', endpoint, 'Token:', token ? token.substring(0, 20) + '...' : 'NULL');
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
@ -98,8 +103,22 @@ class ApiClient {
// Handle 401 Unauthorized
if (response.status === 401) {
this.setToken(null);
window.dispatchEvent(new CustomEvent('auth:logout'));
// Token der für diesen Request verwendet wurde
const requestToken = token;
const currentToken = localStorage.getItem('auth_token');
console.log('[API] 401 received for:', endpoint);
console.log('[API] Request token:', requestToken ? requestToken.substring(0, 20) + '...' : 'NULL');
console.log('[API] Current token:', currentToken ? currentToken.substring(0, 20) + '...' : 'NULL');
// Nur ausloggen wenn der Token der gleiche ist (kein neuer Login in der Zwischenzeit)
if (!currentToken || currentToken === requestToken) {
console.log('[API] Token invalid, triggering logout');
this.setToken(null);
window.dispatchEvent(new CustomEvent('auth:logout'));
} else {
console.log('[API] 401 ignored - new login occurred while request was in flight');
}
throw new ApiError('Sitzung abgelaufen', 401);
}
@ -274,7 +293,9 @@ class ApiClient {
// =====================
async login(username, password) {
console.log('[API] login() called');
const response = await this.post('/auth/login', { username, password });
console.log('[API] login() response:', response ? 'OK' : 'NULL', 'token:', response?.token ? 'EXISTS' : 'MISSING');
this.setToken(response.token);
// Store CSRF token from login response
if (response.csrfToken) {
@ -977,6 +998,79 @@ class ApiClient {
xhr.send(formData);
});
}
// =====================
// KNOWLEDGE ENDPOINTS (Wissensmanagement)
// =====================
// Kategorien
async getKnowledgeCategories() {
return this.get('/knowledge/categories');
}
async createKnowledgeCategory(data) {
return this.post('/knowledge/categories', data);
}
async updateKnowledgeCategory(id, data) {
return this.put(`/knowledge/categories/${id}`, data);
}
async deleteKnowledgeCategory(id) {
return this.delete(`/knowledge/categories/${id}`);
}
async updateKnowledgeCategoryPosition(id, newPosition) {
return this.put(`/knowledge/categories/${id}/position`, { newPosition });
}
// Einträge
async getKnowledgeEntries(categoryId = null) {
const params = categoryId ? `?categoryId=${categoryId}` : '';
return this.get(`/knowledge/entries${params}`);
}
async getKnowledgeEntry(id) {
return this.get(`/knowledge/entries/${id}`);
}
async createKnowledgeEntry(data) {
return this.post('/knowledge/entries', data);
}
async updateKnowledgeEntry(id, data) {
return this.put(`/knowledge/entries/${id}`, data);
}
async deleteKnowledgeEntry(id) {
return this.delete(`/knowledge/entries/${id}`);
}
async updateKnowledgeEntryPosition(id, newPosition, newCategoryId = null) {
return this.put(`/knowledge/entries/${id}/position`, { newPosition, newCategoryId });
}
// Anhänge
async getKnowledgeAttachments(entryId) {
return this.get(`/knowledge/attachments/${entryId}`);
}
async uploadKnowledgeAttachment(entryId, file, onProgress) {
return this.uploadFile(`/knowledge/attachments/${entryId}`, file, onProgress);
}
async deleteKnowledgeAttachment(id) {
return this.delete(`/knowledge/attachments/${id}`);
}
getKnowledgeAttachmentDownloadUrl(id) {
return `${this.baseUrl}/knowledge/attachments/download/${id}`;
}
// Suche
async searchKnowledge(query) {
return this.get(`/knowledge/search?q=${encodeURIComponent(query)}`);
}
}
// Custom API Error Class