Пример #1
0
def customError():

    # Check message
    msg = request.args.get("msg", None)
    if msg is None or msg == "":
        error_msg = "User requested a custom error page without message"
        logger.error(error_msg)
        raise FrontEndException()

    error_msg = "User requested a custom error page with message: {0}".format(
        msg)
    logger.error(error_msg)
    raise FrontEndException(msg)
Пример #2
0
def survey():

    # Check referer and session
    if not checkReferer("iat", request.headers) or not checkSession(session):
        return flask.redirect("/", 302)

    # Get user_id
    user_id = session.get("user_id")

    # Try to update user access info
    updated = DBShortcuts.updateLastUserView("survey", user_id)

    # Check if the user was successfully updated
    if not updated:
        error_msg = "Something went wrong while registering the user action. The database couldn't update the document."
        logger.error(error_msg)
        raise FrontEndException(error_msg)

    # Render survey template
    response_env = {"reCaptcha_public": RECAPTCHA_PUBLIC}
    return flask.render_template("survey.html", **response_env)
Пример #3
0
def iat():

    # Check referer and session
    if not checkReferer("instructions",
                        request.headers) or not checkSession(session):
        return flask.redirect("/", 302)

    # Get user_id
    user_id = session.get("user_id")

    # Try to update user access info
    updated = DBShortcuts.updateLastUserView("iat", user_id)

    # Check if the user was successfully updated
    if not updated:
        error_msg = "Something went wrong while registering the user action. The database couldn't update the document."
        logger.error(error_msg)
        raise FrontEndException(error_msg)

    # Render main iat template
    return flask.render_template("iat.html")
Пример #4
0
def instructions():

    # Check referer and session
    if not checkReferer("welcome",
                        request.headers) or not checkSession(session):
        return flask.redirect("/", 302)

    # Get user_id
    user_id = session.get("user_id")

    # Try to update user access info
    updated = DBShortcuts.updateLastUserView("instructions", user_id)

    # Check if the user was successfully updated
    if not updated:
        error_msg = "Something went wrong while registering the user action. The database couldn't update the document."
        logger.error(error_msg)
        raise FrontEndException(error_msg)

    # Render instructions template
    # We're going to randomly shuffle each word and image list
    response_env = {
        "good_words":
        random.sample(list(
            filter(lambda d: d['label'] in ['good'], STIMULI_WORDS)),
                      k=8),
        "bad_words":
        random.sample(list(
            filter(lambda d: d['label'] in ['bad'], STIMULI_WORDS)),
                      k=8),
        "white_people":
        random.sample(list(
            filter(lambda d: d['label'] in ['white'], STIMULI_IMAGES)),
                      k=4),
        "dark_people":
        random.sample(list(
            filter(lambda d: d['label'] in ['dark'], STIMULI_IMAGES)),
                      k=4)
    }
    return flask.render_template("instructions.html", **response_env)
Пример #5
0
    def registerNewUser(session, request):

        # Create a new user_id
        session["user_id"] = uuid.uuid1().hex

        # Register user in database
        # Open new DB connection
        MongoConnection = MongoConnector(MONGO_DB, MONGO_USERS_COLLECTION,
                                         MONGO_URI)

        # insert new user id
        user_id = session.get("user_id")

        insertResults = MongoConnection.collection.insert_one({
            "user_id":
            user_id,
            "created":
            datetime.datetime.utcnow(),
            "remote_address":
            request.headers.get('X-Real-IP', None),
            "last_timestamp":
            datetime.datetime.utcnow(),
            "hits":
            1,
            "completed":
            False,
            "last_view":
            "welcome",
            "mobile":
            session["mobile"]
        })

        # Check insert result
        if not insertResults.acknowledged:
            error_msg = "Something went wrong while registering a new user in the database. The insert operation was not acknowledged."
            logger.error(error_msg)
            raise FrontEndException(error_msg)

        # Close mongo connection
        MongoConnection.close()
Пример #6
0
def welcome():

    # First, check if we're dealing with a mobile-device user
    mobileUserRegex = r"Mobile|iP(hone|od|ad)|Android|BlackBerry|IEMobile|Kindle|NetFront|Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune"
    userAgent = request.headers.get("User-Agent", None)

    # If no user agent or empty
    if userAgent is None or userAgent == "":
        raise FrontEndException(
            "Although a valid HTTP request was received, the User-Agent header is missing!"
        )

    # Check if user agent matches mobile
    mobileUserAgentMatch = re.search(mobileUserRegex, userAgent)

    # If match failed, then user is not mobile
    if mobileUserAgentMatch is not None:
        # Set mobile parameter in session accordingly
        session["mobile"] = True
    else:
        session["mobile"] = False

    # Check if session has user_id field
    if session.get("user_id", None) is None:

        # Register user
        DBShortcuts.registerNewUser(session, request)

        # Render welcome
        return flask.render_template("welcome.html")

    # If there is a user_id in the session cookie
    else:
        # Open new DB connection
        MongoConnection = MongoConnector(MONGO_DB, MONGO_USERS_COLLECTION,
                                         MONGO_URI)

        # Search user id
        user_id = session.get("user_id")
        searchResults = MongoConnection.collection.find_one(
            {"user_id": user_id})

        # If we can't find that userid, then we register it int he database
        if searchResults is None:

            # Register user
            DBShortcuts.registerNewUser(session, request)

            # Render welcome page
            return flask.render_template("welcome.html")

        # if the user has not completed the test, then render main welcome message
        elif searchResults["completed"] == False:
            # Close connection
            MongoConnection.close()
            # Try to update user access info
            DBShortcuts.updateLastUserView("welcome", searchResults["user_id"])
            # Render welcome page
            return flask.render_template("welcome.html")

        elif searchResults["completed"]:
            # Close connection
            MongoConnection.close()

            if DEBUG_MODE:
                return flask.render_template("welcome.html")
            else:
                # Render message saying that the user already answered the test
                return flask.render_template("sorry.html")
Пример #7
0
def testError():
    error_msg = "User requested a test error page. Everything is fine :)"
    logger.error(error_msg)
    raise FrontEndException(error_msg)
Пример #8
0
def results():

    # Check referer and session
    if not checkReferer("survey",
                        request.headers) or not checkSession(session):
        return flask.redirect("/", 302)

    # Get user_id
    user_id = session.get("user_id")

    # Try to update user access info
    updated = DBShortcuts.updateLastUserView("survey", user_id)

    # Check if the user was successfully updated
    if not updated:
        error_msg = "Something went wrong while registering the user action. The database couldn't update the document."
        logger.error(error_msg)
        raise FrontEndException(error_msg)

    # Read user results
    MongoConnection = MongoConnector(MONGO_DB, MONGO_RESULTS_COLLECTION,
                                     MONGO_URI)
    readResults = MongoConnection.collection.find_one(
        filter={"user_id": user_id}, sort=[("timestamp", -1)])

    # Check if there's at least one user with results
    if readResults is None:
        logger.warning(
            "Request from {0} attempted to render results, but user is not registered in results database"
            .format(request.remote_addr))
        return flask.redirect("/", 302)

    # Load results
    userResults = readResults["results"]
    userOrder = readResults["order"]

    # Close connection
    MongoConnection.close()

    # Set completed status to true
    MongoConnection = MongoConnector(MONGO_DB, MONGO_USERS_COLLECTION,
                                     MONGO_URI)
    updateResults = MongoConnection.collection.update_one(
        {"user_id": user_id}, {"$set": {
            "completed": True
        }})

    if not updateResults.acknowledged:
        error_msg = "Something went wrong while setting the 'completed' status. The database couldn't update the document."
        logger.error(error_msg)
        raise FrontEndException(error_msg)

    # Define response dict in advance
    responseEnv = dict()

    # Check number of results
    MongoConnection = MongoConnector(MONGO_DB, MONGO_COUNTER_COLLECTION,
                                     MONGO_URI)
    readResults = MongoConnection.collection.find_one(
        {"counter_name": "n_results"})

    # Check if mongo did find the document containing the number of results
    if readResults is None:
        error_msg = "Something went wrong while looking for the results counter."
        logger.error(error_msg)
        raise FrontEndException(error_msg)

    # Check number of results
    # If we still have less than 41 results, then we use Harvard's results
    if readResults["counter_value"] < 41:
        # Open json file with Harvard results
        try:
            with open(D_SCORES_PATH) as jsonFile:
                dScores = json.load(jsonFile)
        except Exception:
            error_msg = "Something went wrong while loading other users' results."
            logger.error(error_msg)
            raise FrontEndException(error_msg)
    # Else, just load our own dScores
    else:
        # Read dScores from database
        dScores = readResults["scores_array"]
        # Send dscores as an array
        dScoresArray = list()
        for entry in dScores:
            # Get score
            score = entry.get("score", None)
            # Append to array
            dScoresArray.append(score)

        # Replace dscores object
        dScores = dScoresArray

    # Get round latency results. Depending on user order (1 or 0, randomly assigned), we flip round results order
    # If round is 0
    if userOrder == 0:
        roundResults_3 = userResults.get("round_3", None)
        roundResults_4 = userResults.get("round_4", None)
        roundResults_6 = userResults.get("round_6", None)
        roundResults_7 = userResults.get("round_7", None)
    # If round is 1
    elif userOrder == 1:
        roundResults_3 = userResults.get("round_6", None)
        roundResults_4 = userResults.get("round_7", None)
        roundResults_6 = userResults.get("round_3", None)
        roundResults_7 = userResults.get("round_4", None)

    # Coerce each round result into a dataFrame (pandas library)
    roundResults_3_df = pd.DataFrame(roundResults_3)
    roundResults_4_df = pd.DataFrame(roundResults_4)
    roundResults_6_df = pd.DataFrame(roundResults_6)
    roundResults_7_df = pd.DataFrame(roundResults_7)
    # Create a list containing the dataframes
    roundResults_list = list()
    roundResults_list.append(roundResults_3_df)
    roundResults_list.append(roundResults_4_df)
    roundResults_list.append(roundResults_6_df)
    roundResults_list.append(roundResults_7_df)

    # Remove answers where latency > 10 000 ms
    for stageNum in range(0, 4):
        df_foo = roundResults_list[stageNum]
        df_foo = df_foo[df_foo["latency"] < 10000]
        roundResults_list[stageNum] = df_foo

    # Create a dataframe with the pooled latencies from rounds 3, 4, 6, and 7
    roundResults_pooled = pd.concat([
        roundResults_3_df, roundResults_4_df, roundResults_6_df,
        roundResults_7_df
    ],
                                    ignore_index=True)

    # Count the total number of trials in the pooled dataframe
    # We can't just use the total number of trials, because we removed some of them (the ones with latency > 10 000 ms)
    nRow = len(roundResults_pooled.index)

    # Check that no more than 10% of the pooled latency results were under 300 ms
    nRow_lessThan300 = roundResults_pooled[
        roundResults_pooled["latency"] < 300].shape[0]
    if (nRow_lessThan300 / nRow) > 0.1:
        # If more than 10% of the results, send error code e.1 (Results were random and we can't analyze them)
        resultData = {"code": "e.1"}
        responseEnv = {"resultData": json.dumps(resultData)}
        return flask.render_template("results.html", **responseEnv)

    # For each stage, compute latency mean.
    stageMeans = dict()
    for stageNum in range(0, 4):
        stageDataFrame = roundResults_list[stageNum]
        # Only consider trials where user made 0 mistakes
        stageDataFrame = stageDataFrame[stageDataFrame["error"] == 0]
        stageLatencies = stageDataFrame["latency"]
        latencyMean = stageLatencies.mean()
        stageMeans["stage_{0}".format(stageNum)] = latencyMean

    # Now, consider only trials where user made a mistake. In those cases, replace latency with stage mean + 600
    for stageNum in range(0, 4):
        stageDataFrame = roundResults_list[stageNum]
        latencyMean = stageMeans["stage_{0}".format(stageNum)]
        # Replace trials where errors > 0 with the stage mean
        stageDataFrame.loc[stageDataFrame["error"] > 0] = latencyMean + 600
        roundResults_list[stageNum] = stageDataFrame

    # For each stage, compute the "new mean" (considering the cases where latency was replaced with mean+600)
    newStageMeans = dict()
    for stageNum in range(0, 4):
        stageDataFrame = roundResults_list[stageNum]
        stageLatencies = stageDataFrame["latency"]
        latencyMean = stageLatencies.mean()
        newStageMeans["stage_{0}".format(stageNum)] = latencyMean

    # Compute standard deviations
    # One standard deviations for stage group 1 (stages 3 and 6)
    # One standard deviations for stage group 2 (stages 4 and 7)
    SD1 = pd.concat(
        [roundResults_list[0]["latency"], roundResults_list[2]["latency"]],
        ignore_index=True).std()
    SD2 = pd.concat(
        [roundResults_list[1]["latency"], roundResults_list[3]["latency"]],
        ignore_index=True).std()

    # Compute "IAT effect"
    Q1 = (newStageMeans["stage_0"] - newStageMeans["stage_2"]) / SD1
    Q2 = (newStageMeans["stage_1"] - newStageMeans["stage_3"]) / SD2

    IAT = (Q1 + Q2
           ) / 2  # This is why our "IAT effect" can only range from -2 to 2!!

    # First, check if the user is not registered in the array of scores
    MongoConnection = MongoConnector(MONGO_DB, MONGO_COUNTER_COLLECTION,
                                     MONGO_URI)

    searchResults = MongoConnection.collection.count_documents(
        {"scores_array.user_id": user_id})

    if searchResults < 1:
        # Add IAT effect (dScore) to array of dScores
        updateResults = MongoConnection.collection.update_one(
            {"counter_name": "n_results"},
            {
                "$inc": {
                    "counter_value": 1
                },
                "$push": {
                    # This is an array where we store user id, together with his/her score
                    "scores_array": {
                        "user_id": user_id,
                        "score": IAT
                    }
                }
            })

        # Check update operation
        if updateResults.modified_count < 1:
            error_msg = "Something went wrong while updating the results array."
            logger.error(error_msg)
            raise FrontEndException(error_msg)

    else:
        logger.warning(
            "User {0} from {1} tried to re submit survey answers.".format(
                user_id, request.remote_addr))

    # Close DB connection
    MongoConnection.close()

    # Get fastest latency
    fastestLatency = roundResults_pooled["latency"].min()

    # Get slowest latency
    slowestLatency = roundResults_pooled["latency"].max()

    # Get mean pooled latency
    meanLatency = roundResults_pooled["latency"].mean()

    # Get total number of errors
    totalErrors = roundResults_pooled["error"].sum()

    # Get group stats
    MongoConnection = MongoConnector(MONGO_DB, MONGO_RESULTS_COLLECTION,
                                     MONGO_URI)
    readResults = MongoConnection.collection.find(
        None,  # All documents
        {"results": True})

    # List of rounds data frames
    rounds_dataframes = list()

    for document in readResults:
        # Get results subdocument
        rounds = document["results"]

        # Loop through rounds
        for roundDocument in rounds:
            roundDf = pd.DataFrame(rounds[roundDocument])
            rounds_dataframes.append(roundDf)

    # Concatenate dataframes
    rounds_concatenated = pd.concat(rounds_dataframes)

    # Get fastest latency
    fastestLatency_group = rounds_concatenated["latency"].min()

    # Get slowest latency
    slowestLatency_group = rounds_concatenated["latency"].max()

    # Get mean pooled latency
    meanLatency_group = rounds_concatenated["latency"].mean()

    # Close connection
    MongoConnection.close()

    # Coerce data types
    fastestLatency = int(fastestLatency)
    slowestLatency = int(slowestLatency)
    meanLatency = float(meanLatency)
    totalErrors = int(totalErrors)
    fastestLatency_group = int(fastestLatency_group)
    slowestLatency_group = int(slowestLatency_group)
    meanLatency_group = float(meanLatency_group)
    # Round to 4 decimal places
    meanLatency = round(meanLatency, 3)
    IAT = round(IAT, 3)

    # Prepare results data
    resultData = {
        "code": "s",
        "iatScore": IAT,
        "fastestLatency": fastestLatency,
        "slowestLatency": slowestLatency,
        "meanLatency": meanLatency,
        "errorCount": totalErrors,
        "fastestLatency_g": fastestLatency_group,
        "slowestLatency_g": slowestLatency_group,
        "meanLatency_g": meanLatency_group,
        "dScores": dScores
    }

    # Put data in response env
    responseEnv = {"resultData": json.dumps(resultData)}

    # Render
    return flask.render_template("results.html", **responseEnv)