feat: User-Berechtigungen für Agent-Erstellung und CLI-Nutzung

- Neue Felder CanCreateAgents und CanUseCli im UserRecord (Default: true)
- DB-Migration mit Abwärtskompatibilität (bestehende User behalten alle Rechte)
- Admin-UI: Checkboxen für beide Berechtigungen pro User
- AgentEndpoint: Prüfung auf CanCreateAgents beim Erstellen
- ChatEndpoint: CLI-Fallback nur wenn CanUseCli erlaubt
- Frontend: Neuer-Agent-Button und Agent-Page bei fehlender Berechtigung gesperrt
- Chat: Proaktive Warnung wenn kein API-Key und keine CLI-Berechtigung
- Bug Fix: is_public fehlte im Agent-INSERT (Public Agents erst nach erneutem Speichern sichtbar)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MelekiandClaude Opus 4.6 committed 2026-03-22 18:47:56 +01:00
1 parent 500c00f948
commit f03fbd298e
13 files changed
+100 -16

No files matched your search

+16 -2
View File
@@ -21,6 +21,8 @@ registerPage('admin', {
var defaultPathInput = document.getElementById('adminDefaultPath');
var defaultPathBrowse = document.getElementById('adminDefaultPathBrowse');
var isAdminCheckbox = document.getElementById('adminIsAdmin');
var canCreateAgentsCheckbox = document.getElementById('adminCanCreateAgents');
var canUseCliCheckbox = document.getElementById('adminCanUseCli');
var saveBtn = document.getElementById('adminFormSaveBtn');
function renderUsers() {
@@ -42,6 +44,10 @@ registerPage('admin', {
var metaParts = ['@' + user.username];
if (user.isAdmin) metaParts.push('Administrator');
if (user.defaultPath) metaParts.push(user.defaultPath);
var perms = [];
if (user.canCreateAgents === false) perms.push('keine Agents');
if (user.canUseCli === false) perms.push('keine CLI');
if (perms.length) metaParts.push(perms.join(', '));
metaSpan.textContent = metaParts.join(' · ');
info.appendChild(nameSpan);
@@ -107,6 +113,8 @@ registerPage('admin', {
passwordInput.required = false;
defaultPathInput.value = user.defaultPath || '';
isAdminCheckbox.checked = user.isAdmin;
canCreateAgentsCheckbox.checked = user.canCreateAgents !== false;
canUseCliCheckbox.checked = user.canUseCli !== false;
saveBtn.textContent = 'Speichern';
userForm.hidden = false;
usernameInput.focus();
@@ -199,6 +207,8 @@ registerPage('admin', {
passwordInput.required = true;
defaultPathInput.value = '';
isAdminCheckbox.checked = false;
canCreateAgentsCheckbox.checked = true;
canUseCliCheckbox.checked = true;
saveBtn.textContent = 'Erstellen';
userForm.hidden = false;
usernameInput.focus();
@@ -212,7 +222,9 @@ registerPage('admin', {
username: usernameInput.value.trim(),
displayName: displayNameInput.value.trim(),
defaultPath: defaultPathInput.value.trim() || null,
isAdmin: isAdminCheckbox.checked
isAdmin: isAdminCheckbox.checked,
canCreateAgents: canCreateAgentsCheckbox.checked,
canUseCli: canUseCliCheckbox.checked
};
await apiAdminUpdateUser(editingUserId, data);
@@ -234,7 +246,9 @@ registerPage('admin', {
password: password,
displayName: displayNameInput.value.trim(),
defaultPath: defaultPathInput.value.trim() || null,
isAdmin: isAdminCheckbox.checked
isAdmin: isAdminCheckbox.checked,
canCreateAgents: canCreateAgentsCheckbox.checked,
canUseCli: canUseCliCheckbox.checked
});
showToast('Benutzer erstellt');
+5
View File
@@ -9,6 +9,11 @@ registerPage('agent', {
const isNew = !agentId;
let agent = null;
if (isNew && currentUser && currentUser.canCreateAgents === false && !currentUser.isAdmin) {
showToast('Keine Berechtigung zum Erstellen von Agents', 'error');
return navigateTo('dashboard');
}
if (!isNew) {
agent = await apiGetAgent(agentId);
if (!agent) return navigateTo('dashboard');
+13
View File
@@ -82,6 +82,16 @@ async function _initChatUsageBadge() {
}
}
async function _checkChatPermissions() {
if (!currentUser || currentUser.isAdmin) return;
if (currentUser.canUseCli !== false) return; // CLI erlaubt → kein Problem
try {
var selectedKey = await apiGetSelectedKey(getCurrentAgentId());
if (selectedKey && selectedKey.selected) return; // Key vorhanden → kein Problem
addWarningBubble('Kein API-Key zugewiesen und keine CLI-Berechtigung. Nachrichten können nicht verarbeitet werden. Bitte wende dich an einen Admin.');
} catch(e) { /* ignore */ }
}
async function _refreshChatUsageBadge() {
if (!currentUser) return;
var container = document.getElementById('chatUsageBadge');
@@ -619,6 +629,9 @@ registerPage('chat', {
// Usage Badge laden (Admin only)
_initChatUsageBadge();
// Warnung anzeigen wenn kein Key und keine CLI-Berechtigung
_checkChatPermissions();
// Nach Font-Loading nochmal scrollen (Schriftart kann Höhe verändern)
document.fonts.ready.then(() => {
requestAnimationFrame(() => scrollDown());
+7 -2
View File
@@ -149,8 +149,13 @@ registerPage('dashboard', {
agentGrid.appendChild(card);
}
// Neuer Agent Button
document.getElementById('newAgentBtn').addEventListener('click', () => navigateTo('agent'));
// Neuer Agent Button (nur wenn Berechtigung vorhanden)
var newAgentBtn = document.getElementById('newAgentBtn');
if (currentUser && currentUser.canCreateAgents === false && !currentUser.isAdmin) {
newAgentBtn.hidden = true;
} else {
newAgentBtn.addEventListener('click', () => navigateTo('agent'));
}
// Cronjobs
const cronjobGrid = document.getElementById('cronjobCards');