Beispiel #1
0
class Player(BasePlayer):
    points = models.TextField()
    x_coordinate_form_pick = models.IntegerField()
    y_coordinate_form_pick = models.IntegerField()
    x_coordinate_form_guess = models.IntegerField()
    y_coordinate_form_guess = models.IntegerField()
    guess = models.TextField()
Beispiel #2
0
class FormFieldModel(otree.models.BaseGroup):
    null_boolean = models.BooleanField()
    big_integer = models.BigIntegerField()
    boolean = models.BooleanField(default=False)
    char = models.CharField()
    comma_separated_integer = models.CommaSeparatedIntegerField(max_length=100)
    date = models.DateField()
    date_time = models.DateTimeField()
    alt_date_time = models.DateTimeField(
        widget=otree.forms.SplitDateTimeWidget)
    decimal = models.DecimalField(max_digits=5, decimal_places=2)
    email = models.EmailField()
    file = models.FileField(upload_to='_tmp/uploads')
    file_path = models.FilePathField()
    float = models.FloatField()
    integer = models.IntegerField()
    generic_ip_address = models.GenericIPAddressField()
    positive_integer = models.PositiveIntegerField()
    positive_small_integer = models.PositiveSmallIntegerField()
    slug = models.SlugField()
    small_integer = models.SmallIntegerField()
    text = models.TextField()
    alt_text = models.TextField(widget=otree.forms.TextInput)
    time = models.TimeField()
    url = models.URLField()
    many_to_many = models.ManyToManyField('SimpleModel', related_name='+')
    one_to_one = models.OneToOneField('SimpleModel', related_name='+')

    currency = models.CurrencyField()
    currency_choice = models.CurrencyField(choices=[('0.01',
                                                     '0.01'), ('1.20',
                                                               '1.20')])

    sent_amount = models.CurrencyField(choices=currency_range(0, 0.75, 0.05))
    slider_widget = models.IntegerField(widget=widgets.SliderInput())
Beispiel #3
0
class Player(BasePlayer):
    transcription_1 = models.TextField(
        validators=[MaxLengthValidator(Constants.transcription_max_length)])
    transcription_2 = models.TextField(
        validators=[MaxLengthValidator(Constants.transcription_max_length)])
    distance_1 = models.PositiveIntegerField()
    distance_2 = models.PositiveIntegerField()

    def set_payoff(self):
        self.payoff = 0
Beispiel #4
0
class Player(BasePlayer):
    time_Demographics = models.TextField(widget=widgets.HiddenInput(
        attrs={'id': 'arrive_time'}))
    time_CognitiveReflectionTest = models.TextField(widget=widgets.HiddenInput(
        attrs={'id': 'arrive_time'}))

    def set_payoff(self):
        """Calculate payoff, which is zero for the survey"""
        self.payoff = 0

    q_country = models.CharField(verbose_name='What country are you from?')

    q_age = models.PositiveIntegerField(verbose_name='What is your age?',
                                        choices=range(13, 125),
                                        initial=None)

    q_station = models.PositiveIntegerField(
        verbose_name=
        'What is your computer station number? (see white sticker on computer or ask experimenter)',
        choices=range(1, 17),
        initial=None)

    q_gender = models.CharField(initial=None,
                                choices=['Male', 'Female', 'Other'],
                                verbose_name='What is your gender?',
                                widget=widgets.RadioSelect())
    q_income = models.PositiveIntegerField(
        verbose_name='What is the approximate annual income of your family?',
        choices=[
            [1, 'less than $15,000'],
            [2, '$15,000 - $29,999'],
            [3, '$30,000 - $59,999'],
            [4, '$60,000 - $99,999'],
            [5, '$100,000 - $199,999'],
            [6, '$200,000 or more'],
            [7, 'I rather not answer this question'],
        ])

    q_zipcode = models.PositiveIntegerField(
        verbose_name='What is the zip code where you grew up?')

    q_opinion = models.CharField(
        initial=None,
        verbose_name=
        'Were the instructions provided in this experiment clear and useful?',
        choices=['Yes', 'No'],
        widget=widgets.RadioSelect())

    crt_bat = models.PositiveIntegerField()

    crt_widget = models.PositiveIntegerField()

    crt_lake = models.PositiveIntegerField()
Beispiel #5
0
class Player(BasePlayer):
    time_Instructions = models.TextField(widget=widgets.HiddenInput(
        attrs={'id': 'arrive_time'}))
    time_Transcription = models.TextField(widget=widgets.HiddenInput(
        attrs={'id': 'arrive_time'}))

    transcribed_text = models.TextField()
    distance_1 = models.PositiveIntegerField()
    levenshtein_distance = models.PositiveIntegerField()
    time_Instructions = models.LongStringField()

    def set_payoff(self):
        self.payoff = 0
Beispiel #6
0
class Player(BasePlayer):
    points = models.TextField()
    x_coordinate_form_pick = models.IntegerField()
    y_coordinate_form_pick = models.IntegerField()
    x_coordinate_form_guess = models.IntegerField()
    y_coordinate_form_guess = models.IntegerField()
    box_1_offset_left_form = models.IntegerField()
    box_1_offset_top_form = models.IntegerField()
    box_2_offset_left_form = models.IntegerField()
    box_2_offset_top_form = models.IntegerField()
    box_3_offset_left_form = models.IntegerField()
    box_3_offset_top_form = models.IntegerField()
    guess = models.TextField()
Beispiel #7
0
class Player(otree.models.BasePlayer):

    # <built-in>
    group = models.ForeignKey(Group, null=True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    transcription_1 = models.TextField(validators=[MaxLengthValidator(Constants.transcription_max_length)])
    transcription_2 = models.TextField(validators=[MaxLengthValidator(Constants.transcription_max_length)])
    distance_1 = models.PositiveIntegerField()
    distance_2 = models.PositiveIntegerField()

    def set_payoff(self):
        self.payoff = 0
Beispiel #8
0
class Player(otree.models.BasePlayer):

    # <built-in>
    group = models.ForeignKey(Group, null=True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    name = models.CharField(max_length=255, verbose_name="Your name")

    age = models.CharField(max_length=255, verbose_name="Your age")

    email = models.EmailField(verbose_name="Your email address")

    gender = models.CharField(verbose_name="Are you",
                              max_length=255,
                              widget=widgets.RadioSelect(),
                              choices=["Male", "Female"])

    major = models.CharField(max_length=1000,
                             verbose_name="What is your major?")

    location_of_your_partners_influence_your_decisions = models.TextField(
        verbose_name=("Did the location of your partners influence your "
                      "decisions of how much to contribute to the individual "
                      "account versus the team account? If yes, how?"))

    working_in_a_location_of_their_choice_more_less_to_the_team = models.BooleanField(
        widget=widgets.RadioSelect(),
        verbose_name=("When you were partnered with two people working in a "
                      "location of their choice, did you want to give more "
                      "to the team or less than when you were partnered "
                      "with two people working in a lab?"))

    partners_in_location_their_choice_worked_harder_than_the_lab = models.BooleanField(
        widget=widgets.RadioSelect(),
        verbose_name=("Do you believe your partners participation in a "
                      "location of their choice gave more to the group than "
                      "your partners working the lab?"))

    I_work_best_in = models.CharField(
        verbose_name="Are you",
        max_length=255,
        widget=widgets.RadioSelect(),
        choices=["Structured environments", "flexible environments"])

    risks_in_everyday_life = models.PositiveIntegerField(
        min=1,
        max=10,
        widget=widgets.SliderInput(),
        verbose_name=("In general, do you take more or less risks in everyday "
                      "life? ('1' = take less risk and '10' take more risk.)"))

    risks_in_financial_decision = models.PositiveIntegerField(
        min=1,
        max=10,
        widget=widgets.SliderInput(),
        default=5,
        verbose_name=
        (" In general, do you take more or less risks in financial decisions? "
         "life? ('1' = take less risk and '10' take more risk.)"))
Beispiel #9
0
class Player(otree.models.BasePlayer):

    # <built-in>
    group = models.ForeignKey(Group, null=True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    transcription_1 = models.TextField(
        validators=[MaxLengthValidator(Constants.transcription_max_length)])
    transcription_2 = models.TextField(
        validators=[MaxLengthValidator(Constants.transcription_max_length)])
    distance_1 = models.PositiveIntegerField()
    distance_2 = models.PositiveIntegerField()

    def transcription_1_error_message(self, text_user):
        if not text_is_close_enough(text_user, Constants.reference_texts[0],
                                    Constants.error_rate_transcription_1):
            if Constants.error_rate_transcription_1 == 0.0:
                return Constants.transcription_error_0
            else:
                return Constants.transcription_error_positive
        else:
            self.distance_1 = levenshtein(Constants.reference_texts[0],
                                          text_user)

    def transcription_2_error_message(self, text_user):
        if not text_is_close_enough(text_user, Constants.reference_texts[1],
                                    Constants.error_rate_transcription_2):
            if Constants.error_rate_transcription_2 == 0.0:
                return Constants.transcription_error_0
            else:
                return Constants.transcription_error_positive
        else:
            self.distance_2 = levenshtein(Constants.reference_texts[1],
                                          text_user)

    def set_payoff(self):
        self.payoff = 0
Beispiel #10
0
class Session(models.OTreeModel):
    class Meta:
        app_label = "otree"
        # if i don't set this, it could be in an unpredictable order
        ordering = ['pk']

    _ft = FieldTrackerWithVarsSupport()
    vars: dict = models._PickleField(default=dict)
    config: dict = models._PickleField(default=dict, null=True)

    # label of this session instance
    label = models.CharField(max_length=300,
                             null=True,
                             blank=True,
                             help_text='For internal record-keeping')

    code = models.CharField(
        default=random_chars_8,
        max_length=16,
        null=False,
        unique=True,
        doc="Randomly generated unique identifier for the session.",
    )

    mturk_HITId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk',
    )
    mturk_HITGroupId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk',
    )
    is_mturk = models.BooleanField(default=False)

    def mturk_num_workers(self):
        assert self.is_mturk
        return int(self.num_participants /
                   settings.MTURK_NUM_PARTICIPANTS_MULTIPLE)

    mturk_use_sandbox = models.BooleanField(
        default=True,
        help_text="Should this session be created in mturk sandbox?")

    # use Float instead of DateTime because DateTime
    # is a pain to work with (e.g. naive vs aware datetime objects)
    # and there is no need here for DateTime
    mturk_expiration = models.FloatField(null=True)
    mturk_qual_id = models.CharField(default='', max_length=50)

    archived = models.BooleanField(
        default=False,
        db_index=True,
        doc=("If set to True the session won't be visible on the "
             "main ViewList for sessions"),
    )

    comment = models.TextField(blank=True)

    _anonymous_code = models.CharField(default=random_chars_10,
                                       max_length=10,
                                       null=False,
                                       db_index=True)

    is_demo = models.BooleanField(default=False)

    _admin_report_app_names = models.TextField(default='')
    _admin_report_num_rounds = models.CharField(default='', max_length=255)

    num_participants = models.PositiveIntegerField()

    def __unicode__(self):
        return self.code

    @property
    def participation_fee(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['participation_fee']

    @property
    def real_world_currency_per_point(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['real_world_currency_per_point']

    @property
    def use_browser_bots(self):
        return self.config.get('use_browser_bots', False)

    def mock_exogenous_data(self):
        '''
        It's for any exogenous data:
        - participant labels (which are not passed in through REST API)
        - participant vars
        - session vars (if we enable that)
        '''
        if self.config.get('mock_exogenous_data'):
            import shared_out as user_utils

            with otree.db.idmap.use_cache():
                user_utils.mock_exogenous_data(self)
                otree.db.idmap.save_objects()
                # need to save self because it's not in the idmap cache
                self.save()

    def get_subsessions(self):
        lst = []
        app_sequence = self.config['app_sequence']
        for app in app_sequence:
            models_module = otree.common.get_models_module(app)
            subsessions = models_module.Subsession.objects.filter(
                session=self).order_by('round_number')
            lst.extend(list(subsessions))
        return lst

    def get_participants(self):
        return list(self.participant_set.order_by('id_in_session'))

    def mturk_worker_url(self):
        # different HITs
        # get the same preview page, because they are lumped into the same
        # "hit group". This is not documented, but it seems HITs are lumped
        # if a certain subset of properties are the same:
        # https://forums.aws.amazon.com/message.jspa?messageID=597622#597622
        # this seems like the correct design; the only case where this will
        # not work is if the HIT was deleted from the server, but in that case,
        # the HIT itself should be canceled.

        # 2018-06-04:
        # the format seems to have changed to this:
        # https://worker.mturk.com/projects/{group_id}/tasks?ref=w_pl_prvw
        # but the old format still works.
        # it seems I can't replace groupId by hitID, which i would like to do
        # because it's more precise.
        subdomain = "workersandbox" if self.mturk_use_sandbox else 'www'
        return "https://{}.mturk.com/mturk/preview?groupId={}".format(
            subdomain, self.mturk_HITGroupId)

    def mturk_is_expired(self):
        # self.mturk_expiration is offset-aware, so therefore we must compare
        # it against an offset-aware value.
        return self.mturk_expiration and self.mturk_expiration < time.time()

    def mturk_is_active(self):
        return self.mturk_HITId and not self.mturk_is_expired()

    def advance_last_place_participants(self):
        # django.test takes 0.5 sec to import,
        # if this is done globally then it adds to each startup
        # it's only used here, and often isn't used at all.
        # so best to do it only here
        # it gets cached
        import django.test

        client = django.test.Client()

        participants = self.get_participants()

        # in case some participants haven't started
        unvisited_participants = []
        for p in participants:
            if p._index_in_pages == 0:
                unvisited_participants.append(p)
                client.get(p._start_url(), follow=True)

        if unvisited_participants:
            # that's it -- just visit the start URL, advancing by 1
            return

        last_place_page_index = min([p._index_in_pages for p in participants])
        last_place_participants = [
            p for p in participants
            if p._index_in_pages == last_place_page_index
        ]

        for p in last_place_participants:
            try:
                current_form_page_url = p._current_form_page_url
                if current_form_page_url:
                    resp = client.post(
                        current_form_page_url,
                        data={
                            otree.constants.timeout_happened: True,
                            otree.constants.admin_secret_code:
                            ADMIN_SECRET_CODE,
                        },
                        follow=True,
                    )
                    # not sure why, but many users are getting HttpResponseNotFound
                    if resp.status_code >= 400:
                        msg = ('Submitting page {} failed, '
                               'returned HTTP status code {}.'.format(
                                   current_form_page_url, resp.status_code))
                        content = resp.content
                        if len(content) < 600:
                            msg += ' response content: {}'.format(content)
                        raise AssertionError(msg)

                else:
                    # it's possible that the slowest user is on a wait page,
                    # especially if their browser is closed.
                    # because they were waiting for another user who then
                    # advanced past the wait page, but they were never
                    # advanced themselves.
                    start_url = p._start_url()
                    resp = client.get(start_url, follow=True)
            except:
                logging.exception("Failed to advance participants.")
                raise

            # do the auto-advancing here,
            # rather than in increment_index_in_pages,
            # because it's only needed here.
            otree.channels.utils.sync_group_send_wrapper(
                type='auto_advanced',
                group=auto_advance_group(p.code),
                event={})

    def get_room(self):
        from otree.room import ROOM_DICT

        try:
            room_name = RoomToSession.objects.get(session=self).room_name
            return ROOM_DICT[room_name]
        except RoomToSession.DoesNotExist:
            return None

    def _get_payoff_plus_participation_fee(self, payoff):
        '''For a participant who has the given payoff,
        return their payoff_plus_participation_fee
        Useful to define it here, for data export
        '''

        return self.config[
            'participation_fee'] + payoff.to_real_world_currency(self)

    def _set_admin_report_app_names(self):

        admin_report_app_names = []
        num_rounds_list = []
        for app_name in self.config['app_sequence']:
            models_module = otree.common.get_models_module(app_name)
            app_label = get_app_label_from_name(app_name)
            try:
                select_template([
                    f'{app_label}/admin_report.html',
                    f'{app_label}/AdminReport.html'
                ])
            except TemplateDoesNotExist:
                pass
            else:
                admin_report_app_names.append(app_name)
                num_rounds_list.append(models_module.Constants.num_rounds)

        self._admin_report_app_names = ';'.join(admin_report_app_names)
        self._admin_report_num_rounds = ';'.join(
            str(n) for n in num_rounds_list)

    def _admin_report_apps(self):
        return self._admin_report_app_names.split(';')

    def _admin_report_num_rounds_list(self):
        return [int(num) for num in self._admin_report_num_rounds.split(';')]

    def has_admin_report(self):
        return bool(self._admin_report_app_names)
Beispiel #11
0
class Player(otree.models.BasePlayer):

    # <built-in>
    group = models.ForeignKey(Group, null=True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    player_re_type = models.IntegerField(min=min(Constants.player_types),
                                         max=max(Constants.player_types))

    transcription = models.TextField()
    share = models.BooleanField(default=False, widget=widgets.HiddenInput())

    training_skip = models.BooleanField(default=False,
                                        widget=widgets.HiddenInput())
    training_start_time = models.DateTimeField()
    training_idx = models.PositiveIntegerField(default=0)
    training_intents = models.JSONField()

    round_1_start_time = models.DateTimeField()
    round_1_idx = models.PositiveIntegerField(default=0)
    round_1_transcription_texts = models.JSONField()
    round_1_intents = models.JSONField()
    round_1_a_payoff = models.CurrencyField()

    round_2_start_time = models.DateTimeField()
    round_2_idx = models.PositiveIntegerField(default=0)
    round_2_transcription_texts = models.JSONField()
    round_2_intents = models.JSONField()
    round_2_shared = models.PositiveIntegerField(default=0)
    round_2_a_payoff = models.CurrencyField()
    round_2_b_payoff = models.CurrencyField()

    round_3_start_time = models.DateTimeField()
    round_3_idx = models.PositiveIntegerField(default=0)
    round_3_transcription_texts = models.JSONField()
    round_3_intents = models.JSONField()
    round_3_shared = models.PositiveIntegerField(default=0)
    round_3_a_payoff = models.CurrencyField()
    round_3_b_payoff = models.CurrencyField()

    def set_payoff(self):
        self.payoff = 0

    @property
    def training_transcription_texts(self):
        return Constants.reference_texts

    def training_png(self, idx):
        return Constants.reference_pngs[idx]

    def round_1_png(self, idx):
        if not hasattr(self, "__round_1_png"):
            self.__round_1_png = {}
        if idx not in self.__round_1_png:
            text = self.round_1_transcription_texts[idx]
            self.__round_1_png[idx] = txt2png.render(
                text, encoding=Constants.png_encoding)
        return self.__round_1_png[idx]

    def set_round_1_payoff(self):
        self.round_1_a_payoff = Constants.a_payoff * self.round_1_idx

    def round_1_time_left(self):
        start = self.round_1_start_time
        now = timezone.now()
        time_left = Constants.round_1_seconds - (now - start).seconds
        return time_left if time_left > 0 else 0

    def round_2_png(self, idx):
        if not hasattr(self, "__round_2_png"):
            self.__round_2_png = {}
        if idx not in self.__round_2_png:
            text = self.round_2_transcription_texts[idx]
            self.__round_2_png[idx] = txt2png.render(
                text, encoding=Constants.png_encoding)
        return self.__round_2_png[idx]

    def set_round_2_payoff(self):
        count_b = self.round_2_shared
        if count_b > 0:
            self.round_2_b_payoff = Constants.b_payoff * count_b
        else:
            self.round_2_b_payoff = 0
        count_a = self.round_2_idx - count_b
        if count_a > 0:
            self.round_2_a_payoff = Constants.a_payoff * count_a
        else:
            self.round_2_a_payoff = 0

    def round_2_time_left(self):
        start = self.round_2_start_time
        now = timezone.now()
        time_left = Constants.round_2_seconds - (now - start).seconds
        return time_left if time_left > 0 else 0

    def round_3_png(self, idx):
        if not hasattr(self, "__round_3_png"):
            self.__round_3_png = {}
        if idx not in self.__round_3_png:
            text = self.round_3_transcription_texts[idx]
            self.__round_3_png[idx] = txt2png.render(
                text, encoding=Constants.png_encoding)
        return self.__round_3_png[idx]

    def set_round_3_payoff(self):
        count_b = self.round_3_shared
        if count_b > 0:
            self.round_3_b_payoff = Constants.b_payoff * count_b
        else:
            self.round_3_b_payoff = 0
        count_a = self.round_3_idx - count_b
        if count_a > 0:
            self.round_3_a_payoff = Constants.a_payoff * count_a
        else:
            self.round_3_a_payoff = 0

    def round_3_time_left(self):
        start = self.round_3_start_time
        now = timezone.now()
        time_left = Constants.round_3_seconds - (now - start).seconds
        return time_left if time_left > 0 else 0
Beispiel #12
0
class Session(ModelWithVars):
    class Meta:
        # if i don't set this, it could be in an unpredictable order
        ordering = ['pk']
        app_label = "otree"

    config = models.JSONField(
        default=dict,
        null=True,
        doc=("the session config dict, as defined in the "
             "programmer's settings.py."))

    # label of this session instance
    label = models.CharField(max_length=300,
                             null=True,
                             blank=True,
                             help_text='For internal record-keeping')

    experimenter_name = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='For internal record-keeping')

    code = models.RandomCharField(
        db_index=True,
        length=8,
        doc="Randomly generated unique identifier for the session.")

    time_scheduled = models.DateTimeField(
        null=True,
        doc="The time at which the session is scheduled",
        help_text='For internal record-keeping',
        blank=True)

    time_started = models.DateTimeField(
        null=True,
        doc="The time at which the experimenter started the session")

    mturk_HITId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk')
    mturk_HITGroupId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk')
    mturk_qualification_type_id = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Qualification type that is '
        'assigned to each worker taking hit')

    # since workers can drop out number of participants on server should be
    # greater than number of participants on mturk
    # value -1 indicates that this session it not intended to run on mturk
    mturk_num_participants = models.IntegerField(
        default=-1, help_text="Number of participants on MTurk")

    mturk_sandbox = models.BooleanField(
        default=True,
        help_text="Should this session be created in mturk sandbox?")

    archived = models.BooleanField(
        default=False,
        db_index=True,
        doc=("If set to True the session won't be visible on the "
             "main ViewList for sessions"))

    git_commit_timestamp = models.CharField(
        max_length=200,
        null=True,
        doc=(
            "Indicates the version of the code (as recorded by Git) that was "
            "used to run the session, so that the session can be replicated "
            "later.\n Search through the Git commit log to find a commit that "
            "was made at this time."))

    comment = models.TextField(blank=True)

    _ready_to_play = models.BooleanField(default=False)

    _anonymous_code = models.RandomCharField(length=10)

    special_category = models.CharField(
        db_index=True,
        max_length=20,
        null=True,
        doc="whether it's a test session, demo session, etc.")

    # whether someone already viewed this session's demo links
    demo_already_used = models.BooleanField(default=False, db_index=True)

    # indicates whether a session has been fully created (not only has the
    # model itself been created, but also the other models in the hierarchy)
    ready = models.BooleanField(default=False)

    _pre_create_id = models.CharField(max_length=300, db_index=True, null=True)

    def __unicode__(self):
        return self.code

    @property
    def participation_fee(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['participation_fee']

    @property
    def real_world_currency_per_point(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['real_world_currency_per_point']

    @property
    def session_type(self):
        '''2015-07-10: session_type is deprecated
        this shim method will be removed eventually'''
        return self.config

    def is_open(self):
        return GlobalSingleton.objects.get().default_session == self

    def is_for_mturk(self):
        return (not self.is_demo()) and (self.mturk_num_participants > 0)

    def is_demo(self):
        return (self.special_category ==
                constants_internal.session_special_category_demo)

    def get_subsessions(self):
        lst = []
        app_sequence = self.config['app_sequence']
        for app in app_sequence:
            models_module = otree.common_internal.get_models_module(app)
            subsessions = models_module.Subsession.objects.filter(
                session=self).order_by('round_number')
            lst.extend(list(subsessions))
        return lst

    def delete(self, using=None):
        for subsession in self.get_subsessions():
            subsession.delete()
        super(Session, self).delete(using)

    def get_participants(self):
        return self.participant_set.all()

    def _create_groups_and_initialize(self):
        # group_by_arrival_time code used to be here
        for subsession in self.get_subsessions():
            subsession._create_groups()
            subsession._initialize()
            subsession.save()
        self._ready_to_play = True
        # assert self is subsession.session
        self.save()

    def mturk_requester_url(self):
        if self.mturk_sandbox:
            requester_url = (
                "https://requestersandbox.mturk.com/mturk/manageHITs")
        else:
            requester_url = "https://requester.mturk.com/mturk/manageHITs"
        return requester_url

    def mturk_worker_url(self):
        if self.mturk_sandbox:
            worker_url = (
                "https://workersandbox.mturk.com/mturk/preview?groupId={}"
            ).format(self.mturk_HITGroupId)
        else:
            worker_url = (
                "https://www.mturk.com/mturk/preview?groupId={}").format(
                    self.mturk_HITGroupId)
        return worker_url

    def advance_last_place_participants(self):
        participants = self.get_participants()

        c = django.test.Client()

        # in case some participants haven't started
        unvisited_participants = []
        for p in participants:
            if not p._current_form_page_url:
                unvisited_participants.append(p)
                c.get(p._start_url(), follow=True)

        if unvisited_participants:
            from otree.models import Participant
            for p in unvisited_participants:
                p.save()
                Participant.flush_cached_instance(p)
            # that's it -- just visit the start URL, advancing
            # by 1
            return

        last_place_page_index = min([p._index_in_pages for p in participants])
        last_place_participants = [
            p for p in participants
            if p._index_in_pages == last_place_page_index
        ]

        for p in last_place_participants:
            if not p._current_form_page_url:
                # what if first page is wait page?
                raise
            resp = c.post(p._current_form_page_url,
                          data={constants_internal.auto_submit: True},
                          follow=True)
            assert resp.status_code < 400

    def build_participant_to_player_lookups(self):
        subsession_app_names = self.config['app_sequence']

        num_pages_in_each_app = {}
        for app_name in subsession_app_names:
            views_module = otree.common_internal.get_views_module(app_name)

            num_pages = len(views_module.page_sequence)
            num_pages_in_each_app[app_name] = num_pages

        for participant in self.get_participants():
            participant.build_participant_to_player_lookups(
                num_pages_in_each_app)
Beispiel #13
0
class Player(otree.models.BasePlayer):

    # <built-in>
    group = models.ForeignKey(Group, null=True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    name = models.CharField(max_length=255, verbose_name="Your name")

    age = models.CharField(max_length=255, verbose_name="Your age")

    email = models.EmailField(verbose_name="Your email address")

    gender = models.CharField(verbose_name="Are you",
                              max_length=255,
                              widget=widgets.RadioSelect(),
                              choices=["Male", "Female"])

    major = models.CharField(max_length=1000,
                             verbose_name="What is your major?")

    working_in_a_location_of_their_choice_more_less_to_the_team = models.CharField(
        verbose_name=
        "When you were in a group with two TELECOMMUTERS working in a "
        "location and time of their choice, did you want to give more "
        "to the group account than when you were partnered "
        "with two LAB PARTICIPANTS?",
        max_length=500,
        widget=widgets.RadioSelect(),
        choices=[
            "More to the Group Account with TELECOMMUTERS",
            "Less to the Group Account with TELECOMMUTERS", "Didn't Matter"
        ])

    partners_in_location_their_choice_worked_harder_than_the_lab = models.CharField(
        verbose_name=
        "Do you believe your TELECOMMUTER group members gave more/less/the same to the group "
        "account than your LAB PARTICIPANT group members?",
        max_length=500,
        widget=widgets.RadioSelect(),
        choices=[
            "TELECOMMUTERS gave more", "TELECOMMUTERS gave less",
            "Both types gave the same"
        ])

    location_of_your_partners_influence_your_decisions = models.TextField(
        verbose_name=(
            "Did your group members' type (TELECOMMUTERS or LAB PARTICIPANTS) "
            "influence your decisions today in a way not accounted for above? "
            "If so, please explain."))

    I_work_best_in = models.CharField(
        verbose_name="Which do you prefer working in?",
        max_length=255,
        widget=widgets.RadioSelect(),
        choices=["Structured environments", "flexible environments"])

    I_work_prefer = models.CharField(
        verbose_name="Which type of work do you prefer?",
        max_length=255,
        widget=widgets.RadioSelect(),
        choices=["Working Alone", "Working in Groups"])

    risks_in_everyday_life = models.PositiveIntegerField(
        min=1,
        max=10,
        widget=widgets.SliderInput(),
        verbose_name=("In general, do you take more or less risks in everyday "
                      "life? ('1' = take less risk and '10' take more risk.)"))

    risks_in_financial_decision = models.PositiveIntegerField(
        min=1,
        max=10,
        widget=widgets.SliderInput(),
        default=5,
        verbose_name=
        (" In general, do you take more or less risks in financial decisions? "
         "life? ('1' = take less risk and '10' take more risk.)"))
Beispiel #14
0
class Session(ModelWithVars):
    class Meta:
        app_label = "otree"
        # if i don't set this, it could be in an unpredictable order
        ordering = ['pk']

    _pickle_fields = ['vars', 'config']
    config = models._PickleField(default=dict, null=True)  # type: dict

    # label of this session instance
    label = models.CharField(max_length=300,
                             null=True,
                             blank=True,
                             help_text='For internal record-keeping')

    experimenter_name = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='For internal record-keeping')

    ready = models.BooleanField(default=False)

    code = models.CharField(
        default=random_chars_8,
        max_length=16,
        # set non-nullable, until we make our CharField non-nullable
        null=False,
        unique=True,
        doc="Randomly generated unique identifier for the session.")

    mturk_HITId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk')
    mturk_HITGroupId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk')

    # since workers can drop out number of participants on server should be
    # greater than number of participants on mturk
    # value -1 indicates that this session it not intended to run on mturk
    mturk_num_participants = models.IntegerField(
        default=-1, help_text="Number of participants on MTurk")

    mturk_use_sandbox = models.BooleanField(
        default=True,
        help_text="Should this session be created in mturk sandbox?")

    archived = models.BooleanField(
        default=False,
        db_index=True,
        doc=("If set to True the session won't be visible on the "
             "main ViewList for sessions"))

    comment = models.TextField(blank=True)

    _anonymous_code = models.CharField(default=random_chars_10,
                                       max_length=10,
                                       null=False,
                                       db_index=True)

    _pre_create_id = models.CharField(max_length=255, db_index=True, null=True)

    use_browser_bots = models.BooleanField(default=False)

    # if the user clicks 'start bots' twice, this will prevent the bots
    # from being run twice.
    _cannot_restart_bots = models.BooleanField(default=False)
    _bots_finished = models.BooleanField(default=False)
    _bots_errored = models.BooleanField(default=False)
    _bot_case_number = models.PositiveIntegerField()

    is_demo = models.BooleanField(default=False)

    # whether SOME players are bots
    has_bots = models.BooleanField(default=False)

    _admin_report_app_names = models.TextField(default='')
    _admin_report_num_rounds = models.CharField(default='', max_length=255)

    num_participants = models.PositiveIntegerField()

    def __unicode__(self):
        return self.code

    @property
    def participation_fee(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['participation_fee']

    @property
    def real_world_currency_per_point(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['real_world_currency_per_point']

    def is_for_mturk(self):
        return (not self.is_demo) and (self.mturk_num_participants > 0)

    def get_subsessions(self):
        lst = []
        app_sequence = self.config['app_sequence']
        for app in app_sequence:
            models_module = otree.common_internal.get_models_module(app)
            subsessions = models_module.Subsession.objects.filter(
                session=self).order_by('round_number')
            lst.extend(list(subsessions))
        return lst

    def get_participants(self):
        return self.participant_set.all()

    def _create_groups_and_initialize(self):
        # group_by_arrival_time_time code used to be here
        for subsession in self.get_subsessions():
            subsession._create_groups()
            subsession.before_session_starts()
            subsession.creating_session()
            subsession.save()

    def mturk_requester_url(self):
        if self.mturk_use_sandbox:
            requester_url = (
                "https://requestersandbox.mturk.com/mturk/manageHITs")
        else:
            requester_url = "https://requester.mturk.com/mturk/manageHITs"
        return requester_url

    def mturk_worker_url(self):
        if self.mturk_use_sandbox:
            return ("https://workersandbox.mturk.com/mturk/preview?groupId={}"
                    ).format(self.mturk_HITGroupId)
        return ("https://www.mturk.com/mturk/preview?groupId={}").format(
            self.mturk_HITGroupId)

    def advance_last_place_participants(self):

        participants = self.get_participants()

        # in case some participants haven't started
        unvisited_participants = []
        for p in participants:
            if p._index_in_pages == 0:
                unvisited_participants.append(p)
                client.get(p._start_url(), follow=True)

        if unvisited_participants:
            # that's it -- just visit the start URL, advancing by 1
            return

        last_place_page_index = min([p._index_in_pages for p in participants])
        last_place_participants = [
            p for p in participants
            if p._index_in_pages == last_place_page_index
        ]

        for p in last_place_participants:
            try:
                current_form_page_url = p._current_form_page_url
                if current_form_page_url:
                    resp = client.post(
                        current_form_page_url,
                        data={
                            constants_internal.timeout_happened: True,
                            constants_internal.admin_secret_code:
                            ADMIN_SECRET_CODE
                        },
                        follow=True)
                    # not sure why, but many users are getting HttpResponseNotFound
                    if resp.status_code >= 400:
                        msg = ('Submitting page {} failed, '
                               'returned HTTP status code {}.'.format(
                                   current_form_page_url, resp.status_code))
                        content = resp.content
                        if len(content) < 600:
                            msg += ' response content: {}'.format(content)
                        raise AssertionError(msg)

                else:
                    # it's possible that the slowest user is on a wait page,
                    # especially if their browser is closed.
                    # because they were waiting for another user who then
                    # advanced past the wait page, but they were never
                    # advanced themselves.
                    start_url = p._start_url()
                    resp = client.get(start_url, follow=True)
            except:
                logging.exception("Failed to advance participants.")
                raise

            # do the auto-advancing here,
            # rather than in increment_index_in_pages,
            # because it's only needed here.
            channels.Group('auto-advance-{}'.format(p.code)).send(
                {'text': json.dumps({'auto_advanced': True})})

    def pages_auto_reload_when_advanced(self):
        # keep it enable until I determine
        # (a) the usefulness of the feature
        # (b) the impact on performance
        return True
        # return settings.DEBUG or self.is_demo

    def build_participant_to_player_lookups(self):
        subsession_app_names = self.config['app_sequence']

        views_modules = {}
        for app_name in subsession_app_names:
            views_modules[app_name] = (
                otree.common_internal.get_views_module(app_name))

        def views_module_for_player(player):
            return views_modules[player._meta.app_config.name]

        records_to_create = []

        for participant in self.get_participants():
            page_index = 0
            for player in participant.get_players():
                for View in views_module_for_player(player).page_sequence:
                    page_index += 1
                    records_to_create.append(
                        ParticipantToPlayerLookup(
                            participant=participant,
                            page_index=page_index,
                            app_name=player._meta.app_config.name,
                            player_pk=player.pk,
                            url=reverse(View.url_name(),
                                        args=[participant.code, page_index])))

            # technically could be stored at the session level
            participant._max_page_index = page_index
            participant.save()
        ParticipantToPlayerLookup.objects.bulk_create(records_to_create)

    def get_room(self):
        from otree.room import ROOM_DICT
        try:
            room_name = RoomToSession.objects.get(session=self).room_name
            return ROOM_DICT[room_name]
        except RoomToSession.DoesNotExist:
            return None

    def _get_payoff_plus_participation_fee(self, payoff):
        '''For a participant who has the given payoff,
        return their payoff_plus_participation_fee
        Useful to define it here, for data export
        '''

        return (self.config['participation_fee'] +
                payoff.to_real_world_currency(self))

    def _set_admin_report_app_names(self):

        admin_report_app_names = []
        num_rounds_list = []
        for app_name in self.config['app_sequence']:
            models_module = otree.common_internal.get_models_module(app_name)
            app_label = get_app_label_from_name(app_name)
            try:
                get_template('{}/AdminReport.html'.format(app_label))
                admin_report_app_names.append(app_name)
                num_rounds_list.append(models_module.Constants.num_rounds)
            except TemplateDoesNotExist:
                pass
        self._admin_report_app_names = ';'.join(admin_report_app_names)
        self._admin_report_num_rounds = ';'.join(
            str(n) for n in num_rounds_list)

    def _admin_report_apps(self):
        return self._admin_report_app_names.split(';')

    def _admin_report_num_rounds_list(self):
        return [int(num) for num in self._admin_report_num_rounds.split(';')]

    def has_admin_report(self):
        return bool(self._admin_report_app_names)
Beispiel #15
0
class Player(otree.models.BasePlayer):

    # <built-in>
    group = models.ForeignKey(Group, null=True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    player_name = models.CharField(max_length=255)
    avatar = models.CharField(max_length=255)

    virtual_oponent = models.CharField(max_length=255,
                                       choices=list(
                                           Constants.virtual_comb.keys()))

    n_simple_propuesta = models.CurrencyField(
        choices=range(0, 201),
        verbose_name="¿Cuánto le gustaría ofrecer?",
        default=0)
    n_simple_respuesta = models.CharField(
        widget=widgets.RadioSelectHorizontal(),
        max_length=250,
        choices=["Aceptar", "Rechazar"],
        default="Aceptar")

    n_empresa_trabajador_propuesta = models.CurrencyField(
        verbose_name="¿Cuánto le gustaría ofrecer como salario?",
        choices=range(0, 201),
        default=0)
    n_empresa_trabajador_propuestas = models.TextField(default="[]")

    n_empresa_trabajador_respuesta = models.CharField(
        widget=widgets.RadioSelectHorizontal(),
        max_length=250,
        choices=["Aceptar", "Rechazar"],
        default="Aceptar")
    n_empresa_trabajador_contrapropuesta = models.CurrencyField(
        verbose_name="Contraoferta de salario:",
        choices=range(0, 201),
        default=0)
    n_empresa_trabajador_contrapropuestas = models.TextField(default="[]")

    n_empresa_trabajador_finalizacion_forzada = models.BooleanField(
        default=False)

    def all_propuestas(self):
        return json.loads(self.n_empresa_trabajador_propuestas)

    def add_propuesta(self, v):
        lista = self.all_propuestas()
        lista.append(int(v))
        self.n_empresa_trabajador_propuestas = json.dumps(lista)

    def all_contrapropuestas(self):
        return json.loads(self.n_empresa_trabajador_contrapropuestas)

    def add_contrapropuesta(self, v):
        lista = self.all_contrapropuestas()
        lista.append(int(v))
        self.n_empresa_trabajador_contrapropuestas = json.dumps(lista)

    def role(self):
        if self.subsession.get_current_game() == Constants.n_simple:
            if self.id_in_group == 1:
                return Constants.proponente
            elif self.id_in_group == 2:
                return Constants.respondente
        elif self.subsession.get_current_game(
        ) == Constants.n_empresa_trabajador:
            if self.id_in_group == 1:
                return Constants.empresa
            elif self.id_in_group == 2:
                return Constants.trabajador

    def avatarb64(self):
        if not self.avatar:
            return Constants.default_avatar_b64
        if not hasattr(self, "_avatarb64"):
            path = os.path.join(settings.BASE_DIR, "participants_conf",
                                self.avatar)
            with open(path) as fp:
                self._avatarb64 = "data:image/{};base64,{}".format(
                    self.avatar.rsplit(".", 1)[1].lower(),
                    fp.read().encode("base64"))
        return self._avatarb64
Beispiel #16
0
class Session(ModelWithVars):
    class Meta:
        app_label = "otree"
        # if i don't set this, it could be in an unpredictable order
        ordering = ['pk']

    _pickle_fields = ['vars', 'config']
    config = models._PickleField(default=dict, null=True)  # type: dict

    # label of this session instance
    label = models.CharField(max_length=300,
                             null=True,
                             blank=True,
                             help_text='For internal record-keeping')

    experimenter_name = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='For internal record-keeping')

    ready_for_browser = models.BooleanField(default=False)

    code = models.CharField(
        default=random_chars_8,
        max_length=16,
        # set non-nullable, until we make our CharField non-nullable
        null=False,
        unique=True,
        doc="Randomly generated unique identifier for the session.")

    mturk_HITId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk')
    mturk_HITGroupId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk')

    # since workers can drop out number of participants on server should be
    # greater than number of participants on mturk
    # value -1 indicates that this session it not intended to run on mturk
    mturk_num_participants = models.IntegerField(
        default=-1, help_text="Number of participants on MTurk")

    mturk_use_sandbox = models.BooleanField(
        default=True,
        help_text="Should this session be created in mturk sandbox?")

    archived = models.BooleanField(
        default=False,
        db_index=True,
        doc=("If set to True the session won't be visible on the "
             "main ViewList for sessions"))

    comment = models.TextField(blank=True)

    _anonymous_code = models.CharField(default=random_chars_10,
                                       max_length=10,
                                       null=False,
                                       db_index=True)

    _pre_create_id = models.CharField(max_length=255, db_index=True, null=True)

    def use_browser_bots(self):
        return self.participant_set.filter(is_browser_bot=True).exists()

    is_demo = models.BooleanField(default=False)

    _admin_report_app_names = models.TextField(default='')
    _admin_report_num_rounds = models.CharField(default='', max_length=255)

    num_participants = models.PositiveIntegerField()

    def __unicode__(self):
        return self.code

    @property
    def participation_fee(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['participation_fee']

    @property
    def real_world_currency_per_point(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['real_world_currency_per_point']

    def is_for_mturk(self):
        return (not self.is_demo) and (self.mturk_num_participants > 0)

    def get_subsessions(self):
        lst = []
        app_sequence = self.config['app_sequence']
        for app in app_sequence:
            models_module = otree.common_internal.get_models_module(app)
            subsessions = models_module.Subsession.objects.filter(
                session=self).order_by('round_number')
            lst.extend(list(subsessions))
        return lst

    def get_participants(self):
        return list(self.participant_set.order_by('id_in_session'))

    def mturk_requester_url(self):
        subdomain = 'requestersandbox' if self.mturk_use_sandbox else 'requester'
        return "https://{}.mturk.com/mturk/manageHITs".format(subdomain)

    def mturk_worker_url(self):
        # different HITs
        # get the same preview page, because they are lumped into the same
        # "hit group". This is not documented, but it seems HITs are lumped
        # if a certain subset of properties are the same:
        # https://forums.aws.amazon.com/message.jspa?messageID=597622#597622
        # this seems like the correct design; the only case where this will
        # not work is if the HIT was deleted from the server, but in that case,
        # the HIT itself should be canceled.

        # 2018-06-04:
        # the format seems to have changed to this:
        # https://worker.mturk.com/projects/{group_id}/tasks?ref=w_pl_prvw
        # but the old format still works.
        # it seems I can't replace groupId by hitID, which i would like to do
        # because it's more precise.
        subdomain = "workersandbox" if self.mturk_use_sandbox else 'www'
        return "https://{}.mturk.com/mturk/preview?groupId={}".format(
            subdomain, self.mturk_HITGroupId)

    def advance_last_place_participants(self):
        # django.test takes 0.5 sec to import,
        # if this is done globally then it adds to each startup
        # it's only used here, and often isn't used at all.
        # so best to do it only here
        # it gets cached
        import django.test
        client = django.test.Client()

        participants = self.get_participants()

        # in case some participants haven't started
        unvisited_participants = []
        for p in participants:
            if p._index_in_pages == 0:
                unvisited_participants.append(p)
                client.get(p._start_url(), follow=True)

        if unvisited_participants:
            # that's it -- just visit the start URL, advancing by 1
            return

        last_place_page_index = min([p._index_in_pages for p in participants])
        last_place_participants = [
            p for p in participants
            if p._index_in_pages == last_place_page_index
        ]

        for p in last_place_participants:
            try:
                current_form_page_url = p._current_form_page_url
                if current_form_page_url:
                    resp = client.post(
                        current_form_page_url,
                        data={
                            constants_internal.timeout_happened: True,
                            constants_internal.admin_secret_code:
                            ADMIN_SECRET_CODE
                        },
                        follow=True)
                    # not sure why, but many users are getting HttpResponseNotFound
                    if resp.status_code >= 400:
                        msg = ('Submitting page {} failed, '
                               'returned HTTP status code {}.'.format(
                                   current_form_page_url, resp.status_code))
                        content = resp.content
                        if len(content) < 600:
                            msg += ' response content: {}'.format(content)
                        raise AssertionError(msg)

                else:
                    # it's possible that the slowest user is on a wait page,
                    # especially if their browser is closed.
                    # because they were waiting for another user who then
                    # advanced past the wait page, but they were never
                    # advanced themselves.
                    start_url = p._start_url()
                    resp = client.get(start_url, follow=True)
            except:
                logging.exception("Failed to advance participants.")
                raise

            # do the auto-advancing here,
            # rather than in increment_index_in_pages,
            # because it's only needed here.
            channels.Group('auto-advance-{}'.format(p.code)).send(
                {'text': json.dumps({'auto_advanced': True})})

    def get_room(self):
        from otree.room import ROOM_DICT
        try:
            room_name = RoomToSession.objects.get(session=self).room_name
            return ROOM_DICT[room_name]
        except RoomToSession.DoesNotExist:
            return None

    def _get_payoff_plus_participation_fee(self, payoff):
        '''For a participant who has the given payoff,
        return their payoff_plus_participation_fee
        Useful to define it here, for data export
        '''

        return (self.config['participation_fee'] +
                payoff.to_real_world_currency(self))

    def _set_admin_report_app_names(self):

        admin_report_app_names = []
        num_rounds_list = []
        for app_name in self.config['app_sequence']:
            models_module = otree.common_internal.get_models_module(app_name)
            app_label = get_app_label_from_name(app_name)
            try:
                get_template('{}/AdminReport.html'.format(app_label))
                admin_report_app_names.append(app_name)
                num_rounds_list.append(models_module.Constants.num_rounds)
            except TemplateDoesNotExist:
                pass
        self._admin_report_app_names = ';'.join(admin_report_app_names)
        self._admin_report_num_rounds = ';'.join(
            str(n) for n in num_rounds_list)

    def _admin_report_apps(self):
        return self._admin_report_app_names.split(';')

    def _admin_report_num_rounds_list(self):
        return [int(num) for num in self._admin_report_num_rounds.split(';')]

    def has_admin_report(self):
        return bool(self._admin_report_app_names)
Beispiel #17
0
class Player(otree.models.BasePlayer):

    # <built-in>
    group = models.ForeignKey(Group, null=True)
    subsession = models.ForeignKey(Subsession)
    # </built-in>

    gender = models.CharField(
        max_length=255, choices=['Female', 'Male', 'Other', 'Decline'],
        verbose_name="What gender do you identify with?",
        widget=widgets.RadioSelect())

    age = models.CharField(
        max_length=255,
        choices=[
            "under 18 years old", "18-20 years old", "21-22 years old",
            "23-25 years old", "over 25 years old"],
        verbose_name="What is your age?",
        widget=widgets.RadioSelect())

    ethnicity = models.TextField(
        widget=widgets.HiddenInput(),
        verbose_name="Which of the following BEST describes your ethnic background? Please TICK ALL THAT APPLY.")

    education_level = models.CharField(
        verbose_name=(
            "What is the highest degree or level of school you have completed?"
            " If currently enrolled, highest degree received."),
        max_length=255, widget=widgets.RadioSelect(),
        choices=[
            "High school graduate, diploma or the equivalent",
            "Some college credit, no degree",
            "Trade/technical/vocational training", "Bachelors degree",
            "Masters degree", "Other"])

    marital_status = models.CharField(
        verbose_name="What is your marital status?",
        choices=[
            "Single, never married", "Married or domestic partnership",
            "Other"],
        max_length=255, widget=widgets.RadioSelect())

    employment_status = models.CharField(
        verbose_name="What is your current employment status?",
        widget=widgets.RadioSelect(), max_length=255,
        choices=["no-job", "part-time", "full-time"])

    student_status = models.CharField(
        verbose_name=(
            "What is your current student status at the University of Guelph?"),
        widget=widgets.RadioSelect(), max_length=255,
        choices=["part-time", "full-time", "co-op", "other"])

    enrolled_type = models.CharField(
        verbose_name=(
            "What type of program are you enrolled in at the University of Guelph?"),
        widget=widgets.RadioSelect(), max_length=255,
        choices=["undergraduate degree", "graduate degree", "other"])
        
        
        
    major_type = models.CharField(
        verbose_name=(
           "Which College at the University of Guelph are you registered with?"),
       widget=widgets.RadioSelect(), max_length=255,
       choices=[" College of Business and Economics", "College of Physical and Engineering Science",  "College of Social and Applied Human Sciences","Ontario Agricultural College","Other"])


    class_type = models.CharField(
        verbose_name=(
            "How many Business and Economics classes have you taken so far (including those you are currently taking)?"),
        widget=widgets.RadioSelect(), max_length=255,
        choices=["0","Between 1 and 2", "Between 3 and 5", "Between 6 and 10", "More than 10"])


    auction_buy = models.CharField(
        verbose_name="Do you typically use auctions to buy goods?",
        widget=widgets.RadioSelect(), max_length=255,
        choices=["never", "occasionally", "frequently"])

    auctions_experience = models.CharField(
        verbose_name="How would you rate you previous experience with auctions?",
        widget=widgets.RadioSelect(), max_length=255,
        choices=[
            "no previous experience with auctions",
            "occasional use of auctions", "frequent use of auctions"])
            
    competitive_type = models.CharField(
        verbose_name=(
          "Evaluate the following statement: `When I play games for enjoyment, winning is very important to me' "),
        widget=widgets.RadioSelect(), max_length=255,
        choices=["I strongly disagree", "I disagree", "I neither disagree or agree", "I agree", "I strongly agree"])

            
            
           

    gamble = models.PositiveIntegerField(min=1, max=6)
Beispiel #18
0
class Session(ModelWithVars):
    class Meta:
        # if i don't set this, it could be in an unpredictable order
        ordering = ['pk']
        app_label = "otree"

    config = models.JSONField(
        default=dict,
        null=True,
        doc=("the session config dict, as defined in the "
             "programmer's settings.py."))

    # label of this session instance
    label = models.CharField(max_length=300,
                             null=True,
                             blank=True,
                             help_text='For internal record-keeping')

    experimenter_name = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='For internal record-keeping')

    code = models.RandomCharField(
        length=8, doc="Randomly generated unique identifier for the session.")

    time_scheduled = models.DateTimeField(
        null=True,
        doc="The time at which the session is scheduled",
        help_text='For internal record-keeping',
        blank=True)

    time_started = models.DateTimeField(
        null=True,
        doc="The time at which the experimenter started the session")

    mturk_HITId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk')
    mturk_HITGroupId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk')
    mturk_qualification_type_id = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Qualification type that is '
        'assigned to each worker taking hit')

    # since workers can drop out number of participants on server should be
    # greater than number of participants on mturk
    # value -1 indicates that this session it not intended to run on mturk
    mturk_num_participants = models.IntegerField(
        default=-1, help_text="Number of participants on MTurk")

    mturk_sandbox = models.BooleanField(
        default=True,
        help_text="Should this session be created in mturk sandbox?")

    archived = models.BooleanField(
        default=False,
        doc=("If set to True the session won't be visible on the "
             "main ViewList for sessions"))

    git_commit_timestamp = models.CharField(
        max_length=200,
        null=True,
        doc=(
            "Indicates the version of the code (as recorded by Git) that was "
            "used to run the session, so that the session can be replicated "
            "later.\n Search through the Git commit log to find a commit that "
            "was made at this time."))

    comment = models.TextField(blank=True)

    _ready_to_play = models.BooleanField(default=False)

    _anonymous_code = models.RandomCharField(length=10)

    special_category = models.CharField(
        max_length=20,
        null=True,
        doc="whether it's a test session, demo session, etc.")

    # whether someone already viewed this session's demo links
    demo_already_used = models.BooleanField(default=False)

    # indicates whether a session has been fully created (not only has the
    # model itself been created, but also the other models in the hierarchy)
    ready = models.BooleanField(default=False)

    _pre_create_id = models.CharField(max_length=300, null=True)

    def __unicode__(self):
        return self.code

    @property
    def participation_fee(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['participation_fee']

    @property
    def real_world_currency_per_point(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['real_world_currency_per_point']

    @property
    def session_type(self):
        '''2015-07-10: session_type is deprecated
        this shim method will be removed eventually'''
        return self.config

    def is_open(self):
        return GlobalSingleton.objects.get().default_session == self

    def is_for_mturk(self):
        return (not self.is_demo()) and (self.mturk_num_participants > 0)

    def is_demo(self):
        return (self.special_category ==
                constants_internal.session_special_category_demo)

    def subsession_names(self):
        names = []
        for subsession in self.get_subsessions():
            app_name = subsession._meta.app_config.name
            name = '{} {}'.format(
                otree.common_internal.app_name_format(app_name),
                subsession.name())
            names.append(name)
        if names:
            return ', '.join(names)
        else:
            return '[empty sequence]'

    def get_subsessions(self):
        lst = []
        app_sequence = self.config['app_sequence']
        for app in app_sequence:
            models_module = otree.common_internal.get_models_module(app)
            subsessions = models_module.Subsession.objects.filter(
                session=self).order_by('round_number')
            lst.extend(list(subsessions))
        return lst

    def delete(self, using=None):
        for subsession in self.get_subsessions():
            subsession.delete()
        super(Session, self).delete(using)

    def get_participants(self):
        return self.participant_set.all()

    def payments_ready(self):
        for participants in self.get_participants():
            if not participants.payoff_is_complete():
                return False
        return True

    payments_ready.boolean = True

    def _create_groups_and_initialize(self):
        # if ppg is None, then the arrival time doesn't matter because
        # everyone is assigned to one big group.
        # otherwise, even in single-player games, you would have to wait
        # for other players to arrive
        # the drawback of this approach is that id_in_group is
        # predetermined, rather than by arrival time.
        # alternative design:
        # instead of checking ppg, we could also check if the game
        # contains a wait page
        # another alternative:
        # allow players to start even if the rest of the group hasn't arrived
        # but this might break some assumptions such as len(grp.get_players())
        # also, what happens if you get to the next round before
        # another player has started the first? you can't clone the
        # previous round's groups
        for subsession in self.get_subsessions():
            cond = (self.config.get('group_by_arrival_time')
                    and subsession._Constants.players_per_group is not None)
            if cond:
                if subsession.round_number == 1:
                    subsession._set_players_per_group_list()
                subsession._create_empty_groups()
            else:
                subsession._create_groups()
            subsession._initialize()
            subsession.save()
        self._ready_to_play = True
        # assert self is subsession.session
        self.save()

    def mturk_requester_url(self):
        if self.mturk_sandbox:
            requester_url = (
                "https://requestersandbox.mturk.com/mturk/manageHITs")
        else:
            requester_url = "https://requester.mturk.com/mturk/manageHITs"
        return requester_url

    def mturk_worker_url(self):
        if self.mturk_sandbox:
            worker_url = (
                "https://workersandbox.mturk.com/mturk/preview?groupId={}"
            ).format(self.mturk_HITGroupId)
        else:
            worker_url = (
                "https://www.mturk.com/mturk/preview?groupId={}").format(
                    self.mturk_HITGroupId)
        return worker_url

    def advance_last_place_participants(self):
        participants = self.get_participants()

        c = django.test.Client()

        # in case some participants haven't started
        some_participants_not_visited = False
        for p in participants:
            if not p.visited:
                some_participants_not_visited = True
                c.get(p._start_url(), follow=True)

        if some_participants_not_visited:
            # refresh from DB so that _current_form_page_url gets set
            participants = self.participant_set.all()

        last_place_page_index = min([p._index_in_pages for p in participants])
        last_place_participants = [
            p for p in participants
            if p._index_in_pages == last_place_page_index
        ]

        for p in last_place_participants:
            # what if current_form_page_url hasn't been set yet?
            resp = c.post(p._current_form_page_url,
                          data={constants_internal.auto_submit: True},
                          follow=True)
            assert resp.status_code < 400

    def build_session_user_to_user_lookups(self):
        subsession_app_names = self.config['app_sequence']

        num_pages_in_each_app = {}
        for app_name in subsession_app_names:
            views_module = otree.common_internal.get_views_module(app_name)

            num_pages = len(views_module.page_sequence)
            num_pages_in_each_app[app_name] = num_pages

        for participant in self.get_participants():
            participant.build_session_user_to_user_lookups(
                num_pages_in_each_app)
Beispiel #19
0
class Session(ModelWithVars):
    class Meta:
        app_label = "otree"
        # if i don't set this, it could be in an unpredictable order
        ordering = ['pk']

    config = models.JSONField(default=dict, null=True)  # type: dict
    vars = models.JSONField(default=dict)  # type: dict

    # label of this session instance
    label = models.CharField(max_length=300,
                             null=True,
                             blank=True,
                             help_text='For internal record-keeping')

    experimenter_name = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='For internal record-keeping')

    ready = models.BooleanField(default=False)

    code = models.CharField(
        default=random_chars_8,
        max_length=16,
        # set non-nullable, until we make our CharField non-nullable
        null=False,
        unique=True,
        doc="Randomly generated unique identifier for the session.")

    time_scheduled = models.DateTimeField(
        null=True,
        doc="The time at which the session is scheduled",
        help_text='For internal record-keeping',
        blank=True)

    time_started = models.DateTimeField(
        null=True,
        doc="The time at which the experimenter started the session")

    mturk_HITId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk')
    mturk_HITGroupId = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Hit id for this session on MTurk')
    mturk_qualification_type_id = models.CharField(
        max_length=300,
        null=True,
        blank=True,
        help_text='Qualification type that is '
        'assigned to each worker taking hit')

    # since workers can drop out number of participants on server should be
    # greater than number of participants on mturk
    # value -1 indicates that this session it not intended to run on mturk
    mturk_num_participants = models.IntegerField(
        default=-1, help_text="Number of participants on MTurk")

    mturk_sandbox = models.BooleanField(
        default=True,
        help_text="Should this session be created in mturk sandbox?")

    archived = models.BooleanField(
        default=False,
        db_index=True,
        doc=("If set to True the session won't be visible on the "
             "main ViewList for sessions"))

    comment = models.TextField(blank=True)

    _anonymous_code = models.CharField(default=random_chars_10,
                                       max_length=10,
                                       null=False,
                                       db_index=True)

    _pre_create_id = models.CharField(max_length=300, db_index=True, null=True)

    use_browser_bots = models.BooleanField(default=False)

    # if the user clicks 'start bots' twice, this will prevent the bots
    # from being run twice.
    _cannot_restart_bots = models.BooleanField(default=False)
    _bots_finished = models.BooleanField(default=False)
    _bots_errored = models.BooleanField(default=False)
    _bot_case_number = models.PositiveIntegerField()

    is_demo = models.BooleanField(default=False)

    # whether SOME players are bots
    has_bots = models.BooleanField(default=False)

    def __unicode__(self):
        return self.code

    @property
    def participation_fee(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['participation_fee']

    @property
    def real_world_currency_per_point(self):
        '''This method is deprecated from public API,
        but still useful internally (like data export)'''
        return self.config['real_world_currency_per_point']

    def is_for_mturk(self):
        return (not self.is_demo) and (self.mturk_num_participants > 0)

    def get_subsessions(self):
        lst = []
        app_sequence = self.config['app_sequence']
        for app in app_sequence:
            models_module = otree.common_internal.get_models_module(app)
            subsessions = models_module.Subsession.objects.filter(
                session=self).order_by('round_number')
            lst.extend(list(subsessions))
        return lst

    def delete(self, using=None):
        for subsession in self.get_subsessions():
            subsession.delete()
        super(Session, self).delete(using)

    def get_participants(self):
        return self.participant_set.all()

    def get_human_participants(self):
        return self.participant_set.filter(_is_bot=False)

    def _create_groups_and_initialize(self):
        # group_by_arrival_time code used to be here
        for subsession in self.get_subsessions():
            subsession._create_groups()
            subsession.before_session_starts()
            subsession.save()

    def mturk_requester_url(self):
        if self.mturk_sandbox:
            requester_url = (
                "https://requestersandbox.mturk.com/mturk/manageHITs")
        else:
            requester_url = "https://requester.mturk.com/mturk/manageHITs"
        return requester_url

    def mturk_worker_url(self):
        if self.mturk_sandbox:
            return ("https://workersandbox.mturk.com/mturk/preview?groupId={}"
                    ).format(self.mturk_HITGroupId)
        return ("https://www.mturk.com/mturk/preview?groupId={}").format(
            self.mturk_HITGroupId)

    def advance_last_place_participants(self):

        # can't auto-advance bots, because that could break their
        # pre-determined logic
        # consider pros/cons of doing this
        participants = self.get_human_participants()

        # in case some participants haven't started
        unvisited_participants = []
        for p in participants:
            if p._index_in_pages == 0:
                unvisited_participants.append(p)
                client.get(p._start_url(), follow=True)

        if unvisited_participants:
            # that's it -- just visit the start URL, advancing by 1
            return

        last_place_page_index = min([p._index_in_pages for p in participants])
        last_place_participants = [
            p for p in participants
            if p._index_in_pages == last_place_page_index
        ]

        for p in last_place_participants:
            # what if first page is wait page?
            # that shouldn't happen, because then they must be
            # waiting for some other players who are even further back
            assert p._current_form_page_url
            try:
                resp = client.post(p._current_form_page_url,
                                   data={constants_internal.auto_submit: True},
                                   follow=True)
            except:
                logging.exception("Failed to advance participants.")
                raise

            assert resp.status_code < 400

    def build_participant_to_player_lookups(self):
        subsession_app_names = self.config['app_sequence']

        views_modules = {}
        for app_name in subsession_app_names:
            views_modules[app_name] = (
                otree.common_internal.get_views_module(app_name))

        def views_module_for_player(player):
            return views_modules[player._meta.app_config.name]

        records_to_create = []

        for participant in self.get_participants():
            page_index = 0
            for player in participant.get_players():
                for View in views_module_for_player(player).page_sequence:
                    page_index += 1
                    records_to_create.append(
                        ParticipantToPlayerLookup(
                            participant=participant,
                            page_index=page_index,
                            app_name=player._meta.app_config.name,
                            player_pk=player.pk,
                            url=reverse(View.url_name(),
                                        args=[participant.code, page_index])))

            # technically could be stored at the session level
            participant._max_page_index = page_index
            participant.save()
        ParticipantToPlayerLookup.objects.bulk_create(records_to_create)

    def get_room(self):
        from otree.room import ROOM_DICT
        try:
            room_name = RoomToSession.objects.get(session=self).room_name
            return ROOM_DICT[room_name]
        except RoomToSession.DoesNotExist:
            return None
Beispiel #20
0
class Player(BasePlayer):
    transcribed_text = models.TextField()
    levenshtein_distance = models.PositiveIntegerField()