from otree.api import Currency as c, currency_range from ._builtin import Page as oTreePage, WaitPage from .models import Constants, Task from .forms import TaskForm, cq_formset from colorama import Back, Fore import otree.bots.browser as browser_bots from django.core import validators from django.db.models import Sum class GeneralCQMixin: def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['formset'] = cq_formset(instance=self.player, queryset=self.player.cqs.all()) return context def post(self): self.object = self.get_object() self.form = self.get_form( data=self.request.POST, files=self.request.FILES, instance=self.object) formset = cq_formset(self.request.POST, instance=self.player) if not formset.is_valid(): tot_wrong = self.player.cqs.all().aggregate(tot_wrong=Sum('counter'))['tot_wrong'] if tot_wrong > Constants.max_total_wrong_answers: self.player.eligible = False return super().post() context = self.get_context_data() context['formset'] = formset context['form'] = self.form return self.render_to_response(context) formset.save() return super().post() class CompMixin: def get_form(self, *args, **kwargs): f = super().get_form(*args, **kwargs) for i, j in f.fields.items(): regex = rf'^{str(self.subsession.correct_answers.get(i))}$' j.validators.append(validators.RegexValidator(message='Please check the answer', regex=regex, code='invalid_input')) return f class Page(oTreePage): _allow_custom_attributes = True progress = True section = '' def get_progress(self): totpages = self.participant._max_page_index curpage = self.participant._index_in_pages return f"{curpage/totpages*100:.0f}" def get_context_data(self, *args, **kwargs): c = super().get_context_data(*args, **kwargs) c['sections'] = Constants.sections return c def is_displayed(self) -> bool: return self.player.eligible def __init__(self): if not hasattr(self, 'title'): self.title = self.__class__.__name__ super().__init__() class BackPage(Page): next_btn_seconds = Constants.default_next_btn_secs form_model = 'player' form_fields = ['back'] both_btns = True def get_form(self, *args, **kwargs): f = super().get_form(*args, **kwargs) f.fields['back'].widget.secs = self.next_btn_seconds f.fields['back'].widget.both_btns = self.both_btns return f def before_next_page(self): if self.player.back and self.both_btns: self._is_frozen = False self._index_in_pages -= 2 self.participant._index_in_pages -= 2 self.player.back = False class TaskPage(Page): _allow_custom_attributes = True # template_name = 'reallocation/Task.html' form_model = Task form_fields = ['answer'] form_class = TaskForm practice = False def _get_form_model(self): return self.form_model def get_object(self): if self.player.signal: self._is_frozen = False self.practice = True obj = self.player.get_next_task(practice=self.practice) return obj or super().get_object() def get_form_class(self): return self.form_class def is_displayed(self): if self.player.signal: self._is_frozen = False self.practice = True return self.player.get_next_task(practice=self.practice) is not None and super().is_displayed() def post(self): if self.participant.is_browser_bot: submission = browser_bots.get_next_post_data( participant_code=self.participant.code) post_data = self.request.POST.dict() post_data.update(submission) else: post_data = self.request.POST self.form = self.get_form( data=post_data, files=self.request.FILES, instance=self.get_object()) if self.form.is_valid(): self.object = self.form.save() else: response = self.form_invalid(self.form) return response context = self.get_context_data() if self.player.signal: self._is_frozen = False self.practice = True unanswered = self.player.tasks.filter(practice=self.practice, answer__isnull=True).count() if unanswered > 0: self.form = self.get_form(instance=self.get_object()) context['form'] = self.form return self.render_to_response(context) self._increment_index_in_pages() return self._redirect_to_page_the_user_should_be_on()