Fix quota endpoint: path detection, error handling, better messages
- Backend: detect the actual filesystem mountpoint via 'df' instead of hardcoding /srv/samba — setquota needs the mountpoint, not a subpath - Backend: catch CalledProcessError and FileNotFoundError from setquota and return the actual error message (e.g. quota not enabled, package not installed) instead of crashing with 500 - Frontend: always send the share path in the quota API call so the backend can find the right filesystem, even for SMB per-user quotas - Frontend: read the actual error message from the response and show it in the toast instead of just "N quota(s) failed" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
74737568b0
commit
6631b9e832
2 files changed
+36
-15
No files matched your search
@@ -417,14 +417,23 @@ def toggle_nfs():
|
||||
|
||||
# ===== QUOTA =====
|
||||
|
||||
def _find_mountpoint(path):
|
||||
"""Return the filesystem mountpoint that contains path."""
|
||||
r = subprocess.run(
|
||||
['df', '--output=target', path],
|
||||
capture_output=True, text=True,
|
||||
)
|
||||
lines = [l.strip() for l in r.stdout.strip().splitlines() if l.strip() and l.strip() != 'Mounted on']
|
||||
return lines[0] if lines else '/srv'
|
||||
|
||||
|
||||
@app.route('/api/quota', methods=['POST'])
|
||||
@require_auth
|
||||
def set_quota():
|
||||
data = request.json or {}
|
||||
user = data.get('user', '')
|
||||
quota_type = data.get('type', 'smb')
|
||||
raw_quota = data.get('quota', 0)
|
||||
path = data.get('path', '/srv/samba')
|
||||
path = data.get('path', '/srv')
|
||||
|
||||
if not VALID_NAME.match(user):
|
||||
return jsonify({'error': 'invalid username'}), 400
|
||||
@@ -435,17 +444,23 @@ def set_quota():
|
||||
except (ValueError, TypeError):
|
||||
return jsonify({'error': 'quota must be a positive integer (GB)'}), 400
|
||||
|
||||
if quota_type == 'smb':
|
||||
mount = '/srv/samba'
|
||||
else:
|
||||
try:
|
||||
mount = validate_path(path)
|
||||
except ValueError as e:
|
||||
return jsonify({'error': str(e)}), 400
|
||||
try:
|
||||
safe_path = validate_path(path)
|
||||
except ValueError as e:
|
||||
return jsonify({'error': str(e)}), 400
|
||||
|
||||
mount = _find_mountpoint(safe_path)
|
||||
soft_kb = str(quota_gb * 1024 * 1024)
|
||||
hard_kb = str((quota_gb + 1) * 1024 * 1024)
|
||||
subprocess.run(['setquota', '-u', user, soft_kb, hard_kb, '0', '0', mount], check=True)
|
||||
try:
|
||||
r = subprocess.run(
|
||||
['setquota', '-u', user, soft_kb, hard_kb, '0', '0', mount],
|
||||
capture_output=True, text=True,
|
||||
)
|
||||
if r.returncode != 0:
|
||||
return jsonify({'error': r.stderr.strip() or 'setquota failed'}), 500
|
||||
except FileNotFoundError:
|
||||
return jsonify({'error': 'setquota not found — install quota package'}), 500
|
||||
return jsonify({'status': 'ok'})
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user