From 3bd086ab0eda9d097bc9b0110335c43e9db0defb Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 25 Sep 2026 17:17:41 +0000 Subject: [PATCH] Say accounts cannot be created before the form is filled in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running without GITEA_ADMIN_TOKEN is the safer configuration and is documented as such, but the member form did not know: it offered "Crear también su cuenta" ticked by default and reported "Falta GITEA_ADMIN_TOKEN" only on submit, after three fields had been filled in. That is the shape of failure this project has lost the most time to — something that cannot happen, going unsaid until someone has relied on it. The form now reads the config when it renders and says so, with a link to Gitea's create-user page. The checkbox is disabled rather than hidden, because "you cannot do this here" is more use than an option that quietly is not there. The refusal itself stays in the handler: a disabled input is a courtesy, and a hand-crafted POST still meets the same error. Verified: 104 checks. The form states the limit with no token and is unchanged with one, and submitting create_account anyway still creates no member. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NizVpJ2dwzCbjCrTLCjeHn --- apps/board/members.py | 13 ++++++++-- apps/board/templates/member_new.html | 15 +++++++++++ apps/board/tests/test_members.py | 37 ++++++++++++++++++++++++++++ docs/server-setup.md | 5 ++++ 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/apps/board/members.py b/apps/board/members.py index 9406a1f..3a6876d 100644 --- a/apps/board/members.py +++ b/apps/board/members.py @@ -18,7 +18,7 @@ import json import re import sqlite3 -from flask import (Blueprint, Response, abort, flash, g, redirect, +from flask import (Blueprint, Response, abort, current_app, flash, g, redirect, render_template, request, url_for) from . import gitea @@ -121,7 +121,16 @@ def index(): @admin_required def new(): if request.method == "GET": - return render_template("member_new.html", can_make_admin=g.member["role"] == "owner") + return render_template( + "member_new.html", + can_make_admin=g.member["role"] == "owner", + # Without a site-admin token the server cannot create Gitea accounts, + # which is the documented safer configuration rather than a fault. + # The form says so before it is filled in; offering a ticked checkbox + # and reporting the problem on submit wastes the work of filling it. + can_create_accounts=bool(current_app.config.get("ADMIN_TOKEN")), + gitea_url=current_app.config["GITEA_URL"].rstrip("/"), + ) login = request.form.get("login", "").strip() display_name = request.form.get("display_name", "").strip() diff --git a/apps/board/templates/member_new.html b/apps/board/templates/member_new.html index 60e22c8..e9ed03d 100644 --- a/apps/board/templates/member_new.html +++ b/apps/board/templates/member_new.html @@ -17,10 +17,25 @@ + {% if can_create_accounts %} + {% else %} + {# Disabled rather than hidden: "you cannot do this here" is more use than + an option that quietly is not there. The handler refuses it either way. #} + +

+ Este servidor no puede crear cuentas (no tiene un token de administración + de Gitea). Crea la cuenta primero en + Gitea y luego da de alta + aquí ese mismo usuario. +

+ {% endif %} {% if can_make_admin %} diff --git a/apps/board/tests/test_members.py b/apps/board/tests/test_members.py index cb12958..d488f99 100644 --- a/apps/board/tests/test_members.py +++ b/apps/board/tests/test_members.py @@ -182,3 +182,40 @@ def test_the_export_is_only_your_own_writing(client, db, make_member, sign_in): body = client.get("/comunidad/mis-datos").get_data(as_text=True) assert "Mío" in body assert "Suyo" not in body + + +def test_the_form_says_so_when_accounts_cannot_be_created(app, client, owner_id, sign_in): + """Without a site-admin token the server cannot create Gitea accounts. That + is the documented safer setup, not a fault — but it has to be said before + someone fills the form, not after they submit it.""" + app.config["ADMIN_TOKEN"] = "" + sign_in(owner_id) + + body = client.get("/comunidad/miembros/nuevo").get_data(as_text=True) + assert "no puede crear cuentas" in body + assert 'name="create_account" disabled' in body + assert 'name="create_account" checked' not in body + + +def test_with_a_token_the_form_is_unchanged(app, client, owner_id, sign_in): + app.config["ADMIN_TOKEN"] = "admintoken" + sign_in(owner_id) + + body = client.get("/comunidad/miembros/nuevo").get_data(as_text=True) + assert 'name="create_account" checked' in body + assert "no puede crear cuentas" not in body + + +def test_ticking_it_anyway_still_creates_nothing(app, client, db, post, owner_id, sign_in): + """A disabled input is a courtesy, not a permission — the refusal lives in + the handler, where a hand-crafted POST also meets it.""" + app.config["ADMIN_TOKEN"] = "" + sign_in(owner_id) + + response = post("/comunidad/miembros/nuevo", { + "login": "maria", "display_name": "María", "email": "m@example.com", + "role": "user", "create_account": "on", + }, follow_redirects=True) + + assert "GITEA_ADMIN_TOKEN" in response.get_data(as_text=True) + assert db.execute("SELECT 1 FROM members WHERE gitea_login = 'maria'").fetchone() is None diff --git a/docs/server-setup.md b/docs/server-setup.md index fae2d64..5ad53e8 100644 --- a/docs/server-setup.md +++ b/docs/server-setup.md @@ -346,6 +346,11 @@ board's environment — the compose file, `docker inspect`, a shell in the container — can use it. If you would rather not have that on the box, leave `GITEA_ADMIN_TOKEN` empty and create accounts in Gitea by hand. +Leaving it empty is a supported configuration, not a half-finished one: the +*Dar de alta* form checks for the token when it renders, says plainly that this +server cannot create accounts, and links to Gitea's own create-user page. You +then add that username here, with the checkbox already off. + ### 11.3 Build and run ```sh