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)
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)
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)
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)
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))
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)