mirror of
https://github.com/meilisearch/MeiliSearch
synced 2024-11-22 12:54:26 +01:00
Add indexUid filtering on the /tasks route
This commit is contained in:
parent
80f7d87356
commit
3684c822f1
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -2046,6 +2046,7 @@ dependencies = [
|
|||||||
"rustls-pemfile",
|
"rustls-pemfile",
|
||||||
"segment",
|
"segment",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde-cs",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_url_params",
|
"serde_url_params",
|
||||||
"sha-1",
|
"sha-1",
|
||||||
@ -3085,6 +3086,15 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde-cs"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "18d5b0435c9139761fbe5abeb1283234bcfbde88fadc2ae432579648fbce72ad"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.136"
|
version = "1.0.136"
|
||||||
|
@ -62,6 +62,7 @@ rustls = "0.20.4"
|
|||||||
rustls-pemfile = "0.3.0"
|
rustls-pemfile = "0.3.0"
|
||||||
segment = { version = "0.2.0", optional = true }
|
segment = { version = "0.2.0", optional = true }
|
||||||
serde = { version = "1.0.136", features = ["derive"] }
|
serde = { version = "1.0.136", features = ["derive"] }
|
||||||
|
serde-cs = "0.2.2"
|
||||||
serde_json = { version = "1.0.79", features = ["preserve_order"] }
|
serde_json = { version = "1.0.79", features = ["preserve_order"] }
|
||||||
sha2 = "0.10.2"
|
sha2 = "0.10.2"
|
||||||
siphasher = "0.3.10"
|
siphasher = "0.3.10"
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod analytics;
|
pub mod analytics;
|
||||||
mod task;
|
pub mod task;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod extractors;
|
pub mod extractors;
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
|
@ -2,21 +2,33 @@ use actix_web::{web, HttpRequest, HttpResponse};
|
|||||||
use meilisearch_error::ResponseError;
|
use meilisearch_error::ResponseError;
|
||||||
use meilisearch_lib::tasks::task::TaskId;
|
use meilisearch_lib::tasks::task::TaskId;
|
||||||
use meilisearch_lib::tasks::TaskFilter;
|
use meilisearch_lib::tasks::TaskFilter;
|
||||||
use meilisearch_lib::MeiliSearch;
|
use meilisearch_lib::{IndexUid, MeiliSearch};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde_cs::vec::CS;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::analytics::Analytics;
|
use crate::analytics::Analytics;
|
||||||
use crate::extractors::authentication::{policies::*, GuardedData};
|
use crate::extractors::authentication::{policies::*, GuardedData};
|
||||||
use crate::extractors::sequential_extractor::SeqHandler;
|
use crate::extractors::sequential_extractor::SeqHandler;
|
||||||
use crate::task::{TaskListView, TaskView};
|
use crate::task::{TaskListView, TaskStatus, TaskType, TaskView};
|
||||||
|
|
||||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(web::resource("").route(web::get().to(SeqHandler(get_tasks))))
|
cfg.service(web::resource("").route(web::get().to(SeqHandler(get_tasks))))
|
||||||
.service(web::resource("/{task_id}").route(web::get().to(SeqHandler(get_task))));
|
.service(web::resource("/{task_id}").route(web::get().to(SeqHandler(get_task))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||||
|
pub struct TasksFilter {
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
type_: Option<CS<TaskType>>,
|
||||||
|
status: Option<CS<TaskStatus>>,
|
||||||
|
index_uid: Option<CS<IndexUid>>,
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_tasks(
|
async fn get_tasks(
|
||||||
meilisearch: GuardedData<ActionPolicy<{ actions::TASKS_GET }>, MeiliSearch>,
|
meilisearch: GuardedData<ActionPolicy<{ actions::TASKS_GET }>, MeiliSearch>,
|
||||||
|
params: web::Query<TasksFilter>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
analytics: web::Data<dyn Analytics>,
|
analytics: web::Data<dyn Analytics>,
|
||||||
) -> Result<HttpResponse, ResponseError> {
|
) -> Result<HttpResponse, ResponseError> {
|
||||||
@ -26,15 +38,34 @@ async fn get_tasks(
|
|||||||
Some(&req),
|
Some(&req),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let TasksFilter {
|
||||||
|
type_,
|
||||||
|
status,
|
||||||
|
index_uid,
|
||||||
|
} = params.into_inner();
|
||||||
|
|
||||||
let search_rules = &meilisearch.filters().search_rules;
|
let search_rules = &meilisearch.filters().search_rules;
|
||||||
let filters = if search_rules.is_index_authorized("*") {
|
let filters = match index_uid {
|
||||||
None
|
Some(indexes) => {
|
||||||
} else {
|
let mut filters = TaskFilter::default();
|
||||||
let mut filters = TaskFilter::default();
|
for name in indexes.into_inner() {
|
||||||
for (index, _policy) in search_rules.clone() {
|
if search_rules.is_index_authorized(&name) {
|
||||||
filters.filter_index(index);
|
filters.filter_index(name.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(filters)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if search_rules.is_index_authorized("*") {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let mut filters = TaskFilter::default();
|
||||||
|
for (index, _policy) in search_rules.clone() {
|
||||||
|
filters.filter_index(index);
|
||||||
|
}
|
||||||
|
Some(filters)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some(filters)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let tasks: TaskListView = meilisearch
|
let tasks: TaskListView = meilisearch
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
use std::str::FromStr;
|
||||||
use std::write;
|
use std::write;
|
||||||
|
|
||||||
use meilisearch_error::ResponseError;
|
use meilisearch_error::ResponseError;
|
||||||
@ -8,14 +9,14 @@ use meilisearch_lib::tasks::batch::BatchId;
|
|||||||
use meilisearch_lib::tasks::task::{
|
use meilisearch_lib::tasks::task::{
|
||||||
DocumentDeletion, Task, TaskContent, TaskEvent, TaskId, TaskResult,
|
DocumentDeletion, Task, TaskContent, TaskEvent, TaskId, TaskResult,
|
||||||
};
|
};
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
use time::{Duration, OffsetDateTime};
|
use time::{Duration, OffsetDateTime};
|
||||||
|
|
||||||
use crate::AUTOBATCHING_ENABLED;
|
use crate::AUTOBATCHING_ENABLED;
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
enum TaskType {
|
pub enum TaskType {
|
||||||
IndexCreation,
|
IndexCreation,
|
||||||
IndexUpdate,
|
IndexUpdate,
|
||||||
IndexDeletion,
|
IndexDeletion,
|
||||||
@ -50,15 +51,47 @@ impl From<TaskContent> for TaskType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
impl FromStr for TaskType {
|
||||||
|
type Err = &'static str;
|
||||||
|
|
||||||
|
fn from_str(status: &str) -> Result<Self, &'static str> {
|
||||||
|
match status {
|
||||||
|
"indexCreation" => Ok(TaskType::IndexCreation),
|
||||||
|
"indexUpdate" => Ok(TaskType::IndexUpdate),
|
||||||
|
"indexDeletion" => Ok(TaskType::IndexDeletion),
|
||||||
|
"documentAddition" => Ok(TaskType::DocumentAddition),
|
||||||
|
"documentPartial" => Ok(TaskType::DocumentPartial),
|
||||||
|
"documentDeletion" => Ok(TaskType::DocumentDeletion),
|
||||||
|
"settingsUpdate" => Ok(TaskType::SettingsUpdate),
|
||||||
|
"clearAll" => Ok(TaskType::ClearAll),
|
||||||
|
_ => Err("invalid task type value"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
enum TaskStatus {
|
pub enum TaskStatus {
|
||||||
Enqueued,
|
Enqueued,
|
||||||
Processing,
|
Processing,
|
||||||
Succeeded,
|
Succeeded,
|
||||||
Failed,
|
Failed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for TaskStatus {
|
||||||
|
type Err = &'static str;
|
||||||
|
|
||||||
|
fn from_str(status: &str) -> Result<Self, &'static str> {
|
||||||
|
match status {
|
||||||
|
"enqueued" => Ok(TaskStatus::Enqueued),
|
||||||
|
"processing" => Ok(TaskStatus::Processing),
|
||||||
|
"succeeded" => Ok(TaskStatus::Succeeded),
|
||||||
|
"failed" => Ok(TaskStatus::Failed),
|
||||||
|
_ => Err("invalid task status value"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
@ -16,8 +16,8 @@ pub static AUTHORIZATIONS: Lazy<HashMap<(&'static str, &'static str), HashSet<&'
|
|||||||
("GET", "/indexes/products/documents/0") => hashset!{"documents.get", "*"},
|
("GET", "/indexes/products/documents/0") => hashset!{"documents.get", "*"},
|
||||||
("DELETE", "/indexes/products/documents/0") => hashset!{"documents.delete", "*"},
|
("DELETE", "/indexes/products/documents/0") => hashset!{"documents.delete", "*"},
|
||||||
("GET", "/tasks") => hashset!{"tasks.get", "*"},
|
("GET", "/tasks") => hashset!{"tasks.get", "*"},
|
||||||
("GET", "/indexes/products/tasks") => hashset!{"tasks.get", "*"},
|
("GET", "/tasks?indexUid=products") => hashset!{"tasks.get", "*"},
|
||||||
("GET", "/indexes/products/tasks/0") => hashset!{"tasks.get", "*"},
|
("GET", "/tasks/0") => hashset!{"tasks.get", "*"},
|
||||||
("PUT", "/indexes/products/") => hashset!{"indexes.update", "*"},
|
("PUT", "/indexes/products/") => hashset!{"indexes.update", "*"},
|
||||||
("GET", "/indexes/products/") => hashset!{"indexes.get", "*"},
|
("GET", "/indexes/products/") => hashset!{"indexes.get", "*"},
|
||||||
("DELETE", "/indexes/products/") => hashset!{"indexes.delete", "*"},
|
("DELETE", "/indexes/products/") => hashset!{"indexes.delete", "*"},
|
||||||
|
@ -122,12 +122,12 @@ impl Index<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_task(&self, update_id: u64) -> (Value, StatusCode) {
|
pub async fn get_task(&self, update_id: u64) -> (Value, StatusCode) {
|
||||||
let url = format!("/indexes/{}/tasks/{}", self.uid, update_id);
|
let url = format!("/tasks/{}", update_id);
|
||||||
self.service.get(url).await
|
self.service.get(url).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_tasks(&self) -> (Value, StatusCode) {
|
pub async fn list_tasks(&self) -> (Value, StatusCode) {
|
||||||
let url = format!("/indexes/{}/tasks", self.uid);
|
let url = format!("/tasks?indexUid={}", self.uid);
|
||||||
self.service.get(url).await
|
self.service.get(url).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,22 +3,6 @@ use serde_json::json;
|
|||||||
use time::format_description::well_known::Rfc3339;
|
use time::format_description::well_known::Rfc3339;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
#[actix_rt::test]
|
|
||||||
async fn error_get_task_unexisting_index() {
|
|
||||||
let server = Server::new().await;
|
|
||||||
let (response, code) = server.service.get("/indexes/test/tasks").await;
|
|
||||||
|
|
||||||
let expected_response = json!({
|
|
||||||
"message": "Index `test` not found.",
|
|
||||||
"code": "index_not_found",
|
|
||||||
"type": "invalid_request",
|
|
||||||
"link": "https://docs.meilisearch.com/errors#index_not_found"
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(response, expected_response);
|
|
||||||
assert_eq!(code, 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn error_get_unexisting_task_status() {
|
async fn error_get_unexisting_task_status() {
|
||||||
let server = Server::new().await;
|
let server = Server::new().await;
|
||||||
@ -58,22 +42,6 @@ async fn get_task_status() {
|
|||||||
// TODO check resonse format, as per #48
|
// TODO check resonse format, as per #48
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
|
||||||
async fn error_list_tasks_unexisting_index() {
|
|
||||||
let server = Server::new().await;
|
|
||||||
let (response, code) = server.index("test").list_tasks().await;
|
|
||||||
|
|
||||||
let expected_response = json!({
|
|
||||||
"message": "Index `test` not found.",
|
|
||||||
"code": "index_not_found",
|
|
||||||
"type": "invalid_request",
|
|
||||||
"link": "https://docs.meilisearch.com/errors#index_not_found"
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(response, expected_response);
|
|
||||||
assert_eq!(code, 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn list_tasks() {
|
async fn list_tasks() {
|
||||||
let server = Server::new().await;
|
let server = Server::new().await;
|
||||||
|
@ -35,7 +35,8 @@ use error::Result;
|
|||||||
use self::error::IndexControllerError;
|
use self::error::IndexControllerError;
|
||||||
use crate::index_resolver::index_store::{IndexStore, MapIndexStore};
|
use crate::index_resolver::index_store::{IndexStore, MapIndexStore};
|
||||||
use crate::index_resolver::meta_store::{HeedMetaStore, IndexMetaStore};
|
use crate::index_resolver::meta_store::{HeedMetaStore, IndexMetaStore};
|
||||||
use crate::index_resolver::{create_index_resolver, IndexResolver, IndexUid};
|
pub use crate::index_resolver::IndexUid;
|
||||||
|
use crate::index_resolver::{create_index_resolver, IndexResolver};
|
||||||
use crate::update_file_store::UpdateFileStore;
|
use crate::update_file_store::UpdateFileStore;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
@ -4,6 +4,7 @@ pub mod meta_store;
|
|||||||
|
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use error::{IndexResolverError, Result};
|
use error::{IndexResolverError, Result};
|
||||||
@ -88,6 +89,14 @@ impl TryInto<IndexUid> for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for IndexUid {
|
||||||
|
type Err = IndexResolverError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<IndexUid> {
|
||||||
|
IndexUid::new(s.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct IndexResolver<U, I> {
|
pub struct IndexResolver<U, I> {
|
||||||
index_uuid_store: U,
|
index_uuid_store: U,
|
||||||
index_store: I,
|
index_store: I,
|
||||||
|
@ -13,7 +13,7 @@ mod update_file_store;
|
|||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub use index_controller::MeiliSearch;
|
pub use index_controller::{IndexUid, MeiliSearch};
|
||||||
pub use milli;
|
pub use milli;
|
||||||
pub use milli::heed;
|
pub use milli::heed;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user