Exemple #1
0
def profile_stats_push_handler():
    """
        Params:
            - user_id  (str)
            - child_id (str)
            - course_id (str)
            - lesson_id (str)
            - time_on_completion (integer timestamp in seconds)
            - num_incorrect (int)
            - time_taken (float or int)
    """
    request_data = dict(request.form)
    printColoured(
        " ➤ A child has just completed a lesson! Received some stats to commit:"
    )
    pretty(request_data)

    # try:
    course_id = request_data["course_id"]
    lesson_id = request_data["lesson_id"]
    difficulty = get_lesson_difficulty(course_id, lesson_id)
    return jsonify(
        save_stats(
            {
                "course_id": course_id,
                "lesson_id": lesson_id,
                "num_incorrect": request_data["num_incorrect"],
                "time_taken": request_data["time_taken"],
                "time_on_completion": request_data["time_on_completion"],
                "difficulty": difficulty
            }, request_data["user_id"], request_data["child_id"]))
Exemple #2
0
def save_stats(stats, parent_user_id, child_id):
    """
        TODO
        pushes an object to db.users.children.statistics array
    """
    parent = get_user(user_id=parent_user_id)
    target_child = [
        child for child in parent["children"] if child["_id"] == child_id
    ][0]
    # new_stats = target_child["statistics"].copy()
    # new_stats.append(stats)

    db.users.update_one(
        {
            "_id": ObjectId(parent_user_id),
            "children": {
                "$elemMatch": {
                    "_id": {
                        "$eq": child_id
                    }
                }
            }
        }, {"$push": {
            "children.$.statistics": stats
        }})
    printColoured(" ➤ Successfully saved new performance stats!")
    return stats
Exemple #3
0
def profile_data_fetch_handler():
    """
        Given a user_id and token, gets the target user's profile data
    """
    user_id = request.args.get("user_id")
    profile_data = get_user(user_id=user_id)
    printColoured(" ➤ Fetched user profile of: {}".format(user_id))
    return jsonify(profile_data)
Exemple #4
0
def profile_stats_fetch_handler():
    """
        Given a user_id and token, get their children's associated stats
    """
    user_id = request.args.get("user_id")
    printColoured(" ➤ Getting child stats: {}".format(user_id))
    stats = get_stats(user_id)
    return jsonify(stats)
Exemple #5
0
def pretty(d, indent=1):
    """ Pretty print a dictionary """
    for key, value in d.items():
        printColoured('\t' * indent + str(key) + ":", colour="yellow")
        if isinstance(value, dict):
            pretty(value, indent + 1)
        else:
            printColoured('\t' * (indent + 1) + str(value), colour="blue")
Exemple #6
0
def db_users():
    """ Querying the database and displaying results """
    users = [user for user in get_all_users()]
    courses_lessons = get_courses_lessons()
    courses_all = [course for course in get_courses_all()]
    printColoured(courses_lessons)
    return render_template("database.html",
                           users=users,
                           courses_lessons=courses_lessons,
                           courses_all=courses_all)
Exemple #7
0
def save_user(user) -> str:
    """ 
        Saves and returns the ID of the new user 

        Returns:
            str: ID of the new user
    """
    printColoured(" ➤ Saving new user: {}".format(user), colour="blue")
    # Builtin function vars() takes an object and constructs a dict. The _id key is then
    # removed to prevent colliding with MongoDB's generated ID
    document = vars(user)
    del document["_id"]
    return insert("users", document)
Exemple #8
0
def get_lesson_difficulty(course_id: str, lesson_id: str):
    all_course = get_courses_full()
    try:
        target_course = [
            course for course in all_course if course["courseId"] == course_id
        ][0]
        target_lesson = [lesson for lesson in target_course["lessons"]]
        printColoured(" ➤ Found '{}' lesson '{}'".format(course_id, lesson_id))
        return target_lesson[
            "difficulty"] if "difficulty" in target_lesson else 0.5
    except:
        raise InvalidUserInput(
            description="Failed to find course '{}', lesson '{}'".format(
                course_id, lesson_id))
Exemple #9
0
def google_login_handler():
    """
        When this route is hit, the user is directed to Google's authentication
        page where they will choose a Google account to log in with.
    """
    # Find out what URL to hit for Google login
    google_provider_cfg = get_google_provider_cfg()
    authorization_endpoint = google_provider_cfg["authorization_endpoint"]

    # Use library to construct the request for Google login and provide
    # scopes that let you retrieve user's profile from Google
    request_uri = google_client.prepare_request_uri(
        authorization_endpoint,
        redirect_uri="https://127.0.0.1:5000/api/auth/google/login/callback",
        scope=["openid", "email", "profile"],
    )
    printColoured("REDIRECTING NOW", colour="blue")
    printColoured("Request URI: {}".format(request_uri))
    return redirect(request_uri)
Exemple #10
0
def error_handler(err):
    """
        Returns JSON containing details of the failure event including the
        status code, name and message. This JSON message is returned to the client
        everytime the route handlers encounter a problem, for example, invalid user 
        input.
    """
    response = err.get_response()
    try:
        printColoured(" ➤ Error: {} {}".format(err, err.description),
                      colour="red")
        response.data = dumps({
            "code": err.code,
            "name": "System Error",
            "message": err.description
        })
        response.content_type = 'application/json'
        return response
    except:
        printColoured(" ➤ Error: {}".format(err), colour="red")
        response.data = dumps({"code": err.code, "name": "System Error"})
        response.content_type = 'application/json'
        return response
Exemple #11
0
def wipe_all_users():
    """ Wipes all documents from the GalacticEd 'users' collection """
    db.users.drop()
    printColoured(" ➤ DROPPED USERS", colour="red")
Exemple #12
0
def print_pretty_json(struct, colour="yellow"):
    printColoured(json.dumps(struct, indent=4, sort_keys=True), colour=colour)
Exemple #13
0
def db_wipe_users():
    """ Wipes all users from the database (drops the 'users' named collection) """
    printColoured("Wiping all users")
    wipe_all_users()
    return render_template("database.html")
Exemple #14
0
def profile_stats_push_handler():
    """
        TODO: documentation
        Params:
            - user_id (str)
            - child_id (str)
            - course_id (str)
    """

    try:
        user_id = request.args.get("user_id")
        child_id = request.args.get("child_id")
        category = request.args.get("category")
        printColoured(" ➤ Recommending a lesson from '{}' for {}".format(
            category, child_id))

        curr_timestamp = floor(time.time())
        week_prior_timestamp = curr_timestamp - (
            1 * 7 * 24 * 60 * 60)  # TODO: this is a little dumb
        two_week_prior_timestamp = curr_timestamp - (
            2 * 7 * 24 * 60 * 60)  # TODO: this is a little dumb
        zero_reference = 0

        all_stats = get_stats_in_range(user_id, child_id, "shapes",
                                       zero_reference, curr_timestamp)
        last_week_stats = get_stats_in_range(user_id, child_id, "shapes",
                                             week_prior_timestamp,
                                             curr_timestamp)
        this_week_stats = get_stats_in_range(user_id, child_id, "shapes",
                                             two_week_prior_timestamp,
                                             curr_timestamp)

        print_pretty_json(all_stats)
        # print_pretty_json(last_week_stats)
        # print_pretty_json(this_week_stats)

        # Getting the average time taken, num_incorrect, difficulty:
        printColoured(
            "Performances: (avg time taken, avg num_incorrect, avg difficulty)",
            colour="blue")
        printColoured("-> Global", colour="blue")
        global_performance = stats_summarise(all_stats)
        print_pretty_json(global_performance)

        printColoured("-> Last Week", colour="blue")
        last_week_performance = stats_summarise(last_week_stats)
        print_pretty_json(last_week_performance)

        printColoured("-> This Week", colour="blue")
        this_week_performance = stats_summarise(this_week_stats)
        print_pretty_json(this_week_performance)

    except Exception as err:
        printColoured(err, colour="red")
        raise InvalidUserInput(description="Invalid or missing stats fields")

    return jsonify({"lesson-id": "shapes-4"})
Exemple #15
0
from flask import Flask
from flask_cors import CORS
from dotenv import load_dotenv
from pathlib import Path
from GalacticEd.utils.colourisation import printColoured
from flask_pymongo import PyMongo
from GalacticEd.exceptions import error_handler
from oauthlib.oauth2 import WebApplicationClient
import pymongo
import os

# Setting the environment variables:
# env_path = Path('.') / '.env.{}'.format(os.getenv("GALACTIC_ED_DEV_MODE"))
env_path = Path('.') / '.env.{}'.format("development")
load_dotenv(dotenv_path=env_path)
printColoured(
    "Loaded the context of {} into the environment:".format(env_path))

# Creating the Flask app instance
printColoured(" * Initialising Flask application")
app = Flask(__name__)
CORS(app)

# ===== App Configuration =====

SECRET_KEY = os.getenv("SECRET_KEY")
app.secret_key = SECRET_KEY

GOOGLE_API_CLIENT_SECRET = os.getenv("GOOGLE_API_CLIENT_SECRET")
GOOGLE_API_CLIENT_ID = os.getenv("GOOGLE_API_CLIENT_ID")
GOOGLE_DISCOVERY_URL = (
    "https://accounts.google.com/.well-known/openid-configuration")
Exemple #16
0
def google_login_callback_handler():
    """
        This is the route hit by Google's API. The exact URL is specified in the
        develop console: https://console.developers.google.com/
    """
    printColoured("CLIENT_ID : {}, CLIENT_SECRET: {}".format(
        GOOGLE_API_CLIENT_ID, GOOGLE_API_CLIENT_SECRET),
                  colour="yellow")
    # Get authorization code Google sent back to you
    code = request.args.get("code")

    # Find out what URL to hit to get tokens that allow you to ask for
    # things on behalf of a user
    google_provider_cfg = get_google_provider_cfg()
    token_endpoint = google_provider_cfg["token_endpoint"]

    # Prepare and send a request to get tokens! Yay tokens!
    token_url, headers, body = google_client.prepare_token_request(
        token_endpoint,
        authorization_response=request.url,
        redirect_url=request.base_url,
        code=code)

    token_response = requests.post(
        token_url,
        headers=headers,
        data=body,
        auth=(GOOGLE_API_CLIENT_ID, GOOGLE_API_CLIENT_SECRET),
    )

    # Parse the tokens!
    google_client.parse_request_body_response(json.dumps(
        token_response.json()))

    # Now that you have tokens (yay) let's find and hit the URL
    # from Google that gives you the user's profile information,
    # including their Google profile image and email
    userinfo_endpoint = google_provider_cfg["userinfo_endpoint"]
    uri, headers, body = google_client.add_token(userinfo_endpoint)
    userinfo_response = requests.get(uri, headers=headers, data=body)

    # You want to make sure their email is verified.
    # The user authenticated with Google, authorized your
    # app, and now you've verified their email through Google!
    if userinfo_response.json().get("email_verified"):
        user_email = userinfo_response.json()["email"]
        user_image = userinfo_response.json()["picture"]
        user_name = userinfo_response.json()["given_name"]
    else:
        return "User email not available or not verified by Google.", 400

    # Create a user in your db with the information provided
    # by Google
    printColoured(
        " ➤ GOOGLE API: Registered a user with details: name: {}, email: {}, image: {}"
        .format(user_name, user_email, user_image))

    new_user = User(name=user_name, email=user_email, password="******")
    new_user.commit_user()
    printColoured("COMMITTED THE USER")

    # Send user back to homepage
    return """
        <h3>You've logged in successfully!</h3> 
        <div>Name: {}, Email: {}</div>
        <img src='{}'></img>
    """.format(user_name, user_email, user_image)
Exemple #17
0
def wipe_user(email):
    """
        TODO unprotected! This is just a convenience function
    """
    printColoured(" ➤ Removing a user: {}".format(email), colour="yellow")
    db.users.remove({"email": email})