WIP lot V : le tampon câblé dans le serveur (migration 0010, simulation, discard-simulation), tests en cours de reprise — repris tel quel après la coupure du 02/11
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -586,6 +586,7 @@ pub async fn detail(
|
||||
|
||||
let my_vote = ballots::my_votes(&state, &user.id, &st.doc.id).await?.remove(&id);
|
||||
let my_ballot = ballots::my_ballots(&state, &user.id, &st.doc.id).await?.remove(&id);
|
||||
let seen = ballots::seen(p.revision, my_vote.as_ref(), my_ballot.as_ref());
|
||||
let diff = match (&in_force, p.kind.as_str()) {
|
||||
(Some(v), "text") => Some(edit::diff(&v.body, &p.body)),
|
||||
_ => None,
|
||||
@@ -602,11 +603,11 @@ pub async fn detail(
|
||||
"mine": p.author_id.as_deref() == Some(user.id.as_str()),
|
||||
"submittedAt": p.submitted_at, "enteredAt": p.entered_at, "confirmedAt": p.confirmed_at,
|
||||
"seedMinimal": p.status == "in_force" && p.entered_at.is_none() && p.confirmed_at.is_none() && p.origin == "seed",
|
||||
"tally": st.shown_tally(&p.id), "evaluation": eval, "votedAtInertia": voted_at,
|
||||
"tally": st.shown_tally(&p.id), "tallyPending": st.pending_tally(&p.id),
|
||||
"tallySimulated": st.simulated_tally(&p.id), "evaluation": eval, "votedAtInertia": voted_at,
|
||||
"blocked": st.blocked.contains(&p.id), "votable": st.votable(&p),
|
||||
"myVote": my_vote.as_ref().map(|v| &v.choice),
|
||||
"myVoteStale": my_vote.as_ref().is_some_and(|v| v.revision != p.revision),
|
||||
"myVoteChain": my_vote.as_ref().is_some_and(|v| v.source == "chain"), "myBallot": my_ballot,
|
||||
"myVote": seen.choice, "myVoteState": seen.state, "myVoteStale": seen.stale,
|
||||
"myVoteChain": seen.chain, "myBallot": my_ballot,
|
||||
"translations": tr.get(&p.id).cloned().unwrap_or_default(),
|
||||
},
|
||||
"unit": { "id": unit.id, "code": unit.code, "inertia": docs::inertia_of(unit) },
|
||||
@@ -633,8 +634,9 @@ pub struct VoteBody {
|
||||
choice: Option<String>,
|
||||
}
|
||||
|
||||
/// One vote on the server, in a managed group. Where the vote goes through the
|
||||
/// chain (Monnaie libre), it is a ballot (`ballots::create`), never this.
|
||||
/// One vote written by the server: in a managed group, or in simulation while
|
||||
/// the chain is closed (ADR 0012). Where the vote goes through the chain and the
|
||||
/// chain is open (Monnaie libre), it is a ballot (`ballots::create`), never this.
|
||||
pub async fn vote(
|
||||
State(state): State<AppState>,
|
||||
User(user): User,
|
||||
@@ -642,9 +644,7 @@ pub async fn vote(
|
||||
Json(b): Json<VoteBody>,
|
||||
) -> AppResult<Json<serde_json::Value>> {
|
||||
let (p, st) = guarded(&state, &user, &id).await?;
|
||||
if trustin_access::vote_way(&st.group.to_group()) == trustin_access::VoteWay::Chain {
|
||||
return Err(AppError::Conflict("chain_only"));
|
||||
}
|
||||
let way = ballots::server_way(&state, &st.group)?;
|
||||
if !matches!(p.status.as_str(), "open" | "in_force") {
|
||||
return Err(AppError::Conflict("not_votable"));
|
||||
}
|
||||
@@ -659,13 +659,12 @@ pub async fn vote(
|
||||
if !st.admits(&p, choice) {
|
||||
return Err(AppError::Conflict("objection"));
|
||||
}
|
||||
if !docs::may_vote(&state, &user, &st.group).await? {
|
||||
if !ballots::may_write(&state, &user, &st.group, way).await? {
|
||||
return Err(AppError::Conflict("members_only"));
|
||||
}
|
||||
let cast = ballots::Cast { proposal_id: p.id.clone(), revision: p.revision, choice };
|
||||
ballots::write_server_votes(&state, &user.id, &[cast]).await?;
|
||||
let entered = adoption::run(&state, &st.doc.id).await?;
|
||||
Ok(Json(json!({ "entered": entered })))
|
||||
let entered = ballots::write(&state, &user, &st, way, &[cast]).await?;
|
||||
Ok(Json(json!({ "entered": entered, "simulated": way == ballots::ServerWay::Simulated })))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user