Example #1
0
def start_exp(exp_name):
    """ Serves up the experiment applet. 
    If experiment is ongoing or completed, will not serve. 

    Querystring args (required):
    token: External token
    """

    if not utils.check_qs(request.args, ['token']):
        raise ExperimentError('improper_inputs')
    else:
        token = request.args['token']

    if current_app.config['DEVELOPMENT'] is True:
        refer = 'https://agile-ratio-824.appspot.com/'
    else:
        refer = 'https://co-twins.appspot.com/'

    current_app.logger.info("Referrer: %s" % (request.referrer))

    browser, platform = utils.check_browser_platform(request.user_agent)
    uas = request.user_agent.string

    if (platform == 'android') \
    or (platform == 'iphone') \
    or (platform == 'windows' and re.search('Windows Phone OS', uas)) \
    or (browser == 'opera') \
    or (re.search('BlackBerry', uas)):
        raise ExperimentError('browser_type_not_allowed')

    current_app.logger.info(
        "Subject: %s entered with %s platform and %s browser" %
        (token, platform, browser))

    session = Session(token=token,
                      browser=browser,
                      platform=platform,
                      status=1,
                      exp_name=exp_name,
                      begin_session=datetime.datetime.now())
    db.session.add(session)
    db.session.commit()

    return render_template(exp_name + "/exp.html",
                           experimentname=exp_name,
                           sessionid=session.session_id,
                           debug=current_app.config['EXP_DEBUG'],
                           uniqueid=token,
                           refer=refer)
Example #2
0
def quitter():
    """ Mark quitter as such. """
    if not utils.check_qs(request.form, ['sessionid']):
        resp = {"status": "bad request"}

    else:
        session_id = request.form['sessionid']

        try:
            # pull records from Session table to update
            session = Session.query.filter(
                Session.session_id == session_id).one()
            session.status = 6
            db.session.commit()
            resp = {"status": "marked as quitter"}

        except SQLAlchemyError:
            resp = {"status": "bad request"}

    return jsonify(**resp)
Example #3
0
def enterexp():
    """
    AJAX listener that listens for a signal from the user's script when they
    leave the instructions and enter the real experiment. After the server
    receives this signal, it will no longer allow them to re-access the
    experiment applet (meaning they can't do part of the experiment and
    refresh to start over). This changes the current sessions's status to 2.

    Querystring args (required):
    uniqueid: External gfg_id
    experimentname: Which experiment to serve
    sessionid: session identifier
    """

    if not utils.check_qs(request.form, ['sessionid']):
        raise ExperimentError('improper_inputs')
    else:
        session_id = request.form['sessionid']

    session = Session.query.filter_by(session_id=session_id).first()

    if session:
        session.status = 2
        session.begin_experiment = datetime.datetime.now()
        db.session.commit()

        current_app.logger.info(
            "User has finished the instructions in session id: %s, experiment name: %s",
            session_id, session.exp_name)
        resp = {"status": "success"}
    else:
        current_app.logger.error(
            "DB error: Unique user and experiment combination not found.")
        # it is the dictionary
        resp = {"status": "error, session not found"}

    return jsonify(**resp)
Example #4
0
def worker_complete():
    """Complete worker."""

    if not utils.check_qs(request.form, ['sessionid']):
        resp = {"status": "bad request"}
    else:
        session_id = request.form['sessionid']
        current_app.logger.info("Completed experiment %s" % (session_id))
        try:
            # pull records from Session table to update
            session = Session.query.filter(
                Session.session_id == session_id).one()
            session.status = 3
            db.session.commit()
            resp = {"status": "marked as done"}
            current_app.logger.info("Subject: %s marked as done" %
                                    str(session.token))

        except SQLAlchemyError:
            raise ExperimentError('unknown_error',
                                  session_id=request.args['sessionid'])
            resp = {"status": "db error"}

        return jsonify(**resp)
Example #5
0
def start_exp():
    """ Serves up the experiment applet. 
    If experiment is ongoing or completed, will not serve. 

    Querystring args (required):
    uniqueid: External gfg_id
    surveyid: Which experiment to serve
    """

    browser, platform = utils.check_browser_platform(request.user_agent)

    # Check query string
    if not utils.check_qs(request.args, ['uniqueid', 'surveyid']):
        raise ExperimentError('improper_inputs')
    else:
        uniqueid = request.args['uniqueid']
        survey_id = request.args['surveyid']
        exp_name = experiment_list[
            request.args['surveyid']]  # Survey id to experiment name

    # Decrypt encocded uniqueid
    gfg_id = utils.decrypt(str(current_app.config['SECRET_KEY']),
                           str(uniqueid).decode('string-escape'))

    # Check if user exists in main gfg db
    if not db_utils.gfg_user_exists(gfg_id,
                                    current_app.config['RESEARCH_DB_HOST'],
                                    current_app.config['RESEARCH_DB_USER'],
                                    current_app.config['RESEARCH_DB_PASSWORD'],
                                    current_app.config['RESEARCH_DB_NAME']):
        raise ExperimentError('user_access_denied')

    # Check if user is in Participant table, if not add & commit
    user, new_user = db_utils.get_or_create(db.session,
                                            Participant,
                                            gfg_id=gfg_id)

    current_app.logger.info(
        "Subject: %s entered with %s platform and %s browser" %
        (gfg_id, platform, browser))

    # If any existing sessions disqualify user (ongoing or completed), throw error
    # Otherwise, create new session and serve experiment
    disqualifying_sessions = Session.query.filter_by(gfg_id=gfg_id,
                                                     exp_name=exp_name,
                                                     status=3).first()
    if disqualifying_sessions and current_app.config['EXP_DEBUG'] == False:
        raise ExperimentError('already_did_exp',
                              session_id=disqualifying_sessions.session_id)

    # Otherwise, allow participant to re-enter
    else:
        session = Session(gfg_id=gfg_id,
                          browser=browser,
                          platform=platform,
                          status=1,
                          exp_name=exp_name,
                          begin_session=datetime.datetime.now())
        db.session.add(session)
        db.session.commit()

        return render_template(exp_name + "/exp.html",
                               experimentname=exp_name,
                               surveyid=survey_id,
                               sessionid=session.session_id,
                               debug=current_app.config['EXP_DEBUG'],
                               uniqueid=urllib.quote(uniqueid))
Example #6
0
def results():
    """Return results at the end."""
    if not utils.check_qs(request.args, ['uniqueid', 'surveyid']):
        raise ExperimentError('improper_inputs')
    else:
        uniqueid = request.args['uniqueid']
        survey_id = request.args['surveyid']
        exp_name = experiment_list[request.args['surveyid']]
        content_only = request.args.has_key('content_only')

    current_app.logger.info(
        "Results: uniqueid is  %s, exp_name is %s and survey id is %s" %
        (uniqueid, exp_name, survey_id))
    ## Get last session with code 3 from user
    gfg_id = utils.decrypt(str(current_app.config['SECRET_KEY']),
                           str(uniqueid))
    current_app.logger.info("GFG id after decrypt is -- %s" % (gfg_id))

    try:
        session = Session.query.filter_by(
            gfg_id=gfg_id, status=3,
            exp_name=exp_name).order_by(Session.session_id.desc()).first()
    except SQLAlchemyError:
        raise ExperimentError('user_access_denied')

    if session is None:
        raise ExperimentError('user_access_denied')
    elif session.exp_name == "keep_track":
        exp_display_name = "Working Memory"
        target_trials = KeepTrack.query.filter(
            KeepTrack.session_id == session.session_id,
            KeepTrack.block.in_(["1", "2", "3", "4", "5", "6"])).all()

        all_scored = []
        for trial in target_trials:
            score = trial.simple_score()
            all_scored += score
            current_app.logger.info(
                "trial score: %s, block: %s, inwords: %s" %
                (str(score), trial.block, str(trial.input_words)))

        ## This first value should be stored
        score = (sum(all_scored) / (len(all_scored) / 100.0))

    elif session.exp_name == "category_switch":
        exp_display_name = "Category Switch"
        single_trials_avg = db.session.query(
            func.avg(CategorySwitch.reaction_time).label('average')).filter(
                CategorySwitch.session_id == session.session_id,
                CategorySwitch.block.in_(["sizeReal", "livingReal"]),
                CategorySwitch.accuracy == 1).all()
        mixed_trials_avg = db.session.query(
            func.avg(CategorySwitch.reaction_time).label('average')).filter(
                CategorySwitch.session_id == session.session_id,
                CategorySwitch.block.in_(["mixedReal1", "mixedReal2"]),
                CategorySwitch.accuracy == 1).all()

        ## This value also needs to be stored
        score = mixed_trials_avg[0][0] - single_trials_avg[0][0]

    ## JAKE: You'd need to add another elif for your task. This is probably not the best way to code this but oh well
    ## Probably would be good to have the scoring functions all in one file and just call the right function for the git
    ## task, but lets leave that for later

    session.results = score
    db.session.commit()

    ## Find other people in same age range. If more than 20, calculate percentile and display
    age_matched_ids = db_utils.get_age_matched_ids(
        gfg_id, current_app.config['RESEARCH_DB_HOST'],
        current_app.config['RESEARCH_DB_USER'],
        current_app.config['RESEARCH_DB_PASSWORD'],
        current_app.config['RESEARCH_DB_NAME'])

    finished_matched_sessions = Session.query.filter(
        Session.gfg_id.in_(age_matched_ids),
        Session.exp_name == session.exp_name, Session.status == 3).all()

    if len(finished_matched_sessions) > 2:
        mean_score = db.session.query(
            func.avg(Session.results).label('average')).filter(
                Session.gfg_id.in_(age_matched_ids),
                Session.exp_name == session.exp_name,
                Session.status == 3).all()

        std_score = db.session.query(func.STD(
            Session.results).label('std')).filter(
                Session.gfg_id.in_(age_matched_ids),
                Session.exp_name == session.exp_name,
                Session.status == 3).all()

        percentile = stats.z2p(
            (score - mean_score[0][0]) / (std_score[0][0] + 0.00000001))
        percentile = percentile * 100

        current_app.logger.info(
            "mean: %d, std: %d; percentile: %d" %
            (mean_score[0][0], std_score[0][0], percentile))
    else:
        percentile = None

    return render_template(session.exp_name + "/results.html",
                           score=score,
                           percentile=percentile,
                           exp_display_name=exp_display_name,
                           content_only=content_only)