def get_following(): request_data = request.json user_id = extract_integer(request_data, "userID") reader = Reader.query.filter_by(id=user_id).first() if not reader: raise ResourceNotFound("A user with the specified ID does not exist") follows = reader.follows if not follows: raise ResourceNotFound( "The user with the specified ID does not follow any users") n_recommend = extract_integer(request_data, "n_recommend", default_value=DEFAULT_NRECOMMEND) all_following_books = set() for followed_user in follows: all_following_books.update(set(get_all_books(followed_user))) all_following_books = list(all_following_books) all_following_books = remove_reader_overlap(reader.id, all_following_books) recommendations = sample_top_books(all_following_books, n_recommend) return jsonify(books_schema.dump(recommendations))
def get_readers_recently_read(username): reader = Reader.query.filter_by(username=username).first() if not reader: raise ResourceNotFound( f"A user with the username {username} does not exist") recently_read = get_recently_read(reader) return jsonify(collection_schema.dump(recently_read))
def get_followers(username): reader = Reader.query.filter_by(username=username).first() if not reader: raise ResourceNotFound("A user with the specified ID does not exist") followers = reader.followers return jsonify(readers_schema.dump(followers))
def get_genre(): request_data = request.json n_recommend = extract_integer(request_data, "n_recommend", default_value=DEFAULT_NRECOMMEND) # Seed Book book_id = extract_integer(request_data, "bookID") seed_book = Book.query.filter_by(id=book_id).first() if not seed_book: raise ResourceNotFound("A book with this ID does not exist") # If a genre name is provided, use books from that genre if genre_name := request.json.get("genre"): genre = Genre.query.filter_by(name=genre_name).first() if not genre: raise ResourceNotFound("A genre with this name does not exist") all_genre_books = genre.books
def get_author(): request_data = request.json n_recommend = extract_integer(request_data, "n_recommend", default_value=DEFAULT_NRECOMMEND) # Seed Book book_id = extract_integer(request_data, "bookID") seed_book = Book.query.filter_by(id=book_id).first() if not seed_book: raise ResourceNotFound("A book with this ID does not exist") # If an author's name is provided, use their books if author_name := request_data.get("author"): author = Author.query.filter_by(name=author_name).first() if not author: raise ResourceNotFound("An author with this name does not exist") all_author_books = author.books
def get_all_readers_books(username): reader = Reader.query.filter_by(username=username).first() if not reader: raise ResourceNotFound( f"A user with the username {username} does not exist") all_books = get_all_books( reader, sort_func=lambda membership: membership.book.title) all_collection = Collection(books=all_books, name="All", reader=reader) return jsonify(collection_schema.dump(all_collection))
def get_reader_by_id(id_): if not isinstance(id_, int) and not id_.isdigit(): raise InvalidRequest( r"Id should be an integer or a string interpretable as an integer", ) reader = Reader.query.filter_by(id=id_).first() if not reader: raise ResourceNotFound(f"A user with the id {id_} does not exist") return jsonify(reader_schema.dump(reader))
def get_content(): request_data = request.json n_recommend = extract_integer(request_data, "n_recommend", default_value=DEFAULT_NRECOMMEND) recommender = ContentRecommender(ngram_range=(1, 1)) # Get recommendations from single book or list of books book_id = extract_integer(request_data, "bookID", required=False) book_ids = request_data.get("bookIDs") # Recommending from single seed book ID if book_id: seed = Book.query.filter_by(id=book_id).first() if not seed: raise ResourceNotFound("A book with this ID does not exist") # Recommending from list of book IDs elif book_ids: seed = Book.query.filter(Book.id.in_(book_ids)).all() if not len(seed) == len(book_ids): raise ResourceNotFound( "One of more books with a provided bookID does not exist") else: raise InvalidRequest("One of 'bookID' or 'bookIDs' is a required key") try: most_similar_books = recommender.recommend(seed, n_recommend=POOL_SIZE * n_recommend) except ValueError: raise InvalidRequest( "The provided bookID(s) did not correspond to books") # If a user id is provided, remove overlap between a user's books and the genre books if user_id := extract_integer(request_data, "userID", required=False): most_similar_books = remove_reader_overlap(user_id, most_similar_books)
def delete_reader(id_): if not isinstance(id_, int) and not id_.isdigit(): raise InvalidRequest( r"Id should be an integer or a string interpretable as an integer", ) reader = Reader.query.filter_by(id=id_).first() # Check user exists if not reader: raise ResourceNotFound("A user with the specified ID does not exist") # Check we are not deleting an admin if "admin" in reader.roles: raise ForbiddenResource("Cannot delete an admin") # Delete the user db.session.delete(reader) db.session.commit() # Return the new state of all users in the db users = Reader.query.all() return jsonify(readers_schema.dump(users))
def follow(): follow_data = request.json follower_username = follow_data.get("follower") reader_username = follow_data.get("user") if not (follower_username and reader_username): raise InvalidRequest( r"Request should be of the form {{follower: 'username', user: '******'}}", ) # Only the follower can request to follow if follower_username != flask_praetorian.current_user().username: raise ForbiddenResource( "You do not have the correct authorisation to access this resource" ) reader = Reader.query.filter_by(username=reader_username).first() follower = Reader.query.filter_by(username=follower_username).first() if not reader or not follower: raise ResourceNotFound( "Either the follower or the user to follow does not exist") # Add the follower relationship if it does not exist if request.method == "POST" and follower not in reader.followers: reader.followers.append(follower) db.session.add(reader) db.session.commit() # Delete the follower relationship if it does not exist if request.method == "DELETE" and follower in reader.followers: reader.followers.remove(follower) db.session.add(reader) db.session.commit() return jsonify(reader_schema.dump(follower))
def remove_reader_overlap(reader_id, book_list): reader = Reader.query.filter_by(id=reader_id).first() if not reader: raise ResourceNotFound("A user with the specified ID does not exist") reader_books = get_all_books(reader) return list(set(book_list) - set(reader_books))
def get_reader(username): reader = Reader.query.filter_by(username=username).first() if not reader: raise ResourceNotFound( f"A user with the username {username} does not exist") return jsonify(reader_schema.dump(reader))