forked from yvv/decision
v3 : dixième relecture — mention « sur invitation », noms attendus protégés
- Tout auteur venu par invitation porte « sur invitation » à côté de son nom (propositions, révisions, signalements) : un nom pris avant l'arrivée de son titulaire Ğ1, ou une lettre sosie, ne passe pas pour un membre de la toile. - Un lien d'équipe refuse aussi le nom qu'une invitation attend encore. Boucle : 68 tests Rust, svelte-check, 9 vitest, e2e 13/13. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -97,7 +97,16 @@ pub struct JoinBody {
|
||||
/// `name_key` settles two openings at the same instant.
|
||||
async fn free_name(state: &AppState, raw: &str) -> AppResult<names::Name> {
|
||||
let name = names::check(raw).ok_or(AppError::Invalid("name"))?;
|
||||
let taken: Vec<String> = sqlx::query_scalar("SELECT display_name FROM identities").fetch_all(&state.db).await?;
|
||||
// People already there, and those an invitation still waits for.
|
||||
let mut taken: Vec<String> = sqlx::query_scalar("SELECT display_name FROM identities").fetch_all(&state.db).await?;
|
||||
taken.extend(
|
||||
sqlx::query_scalar::<_, String>(
|
||||
"SELECT label FROM invitations WHERE used_at IS NULL AND identity_id IS NULL AND expires_at > ?",
|
||||
)
|
||||
.bind(util::now())
|
||||
.fetch_all(&state.db)
|
||||
.await?,
|
||||
);
|
||||
if taken.iter().any(|t| names::key(t) == name.key) {
|
||||
return Err(AppError::Conflict("name_taken"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user