Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/boolean voting #56

Merged
merged 13 commits into from
Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion decide/store/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ def post(self, request):
return Response({}, status=status.HTTP_401_UNAUTHORIZED)

with transaction.atomic():
if voting[0]["question"]["question_type"] == "S":
if (
voting[0]["question"]["question_type"] == "S"
or voting[0]["question"]["question_type"] == "B"
):
v, _ = Vote.objects.get_or_create(voting_id=vid, voter_id=uid)
# Delete previous options
VoteOption.objects.filter(vote=v).delete()
Expand Down
21 changes: 21 additions & 0 deletions decide/voting/migrations/0011_alter_question_question_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 4.1 on 2023-12-16 13:56

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("voting", "0010_question_voteblank"),
]

operations = [
migrations.AlterField(
model_name="question",
name="question_type",
field=models.CharField(
choices=[("S", "Single"), ("M", "Multiple"), ("B", "Boolean")],
default="S",
max_length=1,
),
),
]
55 changes: 51 additions & 4 deletions decide/voting/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
from django.db.models import JSONField
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.core.exceptions import BadRequest


class Question(models.Model):
QUESTION_TYPES = (
("S", "Single"),
("M", "Multiple"),
)
QUESTION_TYPES = (("S", "Single"), ("M", "Multiple"), ("B", "Boolean"))

question_type = models.CharField(max_length=1, choices=QUESTION_TYPES, default="S")
desc = models.TextField()
Expand All @@ -32,6 +30,43 @@ def save(self, **kwargs):
)
enBlanco.save()
self.options.add(enBlanco)
if self.question_type == "B":
if (
QuestionOption.objects.filter(
question__id=self.id, option__startswith="Sí"
).count()
== 0
):
op1 = QuestionOption(
question=self, number=self.options.count() + 1, option="Sí"
)
op1.save()
self.options.add(op1)
if (
QuestionOption.objects.filter(
question__id=self.id, option__startswith="No"
).count()
== 0
):
op2 = QuestionOption(
question=self, number=self.options.count() + 1, option="No"
)
op2.save()
self.options.add(op2)
if (
self.voteBlank
and QuestionOption.objects.filter(
question_id=self.id, option__startswith="Voto En Blanco"
).count()
== 0
):
enBlanco = QuestionOption(
question=self,
number=self.options.count() + 1,
option="Voto En Blanco",
)
enBlanco.save()
self.options.add(enBlanco)
return super().save()

def __str__(self):
Expand All @@ -47,6 +82,18 @@ class QuestionOption(models.Model):
hidden = models.BooleanField(default=False)

def save(self):
if self.question.question_type == "B" and self.question.options.count() > 1:
if self.question.voteBlank:
if (
self.option != "Sí"
and self.option != "No"
and self.option != "Voto En Blanco"
):
AntonioRodriguezRuiz marked this conversation as resolved.
Show resolved Hide resolved
raise BadRequest(
"Boolean questions with white votes can only have 'Sí', 'No', or 'Voto En Blanco' options."
)
else:
raise BadRequest("Boolean questions cannot have any options.")
if not self.number:
self.number = self.question.options.count() + 1
else:
Expand Down
81 changes: 81 additions & 0 deletions decide/voting/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from selenium.webdriver.common.by import By
from voting.models import Question, QuestionOption, Voting
from selenium.webdriver.chrome.webdriver import WebDriver
from django.core.exceptions import BadRequest


class VotingTestCase(BaseTestCase):
Expand Down Expand Up @@ -238,6 +239,32 @@ def test_create_voting_from_api(self):
response = self.client.post("/voting/", data, format="json")
self.assertEqual(response.status_code, 201)

def test_create_boolean_voting_from_api(self):
data = {"name": "Example boolean"}
response = self.client.post("/voting/", data, format="json")
self.assertEqual(response.status_code, 401)

# login with user no admin
self.login(user="noadmin")
response = mods.post("voting", params=data, response=True)
self.assertEqual(response.status_code, 403)

# login with user admin
self.login()
response = mods.post("voting", params=data, response=True)
self.assertEqual(response.status_code, 400)

data = {
"name": "Example boolean",
"desc": "Description example boolean",
"question_type": "B",
"question": "Do you agree?",
"question_opt": ["Sí", "No"],
}

response = self.client.post("/voting/", data, format="json")
self.assertEqual(response.status_code, 201)

def test_update_voting(self):
voting = self.create_voting()

Expand Down Expand Up @@ -591,3 +618,57 @@ def createCensusEmptyError(self):
self.cleaner.current_url
== self.live_server_url + "/admin/voting/question/add/"
)


class BooleanQuestionTestCase(BaseTestCase):
def setUp(self):
self.question = Question.objects.create(
question_type="B", desc="What is your favorite color?", voteBlank=False
)
self.question.save()

def test_save_boolean_question(self):
self.assertEqual(QuestionOption.objects.count(), 2)
self.assertEqual(QuestionOption.objects.first().option, "Sí")
self.assertEqual(QuestionOption.objects.last().option, "No")

def test_str_representation(self):
self.assertEqual(str(self.question), "What is your favorite color?")

def test_one_option_boolean_question(self):
self.question = Question.objects.create(
question_type="B", desc="What is your favorite color?", voteBlank=False
)
self.question.save()

opt = QuestionOption(question=self.question, option="option {}".format(1))
with self.assertRaises(BadRequest):
opt.save()
AntonioRodriguezRuiz marked this conversation as resolved.
Show resolved Hide resolved

def test_multiple_option_boolean_question(self):
self.question = Question.objects.create(
question_type="B", desc="What is your favorite color?", voteBlank=False
)
self.question.save()

opt1 = QuestionOption(question=self.question, option="option {}".format(1))
opt2 = QuestionOption(question=self.question, option="option {}".format(2))
opt3 = QuestionOption(question=self.question, option="option {}".format(3))
with self.assertRaises(BadRequest):
opt1.save()
opt2.save()
opt3.save()
AntonioRodriguezRuiz marked this conversation as resolved.
Show resolved Hide resolved


class BooleanWhiteTestCase(BaseTestCase):
def setUp(self):
self.question = Question.objects.create(
question_type="B", desc="What is your favorite color?", voteBlank=True
)
self.question.save()

def test_boolean_question_and_white(self):
self.assertEqual(QuestionOption.objects.count(), 3)
self.assertEqual(QuestionOption.objects.first().option, "Sí")
self.assertEqual(QuestionOption.objects.all()[1].option, "No")
self.assertEqual(QuestionOption.objects.last().option, "Voto En Blanco")