Remove user rename feature; add www-data hint in WebDAV edit modal

- Removed PATCH /api/users/<name> route (rename_user)
- Removed renameModal from index.html
- Removed openRenameModal/submitRename from users.js
- Removed Rename button from users table
- Removed rename docs from README
- Added green info box in WebDAV edit modal: set group=www-data, mode=775

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Sonnet 4.6 committed 2026-06-20 17:01:56 +02:00
1 parent f081496b4b
commit b6179865b5
5 files changed
+5 -70

No files matched your search

-2
View File
@@ -111,8 +111,6 @@ All routes require a login session. On first run you are redirected to `/setup`
Users created in MicroNAS are standard Linux system accounts (`useradd -M -s /usr/sbin/nologin`). Their password is set in both the Linux shadow file (via `smbpasswd`) and the WebDAV htpasswd file automatically.
**Rename** — the Rename button in the Users tab renames the Linux account (`usermod -l`). Because SMB and WebDAV store passwords by username, those entries are removed and must be reset after a rename. The UI shows a warning prompt.
**Delete** — removes the Linux account, SMB entry, and WebDAV htpasswd entry.
**Password change** — updates SMB and WebDAV passwords in sync. Changing a user's password also re-registers them in WebDAV if they were created before WebDAV was installed.
-21
View File
@@ -936,27 +936,6 @@ def change_admin_credentials():
return jsonify({'status': 'updated'})
@app.route('/api/users/<name>', methods=['PATCH'])
@require_auth
def rename_user(name):
if not VALID_NAME.match(name):
return jsonify({'error': 'invalid username'}), 400
new_name = (request.json or {}).get('name', '').strip()
if not new_name or not VALID_NAME.match(new_name):
return jsonify({'error': 'invalid new username'}), 400
if new_name == name:
return jsonify({'status': 'no change'}), 200
r = subprocess.run(['usermod', '-l', new_name, name], capture_output=True, text=True)
if r.returncode != 0:
return jsonify({'error': r.stderr.strip() or 'usermod failed'}), 500
# Remove SMB and WebDAV entries — password must be reset after rename
subprocess.run(['smbpasswd', '-x', name], capture_output=True)
_remove_webdav_user(name)
return jsonify({'status': 'renamed',
'warning': 'SMB and WebDAV password must be reset for the renamed user.'})
@app.route('/api/users/<name>/password', methods=['POST'])
@require_auth
+5
View File
@@ -259,6 +259,11 @@ async function openEditModal(type, share) {
</label>
<input type="text" id="editWebdavUsers" class="form-control" value="${esc(share.users || '')}">
</div>
<div class="mb-3 px-2 py-2 rounded" style="background:#1a2a1a; border:1px solid #2d4a2d; font-size:.82rem; color:#8dba8d">
WebDAV writes files as <code style="color:#3fb950">www-data</code>.
Set the folder group to <code style="color:#3fb950">www-data</code> and mode to <code style="color:#3fb950">775</code> below,
or add <code style="color:#3fb950">www-data</code> to your share group.
</div>
${permSection}`;
} else {
const isRo = /\(ro[,)]/.test(share.clients);
-26
View File
@@ -22,8 +22,6 @@ async function loadUsers() {
</span>
</td>
<td>
<button class="btn btn-sm me-1" style="border:1px solid var(--border); color:var(--muted)"
onclick="openRenameModal(${nameJson})">Rename</button>
<button class="btn btn-sm me-1" style="border:1px solid var(--border); color:var(--muted)"
onclick="openPwModal(${nameJson})">Password</button>
<button class="btn btn-sm btn-danger"
@@ -97,30 +95,6 @@ async function submitPassword() {
showToast(`Password updated for "${name}".`);
}
function openRenameModal(name) {
document.getElementById('renameOldName').value = name;
document.getElementById('renameNewName').value = name;
new bootstrap.Modal(document.getElementById('renameModal')).show();
}
async function submitRename() {
const oldName = document.getElementById('renameOldName').value;
const newName = document.getElementById('renameNewName').value.trim();
if (!newName) return showToast('New username is required.', 'danger');
const res = await apiFetch(`/api/users/${encodeURIComponent(oldName)}`, {
method: 'PATCH', headers: {'Content-Type': 'application/json'},
body: JSON.stringify({name: newName}),
});
if (!res) return;
const data = await res.json();
bootstrap.Modal.getInstance(document.getElementById('renameModal')).hide();
if (!res.ok) return showToast('Error: ' + (data.error || res.status), 'danger');
if (data.warning) showToast(data.warning, 'warning');
else showToast(`Renamed to "${newName}".`);
loadUsers();
loadGroups();
}
function openAdminSettings() {
document.getElementById('adminCurrentPw').value = '';
-21
View File
@@ -102,27 +102,6 @@
</div>
</div>
<!-- Rename user modal -->
<div class="modal fade" id="renameModal" tabindex="-1">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Rename User</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<input type="hidden" id="renameOldName">
<label class="form-label" style="color:var(--muted); font-size:.85rem">New Username</label>
<input type="text" id="renameNewName" class="form-control mb-2">
<div class="small" style="color:var(--yellow)">SMB and WebDAV password must be reset after rename.</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary btn-sm" onclick="submitRename()">Rename</button>
</div>
</div>
</div>
</div>
<!-- Header -->
<div class="topbar d-flex justify-content-between align-items-center">