Esempio n. 1
0
 def post(self, request, code):
     session = db.get_or_404(Session, code=code)
     # background task because it makes http requests,
     # so it will need its own lock.
     session.advance_last_place_participants()
     # task = BackgroundTask(session.advance_last_place_participants)
     return Response('ok')
Esempio n. 2
0
 def get(self, request: Request):
     anonymous_code = request.path_params['anonymous_code']
     session = db.get_or_404(Session, _anonymous_code=anonymous_code)
     label = request.query_params.get('participant_label')
     participant = participant_or_none_if_exceeded(session, label=label)
     if not participant:
         return no_participants_left_http_response()
     return RedirectResponse(participant._start_url())
Esempio n. 3
0
    def post(self, request, code):
        session = db.get_or_404(Session, code=code)
        successful_payments = 0
        failed_payments = 0
        post_data = self.get_post_data()
        mturk_client = get_mturk_client(use_sandbox=session.mturk_use_sandbox)
        payment_page_response = self.redirect('MTurkSessionPayments', code=session.code)
        # use worker ID instead of assignment ID. Because 2 workers can have
        # the same assignment (if 1 starts it then returns it). we can't really
        # block that.
        # however, we can ensure that 1 worker does not get 2 assignments,
        # by enforcing that the same worker is always assigned to the same participant.
        participants = session.pp_set.filter(
            Participant.mturk_worker_id.in_(post_data.getlist('workers'))
        )

        for p in participants:
            # need the try/except so that we try to pay the rest of the participants
            payoff = p.payoff_in_real_world_currency()

            try:
                if payoff > 0:
                    mturk_client.send_bonus(
                        WorkerId=p.mturk_worker_id,
                        AssignmentId=p.mturk_assignment_id,
                        BonusAmount='{0:.2f}'.format(Decimal(payoff)),
                        # prevent duplicate payments
                        UniqueRequestToken='{}_{}'.format(
                            p.mturk_worker_id, p.mturk_assignment_id
                        ),
                        # this field is required.
                        Reason='Thank you',
                    )
                # approve assignment should happen AFTER bonus, so that if bonus fails,
                # the user will still show up in assignments_not_reviewed.
                # worst case is that bonus succeeds but approval fails.
                # in that case, exception will be raised on send_bonus because of UniqueRequestToken.
                # but that's OK, then you can just unselect that participant and pay the others.
                mturk_client.approve_assignment(AssignmentId=p.mturk_assignment_id)
                successful_payments += 1
            except Exception as e:
                msg = (
                    'Could not pay {} because of an error communicating '
                    'with MTurk: {}'.format(p._numeric_label(), str(e))
                )
                enqueue_admin_message('error', msg)
                logger.error(msg)
                failed_payments += 1
                if failed_payments > 10:
                    return payment_page_response
        msg = 'Successfully made {} payments.'.format(successful_payments)
        if failed_payments > 0:
            msg += ' {} payments failed.'.format(failed_payments)
            enqueue_admin_message('warning', msg)
        else:
            enqueue_admin_message('success', msg)
        return payment_page_response
Esempio n. 4
0
    def get(self, request: Request):
        """anything essential should be done in """
        code = request.path_params['code']
        pp = db.get_or_404(Participant, code=code)
        label = request.query_params.get(otree.constants.participant_label)

        pp.initialize(label)

        first_url = pp._url_i_should_be_on()
        return RedirectResponse(first_url)
Esempio n. 5
0
 def post(self, request, code):
     session = db.get_or_404(Session, code=code)
     with MTurkClient(
         use_sandbox=session.mturk_use_sandbox, request=request
     ) as mturk_client:
         expiration = datetime(2015, 1, 1)
         mturk_client.update_expiration_for_hit(
             HITId=session.mturk_HITId,
             # If you update it to a time in the past,
             # the HIT will be immediately expired.
             ExpireAt=expiration,
         )
         session.mturk_expiration = expiration.timestamp()
     # don't need a message because the MTurkCreateHIT page will
     # statically say the HIT has expired.
     return self.redirect('MTurkCreateHIT', code=code)
Esempio n. 6
0
    def get(self, request):
        code = request.path_params['code']
        participant = db.get_or_404(Participant, code=code)
        if participant.is_browser_bot:
            session = participant.session
            has_next_submission = browser_bots.enqueue_next_post_data(
                participant_code=participant.code)

            if has_next_submission:
                msg = ('Finished the last page, '
                       'but the bot is still trying '
                       'to submit more pages.')
                raise BotError(msg)

            browser_bots.send_completion_message(session_code=session.code,
                                                 participant_code=code)

        return render('otree/OutOfRangeNotification.html', {})
Esempio n. 7
0
    def post(self, request, code):
        session = db.get_or_404(Session, code=code)
        with MTurkClient(
            use_sandbox=session.mturk_use_sandbox, request=request
        ) as mturk_client:
            for p in session.pp_set.filter(
                Participant.mturk_worker_id.in_(self.get_post_data().getlist('workers'))
            ):
                mturk_client.reject_assignment(
                    AssignmentId=p.mturk_assignment_id,
                    # The boto3 docs say this param is optional, but if I omit it, I get:
                    # An error occurred (ValidationException) when calling the RejectAssignment operation:
                    # 1 validation error detected: Value null at 'requesterFeedback'
                    # failed to satisfy constraint: Member must not be null
                    RequesterFeedback='',
                )

            enqueue_admin_message('success', "Rejected the selected assignments")
        return self.redirect('MTurkSessionPayments', code=code)
Esempio n. 8
0
    async def dispatch(self) -> None:
        self.request = request = Request(self.scope, receive=self.receive)
        participant_code = request.path_params['participant_code']
        msg = (
            "This user does not exist in the database. " "Maybe the database was reset."
        )
        participant = db.get_or_404(Participant, code=participant_code, msg=msg)

        # if the player tried to skip past a part of the subsession
        # (e.g. by typing in a future URL)
        # or if they hit the back button to a previous subsession
        # in the sequence.
        url_should_be_on = participant._url_i_should_be_on()
        if not request.url.path == url_should_be_on:
            response = RedirectResponse(url_should_be_on, status_code=302)
        else:
            self.set_attributes(participant)
            response = await run_in_threadpool(self.inner_dispatch, request)
            # response = self.inner_dispatch(request)
        await response(self.scope, self.receive, self.send)
Esempio n. 9
0
 def inner_dispatch(self, request):
     self.session = db.get_or_404(Session, code=request.path_params['code'])
     return super().inner_dispatch(request)
Esempio n. 10
0
    def get(self, request: Request):
        code = request.path_params['code']
        session = self.session = db.get_or_404(Session, code=code)
        GET = request.query_params
        try:
            assignment_id = GET['assignmentId']
            worker_id = GET['workerId']
        except KeyError:
            return Response(
                'URL is missing assignmentId or workerId parameter',
                status_code=404)
        qual_id = session.config['mturk_hit_settings'].get(
            'grant_qualification_id')
        use_sandbox = session.mturk_use_sandbox
        if qual_id and not use_sandbox:
            # this is necessary because MTurk's qualification requirements
            # don't prevent 100% of duplicate participation. See:
            # https://groups.google.com/forum/#!topic/otree/B66HhbFE9ck

            previous_participation = (dbq(Participant).join(Session).filter(
                Participant.session != session,
                Session.mturk_qual_id == qual_id,
                Participant.mturk_worker_id == worker_id,
            ).scalar() is not None)
            if previous_participation:
                return Response('You have already accepted a related HIT')

            # if using sandbox, there is no point in granting quals.
            # https://groups.google.com/forum/#!topic/otree/aAmqTUF-b60

            # don't pass request arg, because we don't want to show a message.
            # using the fully qualified name because that seems to make mock.patch work
            mturk_client = otree.views.mturk.get_mturk_client(
                use_sandbox=use_sandbox)

            # seems OK to assign this multiple times
            mturk_client.associate_qualification_with_worker(
                QualificationTypeId=qual_id,
                WorkerId=worker_id,
                # Mturk complains if I omit IntegerValue
                IntegerValue=1,
            )

        try:
            # just check if this worker already game, but
            # don't filter for assignment, because maybe they already started
            # and returned the previous assignment
            # in this case, we should assign back to the same participant
            # so that we don't get duplicates in the DB, and so people
            # can't snoop and try the HIT first, then re-try to get a bigger bonus
            pp = self.session.pp_set.filter_by(mturk_worker_id=worker_id).one()
        except NoResultFound:
            pp = self.session.pp_set.filter_by(
                visited=False).order_by('id').first()
            if not pp:
                return no_participants_left_http_response()

            # 2014-10-17: needs to be here even if it's also set in
            # the next view to prevent race conditions
            # this needs to be inside the lock
            pp.visited = True
            pp.mturk_worker_id = worker_id
        # reassign assignment_id, even if they are returning, because maybe they accepted
        # and then returned, then re-accepted with a different assignment ID
        # if it's their second time
        pp.mturk_assignment_id = assignment_id
        return RedirectResponse(pp._start_url(), status_code=302)