|
96 | 96 | web::resource("/{dataset}/provenance") |
97 | 97 | .route(web::put().to(update_dataset_provenance_handler::<C>)), |
98 | 98 | ) |
| 99 | + .service( |
| 100 | + web::resource("/{dataset}/tiles/{tile}") |
| 101 | + .route(web::put().to(update_dataset_tile_handler::<C>)), |
| 102 | + ) |
99 | 103 | .service( |
100 | 104 | web::resource("/{dataset}/tiles") |
101 | 105 | .route(web::post().to(add_dataset_tiles_handler::<C>)) |
@@ -505,6 +509,66 @@ pub async fn get_dataset_tiles_handler<C: ApplicationContext>( |
505 | 509 | Ok(web::Json(tiles)) |
506 | 510 | } |
507 | 511 |
|
| 512 | +#[derive(Clone, Serialize, Deserialize, PartialEq, Debug, ToSchema)] |
| 513 | +pub struct UpdateDatasetTile { |
| 514 | + pub time: crate::api::model::datatypes::TimeInterval, |
| 515 | + pub spatial_partition: SpatialPartition2D, |
| 516 | + pub band: u32, |
| 517 | + pub z_index: u32, |
| 518 | + pub params: GdalDatasetParameters, |
| 519 | +} |
| 520 | + |
| 521 | +/// Retrieves details about a dataset using the internal name. |
| 522 | +#[utoipa::path( |
| 523 | + tag = "Datasets", |
| 524 | + put, |
| 525 | + path = "/dataset/{dataset}/tiles/{tile}", |
| 526 | + responses( |
| 527 | + (status = 200, description = "OK"), |
| 528 | + (status = 401, response = crate::api::model::responses::UnauthorizedUserResponse) |
| 529 | + ), |
| 530 | + params( |
| 531 | + ("dataset" = DatasetName, description = "Dataset Name"), |
| 532 | + ("tile" = DatasetTileId, description = "Tile Id"), |
| 533 | + ), |
| 534 | + security( |
| 535 | + ("session_token" = []) |
| 536 | + ) |
| 537 | +)] |
| 538 | +pub async fn update_dataset_tile_handler<C: ApplicationContext>( |
| 539 | + dataset: web::Path<(DatasetName, DatasetTileId)>, |
| 540 | + session: C::Session, |
| 541 | + tile: web::Json<UpdateDatasetTile>, |
| 542 | + app_ctx: web::Data<C>, |
| 543 | +) -> Result<impl Responder, UpdateDatasetTileError> { |
| 544 | + let session_ctx = app_ctx.session_context(session).db(); |
| 545 | + |
| 546 | + let (dataset, tile_id) = dataset.into_inner(); |
| 547 | + |
| 548 | + let real_dataset = dataset; |
| 549 | + |
| 550 | + let dataset_id = session_ctx |
| 551 | + .resolve_dataset_name_to_id(&real_dataset) |
| 552 | + .await |
| 553 | + .context(CannotLoadDatasetForUpdatingTile)?; |
| 554 | + |
| 555 | + // handle the case where the dataset name is not known |
| 556 | + let dataset_id = dataset_id |
| 557 | + .ok_or(error::Error::UnknownDatasetName { |
| 558 | + dataset_name: real_dataset.to_string(), |
| 559 | + }) |
| 560 | + .context(CannotLoadDatasetForUpdatingTile)?; |
| 561 | + |
| 562 | + // TODO: validate the tile like in add tiles |
| 563 | + |
| 564 | + session_ctx |
| 565 | + .update_dataset_tile(dataset_id, tile_id, tile.into_inner()) |
| 566 | + .await |
| 567 | + .context(CannotUpdateDatasetTile)?; |
| 568 | + |
| 569 | + Ok(HttpResponse::Ok()) |
| 570 | +} |
| 571 | + |
508 | 572 | /// Update details about a dataset using the internal name. |
509 | 573 | #[utoipa::path( |
510 | 574 | tag = "Datasets", |
@@ -5463,4 +5527,140 @@ mod tests { |
5463 | 5527 |
|
5464 | 5528 | Ok(()) |
5465 | 5529 | } |
| 5530 | + |
| 5531 | + #[ge_context::test] |
| 5532 | + #[allow(clippy::too_many_lines)] |
| 5533 | + async fn it_gets_and_updates_tiles(app_ctx: PostgresContext<NoTls>) -> Result<()> { |
| 5534 | + let volume = VolumeName("test_data".to_string()); |
| 5535 | + |
| 5536 | + // add data |
| 5537 | + let create = CreateDataset { |
| 5538 | + data_path: DataPath::Volume(volume.clone()), |
| 5539 | + definition: DatasetDefinition { |
| 5540 | + properties: AddDataset { |
| 5541 | + name: None, |
| 5542 | + display_name: "ndvi (tiled)".to_string(), |
| 5543 | + description: "ndvi".to_string(), |
| 5544 | + source_operator: "MultiBandGdalSource".to_string(), |
| 5545 | + symbology: None, |
| 5546 | + provenance: None, |
| 5547 | + tags: Some(vec!["upload".to_owned(), "test".to_owned()]), |
| 5548 | + }, |
| 5549 | + meta_data: MetaDataDefinition::GdalMultiBand(GdalMultiBand { |
| 5550 | + r#type: Default::default(), |
| 5551 | + result_descriptor: create_ndvi_result_descriptor(true).into(), |
| 5552 | + }), |
| 5553 | + }, |
| 5554 | + }; |
| 5555 | + |
| 5556 | + let session = admin_login(&app_ctx).await; |
| 5557 | + let ctx = app_ctx.session_context(session.clone()); |
| 5558 | + |
| 5559 | + let db = ctx.db(); |
| 5560 | + |
| 5561 | + let req = actix_web::test::TestRequest::post() |
| 5562 | + .uri("/dataset") |
| 5563 | + .append_header((header::CONTENT_LENGTH, 0)) |
| 5564 | + .append_header((header::AUTHORIZATION, Bearer::new(session.id().to_string()))) |
| 5565 | + .append_header((header::CONTENT_TYPE, "application/json")) |
| 5566 | + .set_payload(serde_json::to_string(&create)?); |
| 5567 | + let res = send_test_request(req, app_ctx.clone()).await; |
| 5568 | + |
| 5569 | + let DatasetNameResponse { dataset_name } = actix_web::test::read_body_json(res).await; |
| 5570 | + let dataset_id = db |
| 5571 | + .resolve_dataset_name_to_id(&dataset_name) |
| 5572 | + .await |
| 5573 | + .unwrap() |
| 5574 | + .unwrap(); |
| 5575 | + |
| 5576 | + assert!(db.load_dataset(&dataset_id).await.is_ok()); |
| 5577 | + |
| 5578 | + // add tile |
| 5579 | + let tiles = create_ndvi_tiles()[0..1].to_vec(); |
| 5580 | + |
| 5581 | + let req = actix_web::test::TestRequest::post() |
| 5582 | + .uri(&format!("/dataset/{dataset_name}/tiles")) |
| 5583 | + .append_header((header::CONTENT_LENGTH, 0)) |
| 5584 | + .append_header((header::AUTHORIZATION, Bearer::new(session.id().to_string()))) |
| 5585 | + .append_header((header::CONTENT_TYPE, "application/json")) |
| 5586 | + .set_payload(serde_json::to_string(&tiles)?); |
| 5587 | + |
| 5588 | + let res = send_test_request(req, app_ctx.clone()).await; |
| 5589 | + assert_eq!( |
| 5590 | + res.status(), |
| 5591 | + 200, |
| 5592 | + "response: {read_body}", |
| 5593 | + read_body = actix_web::test::read_body_json::<ErrorResponse, _>(res).await |
| 5594 | + ); |
| 5595 | + |
| 5596 | + // get tile |
| 5597 | + let req = actix_web::test::TestRequest::get() |
| 5598 | + .uri(&format!("/dataset/{dataset_name}/tiles?offset=0&limit=10")) |
| 5599 | + .append_header((header::AUTHORIZATION, Bearer::new(session.id().to_string()))); |
| 5600 | + |
| 5601 | + let res = send_test_request(req, app_ctx.clone()).await; |
| 5602 | + assert_eq!( |
| 5603 | + res.status(), |
| 5604 | + 200, |
| 5605 | + "response: {read_body}", |
| 5606 | + read_body = actix_web::test::read_body_json::<ErrorResponse, _>(res).await |
| 5607 | + ); |
| 5608 | + |
| 5609 | + let returned_tiles: Vec<DatasetTile> = actix_web::test::read_body_json(res).await; |
| 5610 | + assert_eq!(returned_tiles.len(), 1); |
| 5611 | + assert_eq!( |
| 5612 | + returned_tiles[0], |
| 5613 | + DatasetTile { |
| 5614 | + id: returned_tiles[0].id, |
| 5615 | + time: tiles[0].time.clone(), |
| 5616 | + spatial_partition: tiles[0].spatial_partition.clone(), |
| 5617 | + band: tiles[0].band, |
| 5618 | + z_index: tiles[0].z_index, |
| 5619 | + params: tiles[0].params.clone() |
| 5620 | + } |
| 5621 | + ); |
| 5622 | + |
| 5623 | + let update_tile = UpdateDatasetTile { |
| 5624 | + time: tiles[0].time.clone(), |
| 5625 | + spatial_partition: tiles[0].spatial_partition.clone(), |
| 5626 | + band: tiles[0].band, |
| 5627 | + z_index: tiles[0].z_index + 1, |
| 5628 | + params: tiles[0].params.clone(), |
| 5629 | + }; |
| 5630 | + |
| 5631 | + let req = actix_web::test::TestRequest::put() |
| 5632 | + .uri(&format!( |
| 5633 | + "/dataset/{dataset_name}/tiles/{}", |
| 5634 | + returned_tiles[0].id |
| 5635 | + )) |
| 5636 | + .append_header((header::AUTHORIZATION, Bearer::new(session.id().to_string()))) |
| 5637 | + .append_header((header::CONTENT_TYPE, "application/json")) |
| 5638 | + .set_payload(serde_json::to_string(&update_tile)?); |
| 5639 | + |
| 5640 | + let res = send_test_request(req, app_ctx.clone()).await; |
| 5641 | + assert_eq!(res.status(), 200, "response: {res:?}"); |
| 5642 | + |
| 5643 | + let req = actix_web::test::TestRequest::get() |
| 5644 | + .uri(&format!("/dataset/{dataset_name}/tiles?offset=0&limit=10")) |
| 5645 | + .append_header((header::AUTHORIZATION, Bearer::new(session.id().to_string()))); |
| 5646 | + |
| 5647 | + let res = send_test_request(req, app_ctx.clone()).await; |
| 5648 | + assert_eq!(res.status(), 200, "response: {res:?}"); |
| 5649 | + |
| 5650 | + let returned_tiles: Vec<DatasetTile> = actix_web::test::read_body_json(res).await; |
| 5651 | + assert_eq!(returned_tiles.len(), 1); |
| 5652 | + assert_eq!( |
| 5653 | + returned_tiles[0], |
| 5654 | + DatasetTile { |
| 5655 | + id: returned_tiles[0].id, |
| 5656 | + time: tiles[0].time.clone(), |
| 5657 | + spatial_partition: tiles[0].spatial_partition.clone(), |
| 5658 | + band: tiles[0].band, |
| 5659 | + z_index: tiles[0].z_index + 1, |
| 5660 | + params: tiles[0].params.clone() |
| 5661 | + } |
| 5662 | + ); |
| 5663 | + |
| 5664 | + Ok(()) |
| 5665 | + } |
5466 | 5666 | } |
0 commit comments