Results

Overview

The ballots system provides flexible data visualization and aggregation capabilities for voting results. It supports sorting by multiple criteria, filtering by voters or candidates, and provides various rendering endpoints for displaying ballot data.

Sorting Logic

Primary Sorting Modes

The system supports sorting by different metrics:

  1. By Date (Default) - Sorts by when votes were cast (voted_on column)
  2. By Sum - Sorts by total sum of points
  3. By Mean - Sorts by average score per candidate
  4. By Weight - Sorts by weighted scores
  5. By Category - Sorts by a specific category/option name

Sorting Implementation

// From src/ballots.rs#L789-879
pub async fn ballots_sorted(
    voting_id: &str,
    mode: Option<&str>,
    sort: Option<&str>,
    voters: Vec<&str>,
    candidates: Vec<&str>,
    filter: Option<&str>,
) -> Table<Criterion, TableRow>

The sorting logic works as follows:

  1. Collects all ballots for the specified voting session
  2. Applies string filtering (if provided)
  3. Applies candidate/voter filtering (if provided)
  4. Applies ESC mode (if mode="esc"):
    • Groups rows by candidate
    • Aggregates votes across all voters
    • Calculates mean scores
    • Sorts in descending order by sum
  5. Applies the specified sort criterion to the table rows

ESC Mode (Enhanced Sorting Criteria)

When mode="esc", the system uses the sort_merge_esc function which:

  • Groups ballots by candidate
  • Merges votes from multiple voters
  • Calculates mean for each candidate
  • Sorts results by total sum in descending order

Filtering Logic

String Filtering

The filter_table_by_str function allows filtering by comma-separated tokens:

// From src/ballots.rs#L755-787
fn filter_table_by_str(
    table: Table<Criterion, TableRow>,
    filter: &str,
) -> Table<Criterion, TableRow>

Behavior:

  • Accepts a comma-separated string of terms
  • Matches rows where the candidate name or any vote name contains the term (case-insensitive)
  • Example: filter="candidate1,candidate2" will match rows with either candidate

Candidate/Voter Filtering

The filter_row_on_candidates function provides precise filtering:

// From src/ballots.rs#L594-685
fn filter_row_on_candidates(
    rows: Table<Criterion, TableRow>,
    voters: Vec<&str>,
    candidates: Vec<&str>,
) -> Table<Criterion, TableRow>

Behavior:

  • Takes vectors of voter names and candidate names as filter criteria
  • Uses case-insensitive substring matching
  • If voters vector is empty, all voters are included
  • If candidates vector is empty, all candidates are included
  • Rows must match BOTH voter AND candidate criteria (if both are specified)
  • Aggregates results by candidate

Filter Order of Operations

// From src/ballots.rs#L789-879
table = filter_table_by_str(table, extracted_filter);  // First: String filter
table = filter_row_on_candidates(table, voters, candidates);  // Second: Candidate/voter filter

Available Render Endpoints

1. Ballots by Voted On

Endpoint: GET /ballots/<voting_id>

// From src/templates/ballots.rs#L17-27
#[get("/<voting_id>")]
pub async fn render_ballots_by_voted_on(voting_id: &str)

Description: Lists all ballots in chronological order by when they were cast.

Template: cast-ballots


2. Ballots with Advanced Filtering & Sorting

Endpoint: GET /ballots/<voting_id>/results?sort=...&mode=...&voter=...&candidate=...&filter=...

// From src/templates/ballots.rs#L29-51
#[get("/<voting_id>/results?<sort>&<mode>&<voter>&<candidate>&<filter>")]
pub async fn render_ballots_sorted(
    voting_id: &str,
    sort: Option<&str>,
    mode: Option<&str>,
    voter: Vec<&str>,
    candidate: Vec<&str>,
    filter: Option<&str>,
)

Query Parameters:

ParameterTypeDescription
voting_idpathThe voting session identifier
sortquerySort criterion: date, sum, mean, weight, or category:<name>
modequeryRendering mode: esc for ESC mode, or no-esc (default)
voterqueryVector of voter names to filter by
candidatequeryVector of candidate names to filter by
filterqueryComma-separated string filter for candidates/vote names

Sort Options:

  • date - Sort by voting date (default)
  • sum - Sort by total sum (descending)
  • mean - Sort by average score (descending)
  • weight - Sort by weighted score (descending)
  • category:<name> - Sort by a specific category (descending)

Mode Options:

  • esc - Use ESC mode (grouped by candidate, aggregated votes, sorted by sum)
  • no-esc - Individual rows, not aggregated

Templates: esc or cast-ballots (depending on mode)


3. Ballots by Specific Voter

Endpoint: GET /ballots/<voting_id>/voters/<voter>

// From src/templates/ballots.rs#L53-63
#[get("/<voting_id>/voters/<voter>")]
pub async fn render_ballots_by_voter(
    voting_id: &str,
    voter: &str,
)

Description: Shows all ballots cast by a specific voter for the voting session.

Template: cast-user-ballots

Response: If no ballots found, renders missing-data template.


4. Ballots by Specific Candidate

Endpoint: GET /ballots/<voting_id>/candidates/<candidate>

// From src/templates/ballots.rs#L65-75
#[get("/<voting_id>/candidates/<candidate>")]
pub async fn render_ballots_by_candidate(
    voting_id: &str,
    candidate: &str,
)

Description: Shows all ballots received by a specific candidate.

Template: cast-user-ballots

Response: If no ballots found, renders missing-data template.


Data Structure

TableRow

pub struct TableRow {
    pub voting: String,      // Voting session identifier
    pub voter: String,       // Voter identifier
    pub candidate: String,   // Candidate identifier
    pub sum: i8,             // Total sum of points
    pub weighted: f64,       // Weighted score
    pub mean: f64,           // Average score
    notes: String,           // Additional notes
    votes: Vec<Vote>,        // Array of individual votes
    pub voted_on: String,    // Timestamp of vote
}

Usage Examples

Example 1: Show All Ballots Chronologically

GET /ballots/12345

Example 2: Sort by Sum (ESC Mode)

GET /ballots/12345/results?sort=sum&mode=esc

Example 3: Filter by Specific Voter and Candidate

GET /ballots/12345/results?sort=mean&voter=john_doe&candidate=alice_smith

Example 4: Filter by Category

GET /ballots/12345/results?sort=category:technical&mode=esc

Example 5: String Filter

GET /ballots/12345/results?filter=candidate1,candidate2

Example 6: View Ballots by Specific Voter

GET /ballots/12345/voters/john_doe

Example 7: View Ballots by Specific Candidate

GET /ballots/12345/candidates/alice_smith

Summary

The ballots system provides a flexible and powerful way to:

  • Sort by multiple criteria (date, sum, mean, weight, or category)
  • Filter using precise criteria (voter/candidate names) or loose string matching
  • Aggregate votes across multiple voters when using ESC mode
  • Display different views for administrative and end-user purposes

The system automatically handles edge cases like missing data and provides appropriate templates for different scenarios.