diff --git a/app/views/book.py b/app/views/book.py index 4811969..8db9fb4 100644 --- a/app/views/book.py +++ b/app/views/book.py @@ -332,19 +332,42 @@ def edit_contributor_role(book_id: int): return redirect(url_for("book.settings", book_id=book_id)) -################# -# Collection CRUD -################# +############################### +# Collection/SubCollection CRUD +############################### @bp.route("//create_collection", methods=["POST"]) +@bp.route("///create_sub_collection", methods=["POST"]) @login_required -def collection_create(book_id: int): +def collection_create(book_id: int, collection_id: int | None = None): book: m.Book = db.session.get(m.Book, book_id) if not book or book.owner != current_user or book.is_deleted: log(log.INFO, "User: [%s] is not owner of book: [%s]", current_user, book) flash("You are not owner of this book!", "danger") return redirect(url_for("book.my_books")) + if collection_id: + collection: m.Collection = db.session.get(m.Collection, collection_id) + if not collection or collection.is_deleted: + log(log.WARNING, "Collection with id [%s] not found", collection_id) + flash("Collection not found", "danger") + return redirect(url_for("book.collection_view", book_id=book_id)) + elif collection.is_leaf: + log(log.WARNING, "Collection with id [%s] is leaf", collection_id) + flash("You can't create subcollection for this collection", "danger") + return redirect( + url_for( + "book.sub_collection_view", + book_id=book_id, + collection_id=collection_id, + ) + ) + + redirect_url = url_for("book.collection_view", book_id=book_id) + if collection_id: + redirect_url = url_for( + "book.sub_collection_view", book_id=book_id, collection_id=collection_id + ) form = f.CreateCollectionForm() @@ -363,23 +386,27 @@ def collection_create(book_id: int): label, ) flash("Collection label must be unique!", "danger") - return redirect(url_for("book.collection_view", book_id=book_id)) + return redirect(redirect_url) collection: m.Collection = m.Collection( label=label, about=form.about.data, version_id=book.versions[-1].id ) + if collection_id: + collection.parrent_id = collection_id + collection.is_leaf = True + log(log.INFO, "Create collection [%s]. Book: [%s]", collection, book.id) collection.save() flash("Success!", "success") - return redirect(url_for("book.collection_view", book_id=book_id)) + return redirect(redirect_url) else: - log(log.ERROR, "Book create errors: [%s]", form.errors) + log(log.ERROR, "Collection/Subcollection create errors: [%s]", form.errors) for field, errors in form.errors.items(): field_label = form._fields[field].label.text for error in errors: flash(error.replace("Field", field_label), "danger") - return redirect(url_for("book.settings", book_id=book_id)) + return redirect(redirect_url) @bp.route("///edit", methods=["POST"]) diff --git a/tests/test_book.py b/tests/test_book.py index ebbb0c9..73bf6a1 100644 --- a/tests/test_book.py +++ b/tests/test_book.py @@ -283,3 +283,128 @@ def test_crud_collection(client: FlaskClient, runner: FlaskCliRunner): assert response.status_code == 200 assert b"Collection not found" in response.data + + +def test_crud_subcollection(client: FlaskClient, runner: FlaskCliRunner): + _, user = login(client) + user: m.User + + # add dummmy data + runner.invoke(args=["db-populate"]) + + book: m.Book = db.session.get(m.Book, 1) + book.user_id = user.id + book.save() + + leaf_collection: m.Collection = m.Collection( + label="Test Leaf Collection #1 Label", + version_id=book.versions[-1].id, + is_leaf=True, + ).save() + collection: m.Collection = m.Collection( + label="Test Collection #1 Label", version_id=book.versions[-1].id + ).save() + + response: Response = client.post( + f"/book/{book.id}/{leaf_collection.id}/create_sub_collection", + data=dict( + label="Test SubCollection #1 Label", about="Test SubCollection #1 About" + ), + follow_redirects=True, + ) + + assert response.status_code == 200 + assert b"You can't create subcollection for this collection" in response.data + + response: Response = client.post( + f"/book/{book.id}/{collection.id}/create_sub_collection", + data=dict( + label="Test SubCollection #1 Label", about="Test SubCollection #1 About" + ), + follow_redirects=True, + ) + + assert response.status_code == 200 + assert b"Success!" in response.data + + response: Response = client.post( + f"/book/{book.id}/{collection.id}/create_sub_collection", + data=dict(label="Test Collection #1 Label", about="Test Collection #1 About"), + follow_redirects=True, + ) + + assert response.status_code == 200 + assert b"Collection label must be unique!" in response.data + + sub_collection: m.Collection = m.Collection.query.filter_by( + label="Test SubCollection #1 Label" + ).first() + assert sub_collection + assert sub_collection.is_leaf + assert sub_collection.parrent_id == collection.id + + # m.Collection( + # label="Test Collection #2 Label", version_id=collection.version_id + # ).save() + + # response: Response = client.post( + # f"/book/{book.id}/{collection.id}/edit", + # data=dict( + # label="Test Collection #2 Label", + # ), + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert b"Collection label must be unique!" in response.data + + # new_label = "Test Collection #1 Label(edited)" + # new_about = "Test Collection #1 About(edited)" + + # response: Response = client.post( + # f"/book/{book.id}/{collection.id}/edit", + # data=dict( + # label=new_label, + # about=new_about, + # ), + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert b"Success!" in response.data + + # edited_collection: m.Collection = m.Collection.query.filter_by( + # label=new_label, about=new_about + # ).first() + # assert edited_collection + + # response: Response = client.post( + # f"/book/{book.id}/0/edit", + # data=dict( + # label=new_label, + # about=new_about, + # ), + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert b"Collection not found" in response.data + + # response: Response = client.post( + # f"/book/{book.id}/{collection.id}/delete", + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert b"Success!" in response.data + + # deleted_collection: m.Collection = db.session.get(m.Collection, collection.id) + # assert deleted_collection.is_deleted + + # response: Response = client.post( + # f"/book/{book.id}/{collection.id}/delete", + # follow_redirects=True, + # ) + + # assert response.status_code == 200 + # assert b"Collection not found" in response.data