Example #1
0
def auth(email, password):
    """Log a user in.
        POST { username: String, password: String }
            -> 200 { success: Boolean, session: String }
            -> 400 
        PUT { session }
            -> 200 # Session key valid
            -> 400 # Session key invalid
    """

    try:
        # Get the user
        user = User.getBy(db.session, email=email)
    except NotFound:
        raise HttpException(403, "Account not found.", { "email": email })

    session = user.login(password)
    db.session.add(user)
    db.session.commit()
    db.session.refresh(user)

    return respond({
        "key": session.key,
        "user": user
    })
Example #2
0
def get_popular(course):
    course = model.Course.getBy(db.session, code=course.upper())

    return respond({
        "course": course,
        "popular_questions": course.popular_questions
    })
Example #3
0
def get_popular(course):
    course = model.Course.getBy(db.session, code=course.upper())

    return respond({
        "course": course,
        "popular_questions": course.popular_questions
    })
Example #4
0
def create_comment(entity, content, parent):
    with query(model.Entity):
        entity = db.session.query(model.Entity).filter(model.Entity.id == entity).one()

        if parent != missing:
            parent = db.session.query(model.Comment).filter(model.Comment.id == parent).one()
        else:
            parent = None

    comment = g.user.comment(entity, content, parent)
    db.session.add(comment)
    db.session.commit()
    db.session.refresh(comment) # Conversion from Entity type to Comment

    # Now we invalidate some cache so they pick up the new comments
    if entity.type == "question":
        # Empty the course popular questions
        invalidate_view("course.get_popular")

        db.session.refresh(entity)

        question = entity
        paper = entity.paper
        course = paper.course

        # Invalidate the question's paper
        invalidate_view("paper.get_paper", course=course.code, year=paper.year_start, period=paper.period)
        invalidate_view("question.do_question", course=course.code, year=paper.year_start, period=paper.period, question=".".join(map(str, question.path)))

    # Invalidate the comment cache for specific entity
    invalidate_view("comment.get_comments", entity=entity.id)

    return respond({ "comment": comment })
Example #5
0
def get_course(course):
    course = model.Course.getBy(db.session, code=course.upper())

    return respond({ 
        "course": course,
        "papers": course.papers
    })
Example #6
0
def get_or_update_user(user): 
    # Get the user
    user = model.User.query.get(user)

    if request.method == "GET":
        return respond({ "user": user })
    elif request.method == "PUT":
        pass
Example #7
0
def get_notes(course, year, period, question):
    question = model.Question.get_by_path(db.session, course, year, period,
                                          map(int, question.split(".")))

    notes = db.session.query(with_polymorphic(model.Note, [model.NoteLink, model.NoteUpload]))\
        .filter(model.Note.question_id == question.id).all()

    return respond({"question": question, "notes": notes})
Example #8
0
def get_notes(course, year, period, question):
    question = model.Question.get_by_path(db.session, course, year, period, map(int, question.split(".")))

    notes = db.session.query(with_polymorphic(model.Note, [model.NoteLink, model.NoteUpload]))\
        .filter(model.Note.question_id == question.id).all()

    return respond({
        "question": question,
        "notes": notes    
    })
Example #9
0
def get_similar(course, year, period, question):
    question = model.Question.get_by_path(db.session, course, year, period, map(int, question.split(".")))
    similar = map(lambda similar: similar.similar_question, question.similar)
    papers = map(lambda similar: similar.paper, similar) + [question.paper]

    return respond({ 
        "similar": similar,
        "question": question,
        "papers": papers
    })
Example #10
0
def search_course(q):
    # Replace any + with spaces
    q = q.replace("+", " ")

    # Execute the query
    courses = model.Course.query.filter(
        model.Course.name.ilike("%{}%".format(q)) | \
        model.Course.code.ilike("%{}%".format(q))
    ).limit(COURSE_RESULTS_LIMIT).all()

    return respond({"courses": courses})
Example #11
0
def create_link_note(course, year, period, question, link, description):
    question = model.Question.get_by_path(db.session, course, year, period, map(int, question.split(".")))
    note = model.NoteLink(link=link, description=description, user=g.user, question=question)
    db.session.add(note)
    db.session.commit()
    db.session.refresh(note)

    return respond({
        "question": question,
        "note": note
    })
Example #12
0
def create_link_note(course, year, period, question, link, description):
    question = model.Question.get_by_path(db.session, course, year, period,
                                          map(int, question.split(".")))
    note = model.NoteLink(link=link,
                          description=description,
                          user=g.user,
                          question=question)
    db.session.add(note)
    db.session.commit()
    db.session.refresh(note)

    return respond({"question": question, "note": note})
Example #13
0
def get_comments(entity):
    with query(model.Entity):
        entity = db.session.query(
            model.Entity).filter(model.Entity.id == entity).one()

        comments = db.session.query(
            with_polymorphic(model.Entity, model.Comment)).filter(
                model.Comment.entity_id == entity.id).all()

    users = map(lambda comment: getattr(comment, "user"), comments)

    return respond({"entity": entity, "comments": comments, "users": users})
Example #14
0
def search_course(q):
    # Replace any + with spaces
    q = q.replace("+", " ")

    # Execute the query
    courses = model.Course.query.filter(
        model.Course.name.ilike("%{}%".format(q)) | \
        model.Course.code.ilike("%{}%".format(q)) 
    ).limit(COURSE_RESULTS_LIMIT).all()

    return respond({ 
        "courses": courses
    })
Example #15
0
def get_comments(entity):
    with query(model.Entity):
        entity = db.session.query(model.Entity).filter(model.Entity.id == entity).one()

        comments = db.session.query(
            with_polymorphic(model.Entity, model.Comment)
        ).filter(model.Comment.entity_id == entity.id).all()

    users = map(lambda comment: getattr(comment, "user"), comments)

    return respond({ 
        "entity": entity,
        "comments": comments,
        "users": users
    })
Example #16
0
def create(details):
    try:
        user = model.User(**details)
        db.session.add(user)
        db.session.flush()

        # Log the user in
        session = user.login()
        db.session.commit()
        db.session.refresh(user)

        return respond({ "key": session.key, "user": user })
    except NotFound as nf:
        raise InvalidEntity("Institution", "domain", nf.meta["fields"]["domain"])
    except IntegrityError as ie:
        raise AlreadyExists("User", "email", details["email"])
Example #17
0
def create_question(course, year, period):
    args = parser.parse(POST_PARAMS, request)
    paper = model.Paper.find(db.session, course, year, period)
    question = model.Question(paper, index=args["index"])

    if "content" in args:
        question.set_content(g.user, args["content"])

    db.session.add(question)
    db.session.commit()
    db.session.refresh(question)

    # Load the paper
    getattr(question, "paper")
    getattr(question, "comment_count")
    getattr(question, "similar_count")

    return respond({ "question": question })
Example #18
0
def get_paper(course, year, period):
    paper = model.Paper.find(db.session, course, year, period)

    if request.url.endswith("html"):
        # Request paper contents
        if not paper.contents:
            # If it doesn't exist, start the download
            paper.download(config.APP_DOWNLOAD_DIR)
            db.session.add(paper)
            db.session.commit()

        # Respond with the file
        return send_file(path.join(paper.contents.path, "index.html"), mimetype="text/html")

    else:
        for question in paper.questions:
            getattr(question, "comment_count")

        return respond({"paper": paper, "course": paper.course, "questions": paper.questions})
Example #19
0
def create_comment(entity, content, parent):
    with query(model.Entity):
        entity = db.session.query(
            model.Entity).filter(model.Entity.id == entity).one()

        if parent != missing:
            parent = db.session.query(
                model.Comment).filter(model.Comment.id == parent).one()
        else:
            parent = None

    comment = g.user.comment(entity, content, parent)
    db.session.add(comment)
    db.session.commit()
    db.session.refresh(comment)  # Conversion from Entity type to Comment

    # Now we invalidate some cache so they pick up the new comments
    if entity.type == "question":
        # Empty the course popular questions
        invalidate_view("course.get_popular")

        db.session.refresh(entity)

        question = entity
        paper = entity.paper
        course = paper.course

        # Invalidate the question's paper
        invalidate_view("paper.get_paper",
                        course=course.code,
                        year=paper.year_start,
                        period=paper.period)
        invalidate_view("question.do_question",
                        course=course.code,
                        year=paper.year_start,
                        period=paper.period,
                        question=".".join(map(str, question.path)))

    # Invalidate the comment cache for specific entity
    invalidate_view("comment.get_comments", entity=entity.id)

    return respond({"comment": comment})
Example #20
0
def edit_comment(entity, comment):
    with query(model.Entity):
        entity = db.session.query(
            model.Entity).filter(model.Entity.id == entity).one()
        comment = db.session.query(
            model.Comment).filter(model.Comment.id == comment).one()

    # Ensure the user is the author
    if not g.user.id == comment.user.id:
        raise Unauthorized()

    if request.method == "DELETE":
        comment.content = ""
        comment.deleted = True
    elif request.method == "PUT":
        args = parser.parse({"content": fields.Str(required=True)})
        comment.content = args["content"]

    # Fix up the cache
    if entity.type == "question":
        db.session.refresh(entity)

        question = entity
        paper = entity.paper
        course = paper.course

        invalidate_view("question.do_question",
                        course=course.code,
                        year=paper.year_start,
                        period=paper.period,
                        question=".".join(map(str, question.path)))

    # Invalidate the comment cache for specific entity
    invalidate_view("comment.get_comments", entity=entity.id)

    db.session.add(comment)
    db.session.commit()
    db.session.refresh(comment)
    getattr(comment, "children")

    return respond({"entity": entity, "comment": comment})
Example #21
0
def get_and_update_courses():
    if request.method == "GET":
        # Return the user's courses
        return respond({ 
            "courses": g.user.courses
        })
    else:
        args = parser.parse(patchParams, request)
        id = args["course"]

        try:
            course = model.Course.getBy(db.session, id=id)
        except NotFound:
            return UnacceptableParameter("Course with id '%d' does not exist." % id)

        # Find the course
        userCourse = find(g.user.courses, lambda c: c.id == course.id)

        if request.method == "PATCH":
            # Patch request i.e. append to the collection
            # Ensure it's not already in the users courses
            if userCourse:
                return success() # Ignorance is bliss

            # Add the course
            g.user.courses.append(course)
        else:
            # Delete the course from the collection
            # Ensure we have the course
            if not userCourse:
                return success()
            
            # Remove the course
            g.user.courses.remove(userCourse)

        db.session.add(g.user)
        db.session.commit()
        return success()
Example #22
0
def edit_comment(entity, comment):
    with query(model.Entity):
        entity = db.session.query(model.Entity).filter(model.Entity.id == entity).one()
        comment = db.session.query(model.Comment).filter(model.Comment.id == comment).one()

    # Ensure the user is the author
    if not g.user.id == comment.user.id:
        raise Unauthorized()

    if request.method == "DELETE":
        comment.content = ""
        comment.deleted = True
    elif request.method == "PUT":
        args = parser.parse({ "content": fields.Str(required=True) })
        comment.content = args["content"]

    # Fix up the cache    
    if entity.type == "question":
        db.session.refresh(entity)

        question = entity
        paper = entity.paper
        course = paper.course

        invalidate_view("question.do_question", course=course.code, year=paper.year_start, period=paper.period, question=".".join(map(str, question.path)))

    # Invalidate the comment cache for specific entity
    invalidate_view("comment.get_comments", entity=entity.id)
    
    db.session.add(comment)
    db.session.commit()
    db.session.refresh(comment)
    getattr(comment, "children")

    return respond({ 
        "entity": entity,
        "comment": comment 
    })
Example #23
0
def get_paper(course, year, period):
    paper = model.Paper.find(db.session, course, year, period)

    if request.url.endswith("html"):
        # Request paper contents
        if not paper.contents:
            # If it doesn't exist, start the download
            paper.download(config.APP_DOWNLOAD_DIR)
            db.session.add(paper)
            db.session.commit()

        # Respond with the file
        return send_file(path.join(paper.contents.path, "index.html"),
                         mimetype="text/html")

    else:
        for question in paper.questions:
            getattr(question, "comment_count")

        return respond({
            "paper": paper,
            "course": paper.course,
            "questions": paper.questions
        })
Example #24
0
def do_question(course, year, period, question):
    # Ensure we parse the args before we do any database access
    if request.method == "PUT":
        args = parser.parse(PUT_PARAMS, request)
    elif request.method == "POST":
        args = parser.parse(POST_PARAMS, request)
    else:
        args = None

    question_path = question
    question = model.Question.get_by_path(db.session, course, year, period, map(int, question.split(".")))

    if request.method == "GET":
        return respond({
            "question": question,
            "children": question.flatten_tree(include_self=False)
        })
    else:
        if request.method == "PUT":
            updated = []

            # Update a question
            if "content" in args:
                question.set_content(g.user, args["content"])

            if "marks" in args:
                question.marks = args["marks"]

            if "index_type" in args:
                question.update_index_type(args["index_type"])

                # Update the indexes of all siblings
                if question.parent:
                    for sibling in question.parent.children:
                        sibling.update_index_type(args["index_type"])
                        updated.append(sibling)

            if "is_section" in args:
                question.is_section = args["is_section"]

            updated.append(question)
            db.session.add_all(updated)
            db.session.commit()
            map(db.session.refresh, updated)

            response = { "questions": updated }
        elif request.method == "POST":
            # Create a child question    
            paper = model.Paper.find(db.session, course, year, period)
            new_question = model.Question(paper, index=args["index"], parent=question)

            if "content" in args:
                new_question.set_content(g.user, args["content"])

            db.session.add(new_question)

            with query(model.Question):
                db.session.commit()

            db.session.refresh(new_question)
            getattr(new_question, "paper")
            getattr(new_question, "parent")

            response = { "question": new_question }
        elif request.method == "DELETE":
            if len(question.children):
                raise Forbidden("Question still has children. Please remove children before removing.")

            modified = []
            db.session.delete(question)

            # Decrement any indexes further up the list
            if question.parent:
                db.session.flush()
                for sibling in question.parent.children:
                    if sibling.index > question.index:
                        sibling.update_index(sibling.index - 1)
                        modified.append(sibling)

                db.session.add_all(modified)
            
            db.session.commit()
            map(db.session.refresh, modified)

            response = { "questions": modified }

        # Invalidate the cache
        invalidate_view("question.do_question", course=course, year=year, period=period, question=question_path)
        invalidate_view("question.get_similar", course=course, year=year, period=period, question=question_path)
        invalidate_view("paper.get_paper", course=course, year=year, period=period)
        invalidate_view("course.get_popular", course=course)


        return respond(response)
Example #25
0
def check_auth():
    return respond({ 
        "key": g.user.active_session.key,
        "user": g.user
    })
Example #26
0
def get_course(course):
    course = model.Course.getBy(db.session, code=course.upper())

    return respond({"course": course, "papers": course.papers})
Example #27
0
def search_institution(domain):
    return respond({ "institution": model.Institution.getBy(db.session, domain=domain) })
Example #28
0
def get_institution(instit):
    return respond(
        {"institution": model.Institution.getBy(db.session, id=instit)})
Example #29
0
def search_institution(domain):
    return respond(
        {"institution": model.Institution.getBy(db.session, domain=domain)})
Example #30
0
def get_institution(instit):
    return respond({ "institution": model.Institution.getBy(db.session, id=instit) })