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 })
def get_popular(course): course = model.Course.getBy(db.session, code=course.upper()) return respond({ "course": course, "popular_questions": course.popular_questions })
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 })
def get_course(course): course = model.Course.getBy(db.session, code=course.upper()) return respond({ "course": course, "papers": course.papers })
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
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})
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 })
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 })
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})
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 })
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})
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})
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 })
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 })
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"])
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 })
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})
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})
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})
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()
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 })
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 })
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)
def check_auth(): return respond({ "key": g.user.active_session.key, "user": g.user })
def get_course(course): course = model.Course.getBy(db.session, code=course.upper()) return respond({"course": course, "papers": course.papers})
def search_institution(domain): return respond({ "institution": model.Institution.getBy(db.session, domain=domain) })
def get_institution(instit): return respond( {"institution": model.Institution.getBy(db.session, id=instit)})
def search_institution(domain): return respond( {"institution": model.Institution.getBy(db.session, domain=domain)})
def get_institution(instit): return respond({ "institution": model.Institution.getBy(db.session, id=instit) })