Skip to content

Commit fc4be50

Browse files
committed
Fixed: ballot endpoints does not care about date_start allowing using to send vote before the election starts
1 parent 5704dfc commit fc4be50

File tree

3 files changed

+63
-1
lines changed

3 files changed

+63
-1
lines changed

app/crud.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ def create_ballot(db: Session, ballot: schemas.BallotCreate) -> schemas.BallotGe
367367
db_election = _check_public_election(db, ballot.election_ref)
368368
election = schemas.ElectionGet.model_validate(db_election)
369369

370+
_check_election_is_started(db_election)
370371
_check_election_is_not_ended(db_election)
371372

372373
_check_items_in_election(
@@ -406,6 +407,14 @@ def _check_public_election(db: Session, election_ref: str):
406407
)
407408
return db_election
408409

410+
def _check_election_is_started(election: models.Election):
411+
"""
412+
Check that the election is started.
413+
If it is not, raise an error.
414+
"""
415+
if election.date_start is not None and election.date_start > datetime.now():
416+
raise errors.ForbiddenError("The election has not started yet. You can not create votes")
417+
409418
def _check_election_is_not_ended(election: models.Election):
410419
"""
411420
Check that the election is not ended.
@@ -453,6 +462,7 @@ def update_ballot(
453462
if db_election is None:
454463
raise errors.NotFoundError("elections")
455464

465+
_check_election_is_started(db_election)
456466
_check_election_is_not_ended(db_election)
457467

458468
if len(ballot.votes) != len(vote_ids):

app/schemas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class ElectionBase(BaseModel):
115115
name: Name
116116
description: Description = ""
117117
ref: Ref = ""
118-
date_start: datetime | int | str = Field(default_factory=_utc_now)
118+
date_start: datetime | int | str | None = Field(default_factory=_utc_now)
119119
date_end: datetime | int | str | None = Field(default_factory=_in_a_long_time)
120120
hide_results: bool = True
121121
restricted: bool = False

app/tests/test_api.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class RandomElection(t.TypedDict):
5959
hide_results: bool
6060
num_voters: int
6161
date_end: t.Optional[str]
62+
date_start: t.Optional[str]
6263

6364

6465
def _random_election(num_candidates: int, num_grades: int) -> RandomElection:
@@ -71,6 +72,7 @@ def _random_election(num_candidates: int, num_grades: int) -> RandomElection:
7172
candidates = [{"name": _random_string(10)} for i in range(num_candidates)]
7273
name = _random_string(10)
7374
return {
75+
"date_start":None,
7476
"candidates": candidates,
7577
"grades": grades,
7678
"name": name,
@@ -394,6 +396,56 @@ def test_cannot_update_vote_on_ended_election():
394396

395397
assert response.status_code == 403, response.json()
396398

399+
## TODO: cannot change start_date if a people vote;
400+
##
401+
def test_cannot_create_vote_on_unstarted_election():
402+
"""
403+
On an unstarted election, we are not allowed to create new votes
404+
"""
405+
# Create a random election
406+
body = _random_election(10, 5)
407+
body["date_start"] = (datetime.now() + timedelta(days=1)).isoformat()
408+
body["date_end"] = (datetime.now() + timedelta(days=2)).isoformat()
409+
response = client.post("/elections", json=body)
410+
data = response.json()
411+
assert response.status_code == 200, data
412+
election_ref = data["ref"]
413+
414+
# We create votes using the ID
415+
votes = _generate_votes_from_response("id", data)
416+
response = client.post(
417+
f"/ballots",
418+
json={"votes": votes, "election_ref": election_ref},
419+
)
420+
data = response.json()
421+
assert response.status_code == 403, data
422+
423+
def test_cannot_update_vote_on_unstarted_election():
424+
"""
425+
On an unstarted election, we are not allowed to create new votes
426+
"""
427+
# Create a random election
428+
body = _random_election(10, 5)
429+
body["restricted"] = True
430+
body["num_voters"] = 1
431+
body["date_start"] = (datetime.now() + timedelta(days=1)).isoformat()
432+
body["date_end"] = (datetime.now() + timedelta(days=2)).isoformat()
433+
response = client.post("/elections", json=body)
434+
data = response.json()
435+
assert response.status_code == 200, data
436+
election_ref = data["ref"]
437+
tokens = data["invites"]
438+
assert len(tokens) == 1
439+
440+
# We create votes using the ID
441+
votes = _generate_votes_from_response("id", data)
442+
response = client.put(
443+
f"/ballots",
444+
json={"votes": votes, "election_ref": election_ref},
445+
headers={"Authorization": f"Bearer {tokens[0]}"},
446+
)
447+
data = response.json()
448+
assert response.status_code == 403, data
397449

398450
def test_cannot_create_vote_on_restricted_election():
399451
"""

0 commit comments

Comments
 (0)