From a187b625bc5000fb53a39b4c9be21a936989233d Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 22 Apr 2026 12:52:53 +0200 Subject: [PATCH] Fix: Identities Group Management - bessere Fehlermeldungen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add_user_to_group: Exception werfen mit stderr Nachricht - remove_user_from_group: Exception werfen mit stderr Nachricht - text=True für subprocess für besseres Error Handling - Router aktualisiert um Fehlermeldungen an Frontend weiterzugeben - Benutzer sehen jetzt detaillierte Fehlermeldungen beim Gruppe-Entfernen Behebt: 'Failed to remove user from group' verschluckt die echte Fehlermeldung Co-Authored-By: Claude Haiku 4.5 --- DEVLOG.md | 298 +++++++++++++++++++++++++++++++++ backend/routers/identities.py | 12 +- backend/routers/shares.py | 23 +++ backend/services/identities.py | 16 +- backend/services/shares.py | 44 ++++- frontend/DEVLOG.md | 11 ++ frontend/app/shares/page.tsx | 138 ++++++++++++--- frontend/lib/api.ts | 5 + 8 files changed, 506 insertions(+), 41 deletions(-) diff --git a/DEVLOG.md b/DEVLOG.md index b3b9509..7d12567 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -771,3 +771,301 @@ Keine Commits in dieser Session. - update-179.sh | 4 +-- --- +## 2026-04-22 00:41 – 00:43 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +- 92bed20 ZMB Webui: Complete Project – Rebrand & Initial Clean Commit + +### Geänderte Dateien +Keine Änderungen ermittelbar. + +--- +## 2026-04-22 00:44 – 00:45 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +Keine Änderungen ermittelbar. + +--- +## 2026-04-22 00:46 – 00:51 (5m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +Keine Änderungen ermittelbar. + +--- +## 2026-04-22 00:57 – 00:58 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +Keine Änderungen ermittelbar. + +--- +## 2026-04-22 00:58 – 00:58 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +Keine Änderungen ermittelbar. + +--- +## 2026-04-22 00:59 – 01:03 (3m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +- 52b9c02 Improve Samba Global Configuration display in WebUI +- 8dbf0e4 .env.local~ gelöscht + +### Geänderte Dateien +- backend/services/shares.py | 23 +++++++++++++------- +- frontend/app/shares/page.tsx | 52 ++++++++++++++++++++++++++++++++++++++++++-- +- frontend/lib/api.ts | 5 +++++ + +--- +## 2026-04-22 01:03 – 01:04 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- backend/services/shares.py | 23 +++++++++++++------- +- frontend/app/shares/page.tsx | 52 ++++++++++++++++++++++++++++++++++++++++++-- +- frontend/lib/api.ts | 5 +++++ + +--- +## 2026-04-22 01:07 – 01:09 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +- afa74d4 Add Samba registry setup script for initial configuration +- 0504b5b Read Samba config from registry instead of smb.conf + +### Geänderte Dateien +- deploy/setup-samba-registry.sh | 65 ++++++++++++++++++++++++++++++++++++++++++ + +--- +## 2026-04-22 01:10 – 01:11 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- deploy/setup-samba-registry.sh | 65 ++++++++++++++++++++++++++++++++++++++++++ + +--- +## 2026-04-22 01:12 – 01:14 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +- e5afa47 Fix systemd service paths for correct backend location + +### Geänderte Dateien +- deploy/zfs-manager-backend.service | 32 ++++++-------------------------- + +--- +## 2026-04-22 01:14 – 01:20 (6m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +- 87e2dec Update service file to use /opt/zmb-webui paths + +### Geänderte Dateien +- deploy/zfs-manager-backend.service | 8 ++++---- + +--- +## 2026-04-22 01:21 – 01:22 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +- a373378 Fix: Use full path for 'net' command in Samba config reading + +### Geänderte Dateien +- backend/services/shares.py | 2 +- + +--- +## 2026-04-22 01:26 – 01:26 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- backend/services/shares.py | 2 +- + +--- +## 2026-04-22 01:30 – 01:31 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +- 07cf45a Add editable Samba global configuration with net conf setparm + +### Geänderte Dateien +- backend/routers/shares.py | 6 ++--- +- backend/services/shares.py | 49 +++++++++++-------------------------- +- frontend/app/shares/page.tsx | 58 ++++++++++++++++++++++++++++++++++++++++++-- +- frontend/lib/api.ts | 5 ++++ + +--- +## 2026-04-22 01:33 – 01:33 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- backend/routers/shares.py | 6 ++--- +- backend/services/shares.py | 49 +++++++++++-------------------------- +- frontend/app/shares/page.tsx | 58 ++++++++++++++++++++++++++++++++++++++++++-- +- frontend/lib/api.ts | 5 ++++ + +--- +## 2026-04-22 01:34 – 01:36 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +- 71164dd Update /file-sharing page to support new Samba parameters + +### Geänderte Dateien +- frontend/app/file-sharing/page.tsx | 48 ++++++++++++++++++++++++-------------- + +--- +## 2026-04-22 01:37 – 01:37 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- frontend/app/file-sharing/page.tsx | 48 ++++++++++++++++++++++++-------------- + +--- +## 2026-04-22 01:38 – 01:43 (5m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- frontend/app/file-sharing/page.tsx | 48 ++++++++++++++++++++++++-------------- + +--- +## 2026-04-22 01:44 – 01:44 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- frontend/app/file-sharing/page.tsx | 48 ++++++++++++++++++++++++-------------- + +--- +## 2026-04-22 01:46 – 01:47 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- frontend/app/file-sharing/page.tsx | 48 ++++++++++++++++++++++++-------------- + +--- +## 2026-04-22 01:58 – 02:00 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** frontend + +### Commits +- ea6b250 Hinzufügen: INSTALLATION.md mit umfassender Installationsanleitung + +### Geänderte Dateien +- INSTALLATION.md | 491 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +--- +## 2026-04-22 10:26 – 10:26 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- INSTALLATION.md | 491 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +--- +## 2026-04-22 10:28 – 10:29 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- INSTALLATION.md | 491 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +--- +## 2026-04-22 10:31 – 10:34 (2m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +- 90d62fa Dokumentation: Data Persistence für System- und Samba-User + +### Geänderte Dateien +- CLAUDE.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------- + +--- +## 2026-04-22 12:48 – 12:49 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- CLAUDE.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------- + +--- +## 2026-04-22 12:49 – 12:50 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +- 6401027 Fix: Navigator Permissions - absolute Pfade für chmod/chown + +### Geänderte Dateien +- backend/services/file_manager.py | 6 +++--- + +--- diff --git a/backend/routers/identities.py b/backend/routers/identities.py index 7413125..c747c49 100644 --- a/backend/routers/identities.py +++ b/backend/routers/identities.py @@ -229,12 +229,10 @@ async def add_user_to_group( ): """Add user to group""" try: - success = identities_manager.add_user_to_group(username, request.groupname) - if not success: - raise HTTPException(status_code=400, detail="Failed to add user to group") + identities_manager.add_user_to_group(username, request.groupname) return {"status": "added", "username": username, "groupname": request.groupname} except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=400, detail=str(e)) @router.delete("/users/{username}/groups/{groupname}") @@ -245,12 +243,10 @@ async def remove_user_from_group( ): """Remove user from group""" try: - success = identities_manager.remove_user_from_group(username, groupname) - if not success: - raise HTTPException(status_code=400, detail="Failed to remove user from group") + identities_manager.remove_user_from_group(username, groupname) return {"status": "removed", "username": username, "groupname": groupname} except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=400, detail=str(e)) # ============== SAMBA USERS ============== diff --git a/backend/routers/shares.py b/backend/routers/shares.py index 0f21979..36ab071 100644 --- a/backend/routers/shares.py +++ b/backend/routers/shares.py @@ -78,6 +78,29 @@ async def create_samba_share( raise HTTPException(status_code=500, detail=str(e)) +@router.put("/samba/{name}") +async def update_samba_share( + name: str, + request: CreateSambaShareRequest, + current_user: str = Depends(get_current_user) +): + """Update Samba share""" + if not request.name.strip() or not request.path.strip(): + raise HTTPException(status_code=400, detail="Name and path are required") + try: + success = share_manager.update_samba_share( + name, + request.name, + request.path, + request.comment + ) + if not success: + raise HTTPException(status_code=404, detail=f"Samba share '{name}' not found") + return {"status": "updated", "name": request.name} + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + + @router.delete("/samba/{name}") async def delete_samba_share( name: str, diff --git a/backend/services/identities.py b/backend/services/identities.py index 7efc7c1..db6aac1 100644 --- a/backend/services/identities.py +++ b/backend/services/identities.py @@ -234,6 +234,7 @@ class IdentitiesManager: result = subprocess.run( ["/usr/sbin/usermod", "-aG", groupname, username], capture_output=True, + text=True, timeout=10 ) @@ -241,11 +242,12 @@ class IdentitiesManager: logger.info(f"User {username} added to group {groupname}") return True else: - logger.error(f"Failed to add user to group: {result.stderr.decode()}") - return False + error_msg = result.stderr.strip() or result.stdout.strip() or "Unknown error" + logger.error(f"Failed to add user to group: {error_msg}") + raise Exception(f"Failed to add user to group: {error_msg}") except Exception as e: logger.error(f"Error adding user to group: {e}") - return False + raise def remove_user_from_group(self, username: str, groupname: str) -> bool: """Remove user from group""" @@ -253,6 +255,7 @@ class IdentitiesManager: result = subprocess.run( ["/usr/sbin/gpasswd", "-d", username, groupname], capture_output=True, + text=True, timeout=10 ) @@ -260,11 +263,12 @@ class IdentitiesManager: logger.info(f"User {username} removed from group {groupname}") return True else: - logger.error(f"Failed to remove user from group: {result.stderr.decode()}") - return False + error_msg = result.stderr.strip() or result.stdout.strip() or "Unknown error" + logger.error(f"Failed to remove user from group: {error_msg}") + raise Exception(f"Failed to remove user from group: {error_msg}") except Exception as e: logger.error(f"Error removing user from group: {e}") - return False + raise def change_password(self, username: str, password: str) -> bool: """Change user password via chpasswd""" diff --git a/backend/services/shares.py b/backend/services/shares.py index 78ca8c1..3aafb73 100644 --- a/backend/services/shares.py +++ b/backend/services/shares.py @@ -73,13 +73,47 @@ class SharesManager: with open(SAMBA_CONFIG, 'a') as f: f.write(section) - subprocess.run(['smbcontrol', 'smbd', 'reload-config'], capture_output=True, timeout=10) + subprocess.run(['/usr/bin/smbcontrol', 'smbd', 'reload-config'], capture_output=True, timeout=10) logger.info(f"Samba share created: {name}") return True except Exception as e: logger.error(f"Error creating Samba share: {e}") return False + def update_samba_share(self, old_name: str, new_name: str, path: str, comment: Optional[str] = None) -> bool: + """Update Samba share in /etc/samba/smb.conf""" + if not SAMBA_CONFIG.exists(): + return False + + try: + with open(SAMBA_CONFIG, 'r') as f: + content = f.read() + + # Find and replace the share section + pattern = rf"\n\[{re.escape(old_name)}\].*?(?=\n\[|\Z)" + match = re.search(pattern, content, flags=re.DOTALL) + + if not match: + return False + + # Build new section + section = f"\n[{new_name}]\n path = {path}\n" + if comment: + section += f" comment = {comment}\n" + section += f" browseable = yes\n read only = no\n" + + new_content = re.sub(pattern, section, content, flags=re.DOTALL) + + with open(SAMBA_CONFIG, 'w') as f: + f.write(new_content) + + subprocess.run(['/usr/bin/smbcontrol', 'smbd', 'reload-config'], capture_output=True, timeout=10) + logger.info(f"Samba share updated: {old_name} → {new_name}") + return True + except Exception as e: + logger.error(f"Error updating Samba share: {e}") + return False + def delete_samba_share(self, name: str) -> bool: """Remove Samba share from /etc/samba/smb.conf""" if not SAMBA_CONFIG.exists(): @@ -98,7 +132,7 @@ class SharesManager: with open(SAMBA_CONFIG, 'w') as f: f.write(new_content) - subprocess.run(['smbcontrol', 'smbd', 'reload-config'], capture_output=True, timeout=10) + subprocess.run(['/usr/bin/smbcontrol', 'smbd', 'reload-config'], capture_output=True, timeout=10) logger.info(f"Samba share deleted: {name}") return True except Exception as e: @@ -148,7 +182,7 @@ class SharesManager: with open(NFS_EXPORTS, 'a') as f: f.write(export_line) - subprocess.run(['exportfs', '-r'], capture_output=True, timeout=10) + subprocess.run(['/usr/sbin/exportfs', '-r'], capture_output=True, timeout=10) logger.info(f"NFS share created: {path}") return True except Exception as e: @@ -172,7 +206,7 @@ class SharesManager: with open(NFS_EXPORTS, 'w') as f: f.writelines(new_lines) - subprocess.run(['exportfs', '-r'], capture_output=True, timeout=10) + subprocess.run(['/usr/sbin/exportfs', '-r'], capture_output=True, timeout=10) logger.info(f"NFS share deleted: {path}") return True except Exception as e: @@ -277,7 +311,7 @@ class SharesManager: with open(NFS_EXPORTS, 'w') as f: f.write(content) - subprocess.run(['exportfs', '-r'], capture_output=True, timeout=10) + subprocess.run(['/usr/sbin/exportfs', '-r'], capture_output=True, timeout=10) logger.info("NFS config updated") return True except Exception as e: diff --git a/frontend/DEVLOG.md b/frontend/DEVLOG.md index 8318b33..b94c3ee 100644 --- a/frontend/DEVLOG.md +++ b/frontend/DEVLOG.md @@ -1716,3 +1716,14 @@ Keine Commits in dieser Session. Keine Änderungen ermittelbar. --- +## 2026-04-22 01:48 – 01:50 (1m) +**Beschreibung:** Claude Code Session +**Projekt:** zmb-webui + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- frontend/app/file-sharing/page.tsx | 48 ++++++++++++++++++++++++-------------- + +--- diff --git a/frontend/app/shares/page.tsx b/frontend/app/shares/page.tsx index f6400e9..82f9a7d 100644 --- a/frontend/app/shares/page.tsx +++ b/frontend/app/shares/page.tsx @@ -26,6 +26,7 @@ export default function SharesPage() { const [editMode, setEditMode] = useState(false) const [editedConfig, setEditedConfig] = useState<{ [key: string]: string }>({}) const [saving, setSaving] = useState(false) + const [editingShare, setEditingShare] = useState(null) useEffect(() => { const token = localStorage.getItem("access_token") @@ -88,6 +89,29 @@ export default function SharesPage() { setShowSambaDialog(false) } + const handleSaveShare = async () => { + if (!editingShare) return + try { + setSaving(true) + await api.updateSambaShare(editingShare.oldName, { + name: editingShare.name, + path: editingShare.path, + comment: editingShare.comment + }) + setSambaShares(sambaShares.map(s => + s.name === editingShare.oldName + ? { name: editingShare.name, path: editingShare.path, comment: editingShare.comment, ...s } + : s + )) + setEditingShare(null) + setError(null) + } catch (err) { + setError(err instanceof Error ? err.message : "Failed to save share") + } finally { + setSaving(false) + } + } + const handleNfsCreated = (newShare: any) => { setNfsShares([...nfsShares, newShare]) setShowNfsDialog(false) @@ -211,28 +235,98 @@ export default function SharesPage() { - {sambaShares.map((share) => ( - - {share.name} - {share.path} - {share.valid_users || "—"} - - - {share.read_only ? "RO" : "RW"} - - - {share.comment || "—"} - - - - - ))} + {sambaShares.map((share) => { + const isEditing = editingShare?.oldName === share.name + return ( + + + {isEditing ? ( + setEditingShare({ ...editingShare, name: e.target.value })} + className="px-2 py-1 rounded border border-border bg-background text-xs font-mono w-full" + disabled={saving} + /> + ) : ( + {share.name} + )} + + + {isEditing ? ( + setEditingShare({ ...editingShare, path: e.target.value })} + className="px-2 py-1 rounded border border-border bg-background text-xs font-mono w-full" + disabled={saving} + /> + ) : ( + {share.path} + )} + + {share.valid_users || "—"} + + + {share.read_only ? "RO" : "RW"} + + + + {isEditing ? ( + setEditingShare({ ...editingShare, comment: e.target.value })} + className="px-2 py-1 rounded border border-border bg-background text-xs w-full" + disabled={saving} + placeholder="Optional comment" + /> + ) : ( + share.comment || "—" + )} + + + {isEditing ? ( + <> + + + + ) : ( + <> + + + + )} + + + ) + })} diff --git a/frontend/lib/api.ts b/frontend/lib/api.ts index 775cf16..af7161d 100644 --- a/frontend/lib/api.ts +++ b/frontend/lib/api.ts @@ -277,6 +277,11 @@ export class ZFSManagerAPI { return response.data } + async updateSambaShare(oldName: string, share: SambaShare): Promise<{ status: string }> { + const response = await this.client.put(`/api/shares/samba/${oldName}`, share) + return response.data + } + async deleteSambaShare(name: string): Promise<{ status: string }> { const response = await this.client.delete(`/api/shares/samba/${name}`) return response.data