Skip to content

Commit

Permalink
feat: disabling selected choices
Browse files Browse the repository at this point in the history
  • Loading branch information
AmooHashem committed Nov 4, 2024
1 parent bcdd9cc commit 798fa05
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 71 deletions.
96 changes: 27 additions & 69 deletions apps/attributes/models/intrinsic_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,41 @@ class Enabled(IntrinsicAttribute):
class Condition(IntrinsicAttribute):

def is_true(self, *args, **kwargs):
from apps.fsm.utils import AnswerSheetFacade

player = kwargs.get('player')
user = kwargs.get('user')
value = self.value
total_condition_result = True

if 'expected_correct_choices_in_last_answer_count' in value:
expected_count = value.get(
'expected_correct_choices_in_last_answer_count')
if not player:
total_condition_result = False
else:
expected_correct_choices_in_last_answer_count = value.get(
'expected_correct_choices_in_last_answer_count')
facade = AnswerSheetFacade(player.answer_sheet)
total_condition_result = facade.check_expected_correct_choices_in_last_answer_count(
expected_correct_choices_in_last_answer_count)

try:
# Get the last multi-choice answer in a single query
from apps.fsm.models.response import MultiChoiceAnswer
last_answer = (
player.answer_sheet.answers
.instance_of(MultiChoiceAnswer)
.prefetch_related('choices')
.latest('id')
)

# Count how many of the selected choices are marked as correct
correct_choices_count = sum(
1 for choice in last_answer.choices.all()
if choice.is_correct
)

total_condition_result = correct_choices_count == expected_count
except:
if 'expected_choices' in value:
if not player:
total_condition_result = False
else:
expected_choice_ids = value.get('expected_choices')
facade = AnswerSheetFacade(player.answer_sheet)
total_condition_result = facade.check_expected_choices(
expected_choice_ids)

if 'expected_choices_in_last_answer' in value:
if not player:
total_condition_result = False
else:
expected_choice_ids = value.get(
'expected_choices_in_last_answer')
facade = AnswerSheetFacade(player.answer_sheet)
total_condition_result = facade.check_expected_choices_in_last_answer(
expected_choice_ids)

if 'completed_fsms' in value:
completed_fsm_ids = value.get('completed_fsms')
Expand All @@ -55,55 +62,6 @@ def is_true(self, *args, **kwargs):
except:
total_condition_result = False

if 'expected_choices' in value:
expected_choice_ids = value.get('expected_choices')

try:
# Get all multi-choice answers in one query
from apps.fsm.models.response import MultiChoiceAnswer
multi_choice_answers = (
player.answer_sheet.answers
.instance_of(MultiChoiceAnswer)
.prefetch_related('choices')
)

# Create a set of all selected choice IDs for O(1) lookup
all_choice_ids = {
choice.id
for answer in multi_choice_answers
for choice in answer.choices.all()
}

# Check if all expected choices exist in the set
total_condition_result = \
all(choice_id in all_choice_ids for choice_id in expected_choice_ids)
except:
total_condition_result = False

if 'expected_choices_in_last_answer' in value:
expected_choice_ids = value.get('expected_choices_in_last_answer')

try:
# Get the last multi-choice answer in a single query
from apps.fsm.models.response import MultiChoiceAnswer
last_answer = (
player.answer_sheet.answers
.instance_of(MultiChoiceAnswer)
.prefetch_related('choices')
.latest('id')
)

# Convert both sets of choices to sets for comparison
submitted_choice_ids = {
choice.id for choice in last_answer.choices.all()}

expected_choice_ids = set(expected_choice_ids)

total_condition_result = submitted_choice_ids == expected_choice_ids

except:
total_condition_result = False

is_not = value.get('not', False)
return total_condition_result ^ is_not

Expand Down
1 change: 1 addition & 0 deletions apps/fsm/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def object(self):
def attributes(self):
return self.object.attributes.all()

# default is False
def is_enabled(self, *args, **kwargs) -> bool:
user = kwargs.get('user')
if not user:
Expand Down
1 change: 1 addition & 0 deletions apps/fsm/models/fsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class FSMCardType(models.TextChoices):
def __str__(self):
return self.name

# default is False
def is_enabled(self, *args, **kwargs) -> bool:
user = kwargs.get('user')

Expand Down
12 changes: 10 additions & 2 deletions apps/fsm/models/question_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,19 @@ class Choice(models.Model):
text = models.TextField()
is_correct = models.BooleanField(default=False)

# default is True
def is_enabled(self, *args, **kwargs):
from apps.fsm.utils import AnswerSheetFacade
player = kwargs.get('player')
answer_sheet = player.answer_sheet
result = False
return result
facade = AnswerSheetFacade(answer_sheet)

question = self.problem
if question.lock_after_answer:
if facade.check_expected_choices_in_last_answer([self.id]):
return False

return True

def __str__(self):
return self.text
Expand Down
69 changes: 69 additions & 0 deletions apps/fsm/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,72 @@ def get_user_permission(receipt: RegistrationReceipt) -> dict:
def add_admin_to_program(user: User, program: Program):
program.admins.add(user)
register_user_in_program(user, program)


class AnswerSheetFacade:
def __init__(self, answer_sheet) -> None:
self.answer_sheet = answer_sheet

def check_expected_choices(self, expected_choice_ids):
try:
# Get all multi-choice answers in one query
from apps.fsm.models.response import MultiChoiceAnswer
multi_choice_answers = (
self.answer_sheet.answers
.instance_of(MultiChoiceAnswer)
.prefetch_related('choices')
)

# Create a set of all selected choice IDs for O(1) lookup
all_choice_ids = {
choice.id
for answer in multi_choice_answers
for choice in answer.choices.all()
}

# Check if all expected choices exist in the set
return all(choice_id in all_choice_ids for choice_id in expected_choice_ids)
except:
return False

def check_expected_choices_in_last_answer(self, expected_choice_ids):
try:
# Get the last multi-choice answer in a single query
from apps.fsm.models.response import MultiChoiceAnswer
last_answer = (
self.answer_sheet.answers
.instance_of(MultiChoiceAnswer)
.prefetch_related('choices')
.latest('id')
)

# Convert both sets of choices to sets for comparison
submitted_choice_ids = {
choice.id for choice in last_answer.choices.all()}

expected_choice_ids = set(expected_choice_ids)

return submitted_choice_ids == expected_choice_ids
except:
return False

def check_expected_correct_choices_in_last_answer_count(self, expected_correct_choices_in_last_answer_count):
try:
# Get the last multi-choice answer in a single query
from apps.fsm.models.response import MultiChoiceAnswer
last_answer = (
self.answer_sheet.answers
.instance_of(MultiChoiceAnswer)
.prefetch_related('choices')
.latest('id')
)

# Count how many of the selected choices are marked as correct
correct_choices_count = sum(
1 for choice in last_answer.choices.all()
if choice.is_correct
)

return correct_choices_count == expected_correct_choices_in_last_answer_count
except:
return False

0 comments on commit 798fa05

Please sign in to comment.