diff --git a/pydatalab/pydatalab/routes/v0_1/collections.py b/pydatalab/pydatalab/routes/v0_1/collections.py index 09f8d9cc0..37d26f0f2 100644 --- a/pydatalab/pydatalab/routes/v0_1/collections.py +++ b/pydatalab/pydatalab/routes/v0_1/collections.py @@ -333,27 +333,32 @@ def add_items_to_collection(collection_id): data = request.get_json() refcodes = data.get("data", {}).get("refcodes", []) - collection = flask_mongo.db.collections.find_one({"_id": ObjectId(collection_id)}) + collection = flask_mongo.db.collections.find_one( + {"collection_id": collection_id, **get_default_permissions()} + ) + if not collection: return jsonify({"error": "Collection not found"}), 404 if not refcodes: return jsonify({"error": "No item provided"}), 400 - item_count = flask_mongo.db.items.count_documents({"refcode": {"$in": refcodes}}) + item_count = flask_mongo.db.items.count_documents( + {"refcode": {"$in": refcodes}, **get_default_permissions()} + ) if item_count == 0: return jsonify({"error": "No matching items found"}), 404 update_result = flask_mongo.db.items.update_many( - {"refcode": {"$in": refcodes}}, + {"refcode": {"$in": refcodes}, **get_default_permissions()}, { "$addToSet": { "relationships": { "description": "Is a member of", "relation": None, "type": "collections", - "immutable_id": ObjectId(collection_id), + "immutable_id": ObjectId(collection["_id"]), } } }, diff --git a/pydatalab/tests/server/test_graph.py b/pydatalab/tests/server/test_graph.py index 167f60dd8..0b1a65d97 100644 --- a/pydatalab/tests/server/test_graph.py +++ b/pydatalab/tests/server/test_graph.py @@ -22,6 +22,21 @@ def test_simple_graph(admin_client): child_2 = Sample( item_id="child_2", + refcode="test:TEST02", + synthesis_constituents=[ + Constituent(item={"type": "samples", "item_id": "parent"}, quantity=None), + ], + ) + + child_3 = Sample( + item_id="child_3", + synthesis_constituents=[ + Constituent(item={"type": "samples", "item_id": "parent"}, quantity=None), + ], + ) + + child_4 = Sample( + item_id="child_4", synthesis_constituents=[ Constituent(item={"type": "samples", "item_id": "parent"}, quantity=None), ], @@ -45,25 +60,30 @@ def test_simple_graph(admin_client): cell_format="swagelok", ) - new_samples = [json.loads(d.json()) for d in [parent, child_1, child_2, missing_child, cell]] + new_samples = [ + json.loads(d.json()) + for d in [parent, child_1, child_2, child_3, child_4, missing_child, cell] + ] - response = admin_client.post( + sample_list = admin_client.post( "/new-samples/", json={"new_sample_datas": new_samples}, ) - assert response.status_code == 207 - assert all(d == 201 for d in response.json["http_codes"]) + assert sample_list.status_code == 207 + assert all(d == 201 for d in sample_list.json["http_codes"]) graph = admin_client.get("/item-graph").json assert {n["data"]["id"] for n in graph["nodes"]} == { "parent", "child_1", "child_2", + "child_3", + "child_4", "missing_child", "abcd-1-2-3", } - assert len(graph["edges"]) == 4 + assert len(graph["edges"]) == 6 response = admin_client.post("/delete-sample/", json={"item_id": "missing_child"}) assert response @@ -73,18 +93,20 @@ def test_simple_graph(admin_client): "parent", "child_1", "child_2", + "child_3", + "child_4", "abcd-1-2-3", } - assert len(graph["edges"]) == 3 + assert len(graph["edges"]) == 5 graph = admin_client.get("/item-graph/child_1").json assert len(graph["nodes"]) == 2 assert len(graph["edges"]) == 1 graph = admin_client.get("/item-graph/parent").json - assert len(graph["nodes"]) == 4 - assert len(graph["edges"]) == 3 + assert len(graph["nodes"]) == 6 + assert len(graph["edges"]) == 5 collection_id = "testcoll" collection_json = { @@ -107,5 +129,32 @@ def test_simple_graph(admin_client): assert len(graph["edges"]) == 2 graph = admin_client.get("/item-graph/parent").json + assert len(graph["nodes"]) == 7 + assert len(graph["edges"]) == 10 + + samples = sample_list.json["responses"] + + refcode_child_3 = None + refcode_child_4 = None + + for item in samples: + if item["item_id"] == "child_3": + refcode_child_3 = item["sample_list_entry"].get("refcode") + elif item["item_id"] == "child_4": + refcode_child_4 = item["sample_list_entry"].get("refcode") + + response = admin_client.post( + f"/collections/{collection_id}", + json={"data": {"refcodes": [refcode_child_3, refcode_child_4]}}, + ) + + assert response.status_code == 200 + assert response.json["status"] == "success" + + graph = admin_client.get(f"/item-graph?collection_id={collection_id}").json assert len(graph["nodes"]) == 5 - assert len(graph["edges"]) == 8 + assert len(graph["edges"]) == 4 + + graph = admin_client.get("/item-graph/parent").json + assert len(graph["nodes"]) == 7 + assert len(graph["edges"]) == 14 diff --git a/pydatalab/tests/server/test_samples.py b/pydatalab/tests/server/test_samples.py index c8c55c2f6..6450e54a9 100644 --- a/pydatalab/tests/server/test_samples.py +++ b/pydatalab/tests/server/test_samples.py @@ -642,3 +642,56 @@ def test_items_added_to_existing_collection(client, default_collection, default_ len([d for d in response.json["item_data"]["relationships"] if d["type"] == "collections"]) == 1 ) + + +@pytest.mark.dependency() +def test_add_items_to_collection_not_found(client): + collection_id = "invalid_collection_id" + + response = client.post(f"/collections/{collection_id}", json={"data": {"refcodes": []}}) + assert response.status_code == 404 + assert response.json["error"] == "Collection not found" + + +@pytest.mark.dependency(depends=["test_add_items_to_collection_not_found"]) +def test_add_items_to_collection_no_items(client, default_collection): + response = client.post( + f"/collections/{default_collection.collection_id}", json={"data": {"refcodes": []}} + ) + + assert response.status_code == 400 + assert response.json["error"] == "No item provided" + + +@pytest.mark.dependency(depends=["test_add_items_to_collection_no_items"]) +def test_add_items_to_collection_no_matching_items(client, default_collection): + refcodes = ["item123", "item456"] + + response = client.post( + f"/collections/{default_collection.collection_id}", json={"data": {"refcodes": refcodes}} + ) + assert response.status_code == 404 + assert response.json["error"] == "No matching items found" + + +@pytest.mark.dependency(depends=["test_add_items_to_collection_no_matching_items"]) +def test_add_items_to_collection_success(client, default_collection, example_items): + refcodes = [ + item["refcode"] for item in example_items if item["item_id"] in {"12345", "sample_1"} + ] + + response = client.post( + f"/collections/{default_collection.collection_id}", + json={"data": {"refcodes": refcodes}}, + ) + + assert response.status_code == 200 + assert response.json["status"] == "success" + + response = client.get(f"/collections/{default_collection.collection_id}") + assert response.status_code == 200 + + collection_data = response.json + child_refcodes = [item["refcode"] for item in collection_data["child_items"]] + + assert all(refcode in child_refcodes for refcode in refcodes) diff --git a/webapp/src/components/AddToCollectionModal.vue b/webapp/src/components/AddToCollectionModal.vue index a7a88b96b..874cedb61 100644 --- a/webapp/src/components/AddToCollectionModal.vue +++ b/webapp/src/components/AddToCollectionModal.vue @@ -63,7 +63,7 @@ export default { methods: { async submitForm() { try { - const collectionIds = this.startInCollection.map((collection) => collection.immutable_id); + const collectionIds = this.startInCollection.map((collection) => collection.collection_id); const refcodes = this.itemsSelected.map((item) => item.refcode); for (const collectionId of collectionIds) { diff --git a/webapp/src/server_fetch_utils.js b/webapp/src/server_fetch_utils.js index 2ea5eae62..876392f00 100644 --- a/webapp/src/server_fetch_utils.js +++ b/webapp/src/server_fetch_utils.js @@ -513,6 +513,8 @@ export function addABlock(item_id, block_type, index = null) { export function saveItem(item_id) { console.log("saveItem Called!"); var item_data = store.state.all_item_data[item_id]; + console.log("Item data before saving:", item_data); + store.commit("setItemSaved", { item_id: item_id, isSaved: false }); fetch_post(`${API_URL}/save-item/`, { item_id: item_id, @@ -705,8 +707,8 @@ export function getBlocksInfos() { }); } -export function addItemsToCollection(collectionId, refcodes) { - return fetch_post(`${API_URL}/collections/${collectionId}`, { +export function addItemsToCollection(collection_id, refcodes) { + return fetch_post(`${API_URL}/collections/${collection_id}`, { data: { refcodes }, }) .then(function (response_json) {