Make Nextcloud user and password mandatory for all sites

- NC User and NC Pass are now required fields when adding a site
- Auto-provision Nextcloud user on site creation
- Client-side validation enforces all fields in both Add and Edit forms
- Updated placeholder text to reflect required status
- Sites without NC creds now show Not set badge instead of Global

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kamaji
2026-01-26 11:01:18 -06:00
parent a719e528ed
commit 67e35c298a
2 changed files with 31 additions and 12 deletions

26
app.py
View File

@@ -981,14 +981,15 @@ def admin_dashboard():
def admin_add_site(): def admin_add_site():
"""Add a new site to sites.conf. """Add a new site to sites.conf.
JSON body: {site, pin, nc_user?, nc_pass?} JSON body: {site, pin, nc_user, nc_pass}
Site must be exactly 4 digits and must not already exist. Site must be exactly 4 digits and must not already exist.
NC User and NC Pass are required.
""" """
data = request.get_json(force=True) data = request.get_json(force=True)
site = data.get("site", "").strip() site = data.get("site", "").strip()
pin = data.get("pin", "").strip() pin = data.get("pin", "").strip()
nc_user = data.get("nc_user", "").strip() or None nc_user = data.get("nc_user", "").strip()
nc_pass = data.get("nc_pass", "").strip() or None nc_pass = data.get("nc_pass", "").strip()
if not re.fullmatch(r"\d{4}", site): if not re.fullmatch(r"\d{4}", site):
return jsonify({"ok": False, "error": "Site must be exactly 4 digits"}), 400 return jsonify({"ok": False, "error": "Site must be exactly 4 digits"}), 400
@@ -996,6 +997,12 @@ def admin_add_site():
if not pin: if not pin:
return jsonify({"ok": False, "error": "PIN is required"}), 400 return jsonify({"ok": False, "error": "PIN is required"}), 400
if not nc_user:
return jsonify({"ok": False, "error": "NC User is required"}), 400
if not nc_pass:
return jsonify({"ok": False, "error": "NC Pass is required"}), 400
# Reject characters that would corrupt sites.conf (colon is the # Reject characters that would corrupt sites.conf (colon is the
# field delimiter, newlines would inject extra lines) # field delimiter, newlines would inject extra lines)
for field_name, value in [("PIN", pin), ("NC User", nc_user), ("NC Pass", nc_pass)]: for field_name, value in [("PIN", pin), ("NC User", nc_user), ("NC Pass", nc_pass)]:
@@ -1011,7 +1018,18 @@ def admin_add_site():
sites[site] = {"pin": pin, "nc_user": nc_user, "nc_pass": nc_pass} sites[site] = {"pin": pin, "nc_user": nc_user, "nc_pass": nc_pass}
save_sites(sites) save_sites(sites)
return jsonify({"ok": True})
# Auto-provision the Nextcloud user
nc_msg = None
if all([NC_URL, NC_USER, NC_PASS]):
if nc_user_exists(nc_user):
nc_msg = f"NC user '{nc_user}' already exists"
elif nc_create_user(nc_user, nc_pass):
nc_msg = f"NC user '{nc_user}' created"
else:
nc_msg = f"Site saved, but failed to create NC user '{nc_user}'"
return jsonify({"ok": True, "nc_msg": nc_msg})
@app.route("/admin/api/sites/<site_id>", methods=["PUT"]) @app.route("/admin/api/sites/<site_id>", methods=["PUT"])

View File

@@ -302,8 +302,8 @@
<input type="text" id="add-pin" placeholder="PIN" inputmode="numeric"> <input type="text" id="add-pin" placeholder="PIN" inputmode="numeric">
</div> </div>
<div class="form-row"> <div class="form-row">
<input type="text" id="add-nc-user" placeholder="NC User (optional)"> <input type="text" id="add-nc-user" placeholder="NC User">
<input type="text" id="add-nc-pass" placeholder="NC Pass (optional)"> <input type="text" id="add-nc-pass" placeholder="NC Pass">
<button type="button" class="btn btn-outline btn-gen" onclick="document.getElementById('add-nc-pass').value = generatePassword()">Gen</button> <button type="button" class="btn btn-outline btn-gen" onclick="document.getElementById('add-nc-pass').value = generatePassword()">Gen</button>
</div> </div>
<button class="btn btn-blue" onclick="addSite()">Add Site</button> <button class="btn btn-blue" onclick="addSite()">Add Site</button>
@@ -324,7 +324,7 @@
<span class="nc-badge missing">Not found</span> <span class="nc-badge missing">Not found</span>
{% endif %} {% endif %}
{% else %} {% else %}
<span class="nc-badge global">Global</span> <span class="nc-badge missing">Not set</span>
{% endif %} {% endif %}
</div> </div>
<div class="card-actions"> <div class="card-actions">
@@ -391,8 +391,8 @@
const nc_user = document.getElementById('add-nc-user').value.trim(); const nc_user = document.getElementById('add-nc-user').value.trim();
const nc_pass = document.getElementById('add-nc-pass').value.trim(); const nc_pass = document.getElementById('add-nc-pass').value.trim();
if (!site || !pin) { if (!site || !pin || !nc_user || !nc_pass) {
showBanner('Site number and PIN are required', 'error'); showBanner('All fields are required', 'error');
return; return;
} }
@@ -404,7 +404,8 @@
}); });
const data = await resp.json(); const data = await resp.json();
if (data.ok) { if (data.ok) {
window.location.reload(); if (data.nc_msg) showBanner(data.nc_msg, 'success');
setTimeout(() => window.location.reload(), 1500);
} else { } else {
showBanner(data.error || 'Failed to add site', 'error'); showBanner(data.error || 'Failed to add site', 'error');
} }
@@ -485,8 +486,8 @@
const nc_user = document.getElementById('edit-nc-user').value.trim(); const nc_user = document.getElementById('edit-nc-user').value.trim();
const nc_pass = document.getElementById('edit-nc-pass').value.trim(); const nc_pass = document.getElementById('edit-nc-pass').value.trim();
if (!pin) { if (!pin || !nc_user || !nc_pass) {
showBanner('PIN is required', 'error'); showBanner('PIN, NC User, and NC Pass are required', 'error');
return; return;
} }