Admin:
- POST /api/admin/users/{userId}/impersonate – erstellt Token für Zieluser
- Login-as-Button (fa-sign-in) in User-Liste (nicht für sich selbst)
- confirm-Dialog, danach location.reload() mit neuem User-Kontext
- Default-Path Feld + Browse-Button im Admin-Formular
Default-Path:
- Neues Feld default_path in users-Tabelle (TryAddColumn Migration)
- UserRecord.DefaultPath Property
- In allen Endpoints: Admin CRUD, Auth /me, Profile Get/Update
- Profil-Seite: Default-Path Feld + Browse-Button
- Session-Seite: Workspace-Browse nutzt defaultPath als Fallback
150 lines
5.1 KiB
JavaScript
150 lines
5.1 KiB
JavaScript
// ── Profile Page ──
|
||
|
||
var _profileMde = null;
|
||
|
||
registerPage('profile', {
|
||
async init() {
|
||
var profile = await apiGetProfile();
|
||
if (!profile) return;
|
||
|
||
var usernameInput = document.getElementById('profileUsername');
|
||
var displayNameInput = document.getElementById('profileDisplayName');
|
||
var defaultPathInput = document.getElementById('profileDefaultPath');
|
||
var defaultPathBrowse = document.getElementById('profileDefaultPathBrowse');
|
||
var personaInput = document.getElementById('profilePersona');
|
||
var saveBtn = document.getElementById('profileSaveBtn');
|
||
var messageDiv = document.getElementById('profileMessage');
|
||
|
||
// EasyMDE für Persona
|
||
_profileMde = new EasyMDE({
|
||
element: personaInput,
|
||
initialValue: profile.persona || '',
|
||
toolbar: ['bold', 'italic', 'heading', '|', 'unordered-list', 'ordered-list', '|', 'link', 'code', '|', 'preview'],
|
||
status: false,
|
||
spellChecker: false,
|
||
autoDownloadFontAwesome: false,
|
||
minHeight: '150px',
|
||
placeholder: 'Beschreibe dich selbst – Name, Rolle, Präferenzen, Kommunikationsstil...',
|
||
previewClass: ['editor-preview', 'markdown']
|
||
});
|
||
_profileMde.codemirror.setOption('theme', 'default');
|
||
_profileMde.codemirror.getWrapperElement().closest('.EasyMDEContainer').classList.add('fe-mde-wrap');
|
||
|
||
var currentPwInput = document.getElementById('profileCurrentPassword');
|
||
var newPwInput = document.getElementById('profileNewPassword');
|
||
var confirmPwInput = document.getElementById('profileConfirmPassword');
|
||
var passwordBtn = document.getElementById('profilePasswordBtn');
|
||
var passwordMessageDiv = document.getElementById('profilePasswordMessage');
|
||
|
||
var logoutBtn = document.getElementById('profileLogoutBtn');
|
||
|
||
// Felder befüllen
|
||
usernameInput.value = profile.username || '';
|
||
displayNameInput.value = profile.displayName || '';
|
||
defaultPathInput.value = profile.defaultPath || '';
|
||
|
||
// Default Path Browse
|
||
if (defaultPathBrowse) {
|
||
defaultPathBrowse.addEventListener('click', function() {
|
||
openFolderBrowser({
|
||
startPath: defaultPathInput.value.trim() || '/',
|
||
onSelect: function(path) {
|
||
defaultPathInput.value = path;
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
// Profil speichern
|
||
saveBtn.addEventListener('click', async function() {
|
||
saveBtn.disabled = true;
|
||
saveBtn.textContent = 'Speichern...';
|
||
messageDiv.hidden = true;
|
||
|
||
try {
|
||
var updated = await apiUpdateProfile({
|
||
displayName: displayNameInput.value.trim(),
|
||
defaultPath: defaultPathInput.value.trim() || null,
|
||
persona: _profileMde.value().trim()
|
||
});
|
||
|
||
// currentUser aktualisieren
|
||
if (currentUser) {
|
||
currentUser.displayName = updated.displayName;
|
||
}
|
||
|
||
messageDiv.textContent = 'Profil gespeichert';
|
||
messageDiv.className = 'profile-message profile-message-success';
|
||
messageDiv.hidden = false;
|
||
setTimeout(function() { messageDiv.hidden = true; }, 3000);
|
||
} catch (err) {
|
||
messageDiv.textContent = err.message;
|
||
messageDiv.className = 'profile-message profile-message-error';
|
||
messageDiv.hidden = false;
|
||
} finally {
|
||
saveBtn.disabled = false;
|
||
saveBtn.textContent = 'Speichern';
|
||
}
|
||
});
|
||
|
||
// Passwort ändern
|
||
passwordBtn.addEventListener('click', async function() {
|
||
passwordMessageDiv.hidden = true;
|
||
|
||
var currentPw = currentPwInput.value;
|
||
var newPw = newPwInput.value;
|
||
var confirmPw = confirmPwInput.value;
|
||
|
||
if (!currentPw || !newPw) {
|
||
passwordMessageDiv.textContent = 'Alle Felder ausfüllen';
|
||
passwordMessageDiv.className = 'profile-message profile-message-error';
|
||
passwordMessageDiv.hidden = false;
|
||
return;
|
||
}
|
||
|
||
if (newPw !== confirmPw) {
|
||
passwordMessageDiv.textContent = 'Neue Passwörter stimmen nicht überein';
|
||
passwordMessageDiv.className = 'profile-message profile-message-error';
|
||
passwordMessageDiv.hidden = false;
|
||
return;
|
||
}
|
||
|
||
passwordBtn.disabled = true;
|
||
passwordBtn.textContent = 'Ändern...';
|
||
|
||
try {
|
||
await apiChangePassword(currentPw, newPw);
|
||
|
||
currentPwInput.value = '';
|
||
newPwInput.value = '';
|
||
confirmPwInput.value = '';
|
||
|
||
passwordMessageDiv.textContent = 'Passwort geändert';
|
||
passwordMessageDiv.className = 'profile-message profile-message-success';
|
||
passwordMessageDiv.hidden = false;
|
||
setTimeout(function() { passwordMessageDiv.hidden = true; }, 3000);
|
||
} catch (err) {
|
||
passwordMessageDiv.textContent = err.message;
|
||
passwordMessageDiv.className = 'profile-message profile-message-error';
|
||
passwordMessageDiv.hidden = false;
|
||
} finally {
|
||
passwordBtn.disabled = false;
|
||
passwordBtn.textContent = 'Passwort ändern';
|
||
}
|
||
});
|
||
|
||
// Logout
|
||
logoutBtn.addEventListener('click', async function() {
|
||
await apiLogout();
|
||
currentUser = null;
|
||
navigateTo('login');
|
||
});
|
||
},
|
||
destroy() {
|
||
if (_profileMde) {
|
||
_profileMde.toTextArea();
|
||
_profileMde = null;
|
||
}
|
||
}
|
||
});
|