mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-07-27 08:41:00 +00:00
Format
This commit is contained in:
@ -138,7 +138,9 @@ pub trait Policy {
|
|||||||
auth: Data<AuthController>,
|
auth: Data<AuthController>,
|
||||||
token: &str,
|
token: &str,
|
||||||
index: Option<&str>,
|
index: Option<&str>,
|
||||||
) -> Result<AuthFilter, policies::AuthError> where Self: Sized;
|
) -> Result<AuthFilter, policies::AuthError>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod policies {
|
pub mod policies {
|
||||||
|
@ -424,7 +424,8 @@ async fn render(index: Index, query: RenderQuery) -> Result<RenderResult, Render
|
|||||||
|
|
||||||
fragment.clone()
|
fragment.clone()
|
||||||
}
|
}
|
||||||
found => return Err(UnknownTemplatePrefix {
|
found => {
|
||||||
|
return Err(UnknownTemplatePrefix {
|
||||||
embedder_name: embedder_name.to_string(),
|
embedder_name: embedder_name.to_string(),
|
||||||
found: found.to_string(),
|
found: found.to_string(),
|
||||||
available_indexing_fragments: embedding_config
|
available_indexing_fragments: embedding_config
|
||||||
@ -435,7 +436,8 @@ async fn render(index: Index, query: RenderQuery) -> Result<RenderResult, Render
|
|||||||
.config
|
.config
|
||||||
.embedder_options
|
.embedder_options
|
||||||
.search_fragments(),
|
.search_fragments(),
|
||||||
}),
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"chatCompletions" | "chatcompletions" => {
|
"chatCompletions" | "chatcompletions" => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use ::time::format_description::well_known::Rfc3339;
|
use ::time::format_description::well_known::Rfc3339;
|
||||||
use maplit::{hashmap};
|
use maplit::hashmap;
|
||||||
use meilisearch::Opt;
|
use meilisearch::Opt;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
@ -33,8 +33,9 @@ macro_rules! hashset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub static AUTHORIZATIONS: Lazy<HashMap<(&'static str, &'static str), HashSet<&'static [&'static str]>>> =
|
pub static AUTHORIZATIONS: Lazy<
|
||||||
Lazy::new(|| {
|
HashMap<(&'static str, &'static str), HashSet<&'static [&'static str]>>,
|
||||||
|
> = Lazy::new(|| {
|
||||||
let authorizations = hashmap! {
|
let authorizations = hashmap! {
|
||||||
("POST", "/multi-search") => hashset!{"search", "*"},
|
("POST", "/multi-search") => hashset!{"search", "*"},
|
||||||
("POST", "/indexes/products/search") => hashset!{"search", "*"},
|
("POST", "/indexes/products/search") => hashset!{"search", "*"},
|
||||||
@ -100,7 +101,12 @@ pub static AUTHORIZATIONS: Lazy<HashMap<(&'static str, &'static str), HashSet<&'
|
|||||||
});
|
});
|
||||||
|
|
||||||
pub static ALL_ACTIONS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
|
pub static ALL_ACTIONS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
|
||||||
AUTHORIZATIONS.values().flat_map(|v| v.iter()).flat_map(|v| v.iter()).copied().collect::<HashSet<_>>()
|
AUTHORIZATIONS
|
||||||
|
.values()
|
||||||
|
.flat_map(|v| v.iter())
|
||||||
|
.flat_map(|v| v.iter())
|
||||||
|
.copied()
|
||||||
|
.collect::<HashSet<_>>()
|
||||||
});
|
});
|
||||||
|
|
||||||
static INVALID_RESPONSE: Lazy<Value> = Lazy::new(|| {
|
static INVALID_RESPONSE: Lazy<Value> = Lazy::new(|| {
|
||||||
@ -298,7 +304,11 @@ async fn unauthorized_partial_actions() {
|
|||||||
// create a new API key letting all actions except one.
|
// create a new API key letting all actions except one.
|
||||||
server.use_api_key(MASTER_KEY);
|
server.use_api_key(MASTER_KEY);
|
||||||
|
|
||||||
let actions = actions.iter().filter(|&a| a != excluded_action).copied().collect::<HashSet<_>>();
|
let actions = actions
|
||||||
|
.iter()
|
||||||
|
.filter(|&a| a != excluded_action)
|
||||||
|
.copied()
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
let content = json!({
|
let content = json!({
|
||||||
"indexes": ["products"],
|
"indexes": ["products"],
|
||||||
"actions": actions,
|
"actions": actions,
|
||||||
@ -315,7 +325,14 @@ async fn unauthorized_partial_actions() {
|
|||||||
let (mut response, code) = server.dummy_request(method, route).await;
|
let (mut response, code) = server.dummy_request(method, route).await;
|
||||||
response["message"] = serde_json::json!(null);
|
response["message"] = serde_json::json!(null);
|
||||||
|
|
||||||
assert_eq!(response, INVALID_RESPONSE.clone(), "on route: {:?} - {:?} with actions: {:?}", method, route, actions);
|
assert_eq!(
|
||||||
|
response,
|
||||||
|
INVALID_RESPONSE.clone(),
|
||||||
|
"on route: {:?} - {:?} with actions: {:?}",
|
||||||
|
method,
|
||||||
|
route,
|
||||||
|
actions
|
||||||
|
);
|
||||||
assert_eq!(code, 403, "{:?}", &response);
|
assert_eq!(code, 403, "{:?}", &response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,7 +372,11 @@ async fn access_authorized_no_index_restriction() {
|
|||||||
route,
|
route,
|
||||||
actions
|
actions
|
||||||
);
|
);
|
||||||
assert_ne!(code, 403, "on route: {:?} - {:?} with action: {:?}", method, route, actions);
|
assert_ne!(
|
||||||
|
code, 403,
|
||||||
|
"on route: {:?} - {:?} with action: {:?}",
|
||||||
|
method, route, actions
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -793,7 +814,13 @@ async fn error_creating_index_without_action() {
|
|||||||
server.use_api_key(MASTER_KEY);
|
server.use_api_key(MASTER_KEY);
|
||||||
|
|
||||||
// create key with access on all indexes.
|
// create key with access on all indexes.
|
||||||
let create_index_actions = AUTHORIZATIONS.get(&("POST","/indexes")).unwrap().iter().flat_map(|s| s.iter()).cloned().collect::<HashSet<_>>();
|
let create_index_actions = AUTHORIZATIONS
|
||||||
|
.get(&("POST", "/indexes"))
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.flat_map(|s| s.iter())
|
||||||
|
.cloned()
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
let content = json!({
|
let content = json!({
|
||||||
"indexes": ["*"],
|
"indexes": ["*"],
|
||||||
// Give all action but the ones allowing to create an index.
|
// Give all action but the ones allowing to create an index.
|
||||||
|
@ -457,10 +457,7 @@ impl<State> Index<'_, State> {
|
|||||||
self.service.get(url).await
|
self.service.get(url).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn render(
|
pub async fn render(&self, query: Value) -> (Value, StatusCode) {
|
||||||
&self,
|
|
||||||
query: Value
|
|
||||||
) -> (Value, StatusCode) {
|
|
||||||
let url = format!("/indexes/{}/render", urlencode(self.uid.as_ref()));
|
let url = format!("/indexes/{}/render", urlencode(self.uid.as_ref()));
|
||||||
self.service.post_encoded(url, query, self.encoder).await
|
self.service.post_encoded(url, query, self.encoder).await
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,5 @@ mod add_documents;
|
|||||||
mod delete_documents;
|
mod delete_documents;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod get_documents;
|
mod get_documents;
|
||||||
mod update_documents;
|
|
||||||
mod render_documents;
|
mod render_documents;
|
||||||
|
mod update_documents;
|
||||||
|
@ -6,13 +6,7 @@ use meili_snap::snapshot;
|
|||||||
async fn empty_id() {
|
async fn empty_id() {
|
||||||
let index = shared_index_for_fragments().await;
|
let index = shared_index_for_fragments().await;
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) = index.render(json! {{ "template": { "id": "" }}}).await;
|
||||||
.render(json! {{
|
|
||||||
"template": {
|
|
||||||
"id": ""
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
{
|
{
|
||||||
@ -28,13 +22,7 @@ async fn empty_id() {
|
|||||||
async fn wrong_id_prefix() {
|
async fn wrong_id_prefix() {
|
||||||
let index = shared_index_for_fragments().await;
|
let index = shared_index_for_fragments().await;
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) = index.render(json! {{ "template": { "id": "wrong.disregarded" }}}).await;
|
||||||
.render(json! {{
|
|
||||||
"template": {
|
|
||||||
"id": "wrong.disregarded"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
{
|
{
|
||||||
@ -50,13 +38,7 @@ async fn wrong_id_prefix() {
|
|||||||
async fn missing_embedder() {
|
async fn missing_embedder() {
|
||||||
let index = shared_index_for_fragments().await;
|
let index = shared_index_for_fragments().await;
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) = index.render(json! {{ "template": { "id": "embedders" }}}).await;
|
||||||
.render(json! {{
|
|
||||||
"template": {
|
|
||||||
"id": "embedders"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
{
|
{
|
||||||
@ -72,13 +54,8 @@ async fn missing_embedder() {
|
|||||||
async fn wrong_embedder() {
|
async fn wrong_embedder() {
|
||||||
let index = shared_index_for_fragments().await;
|
let index = shared_index_for_fragments().await;
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) =
|
||||||
.render(json! {{
|
index.render(json! {{ "template": { "id": "embedders.wrong.disregarded" }}}).await;
|
||||||
"template": {
|
|
||||||
"id": "embedders.wrong.disregarded"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
{
|
{
|
||||||
@ -94,13 +71,7 @@ async fn wrong_embedder() {
|
|||||||
async fn missing_template_kind() {
|
async fn missing_template_kind() {
|
||||||
let index = shared_index_for_fragments().await;
|
let index = shared_index_for_fragments().await;
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) = index.render(json! {{ "template": { "id": "embedders.rest" }}}).await;
|
||||||
.render(json! {{
|
|
||||||
"template": {
|
|
||||||
"id": "embedders.rest"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
{
|
{
|
||||||
@ -116,13 +87,8 @@ async fn missing_template_kind() {
|
|||||||
async fn wrong_template_kind() {
|
async fn wrong_template_kind() {
|
||||||
let index = shared_index_for_fragments().await;
|
let index = shared_index_for_fragments().await;
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) =
|
||||||
.render(json! {{
|
index.render(json! {{ "template": { "id": "embedders.rest.wrong.disregarded" }}}).await;
|
||||||
"template": {
|
|
||||||
"id": "embedders.rest.wrong.disregarded"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
{
|
{
|
||||||
@ -138,13 +104,8 @@ async fn wrong_template_kind() {
|
|||||||
async fn document_template_on_fragmented_index() {
|
async fn document_template_on_fragmented_index() {
|
||||||
let index = shared_index_for_fragments().await;
|
let index = shared_index_for_fragments().await;
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) =
|
||||||
.render(json! {{
|
index.render(json! {{ "template": { "id": "embedders.rest.documentTemplate" }}}).await;
|
||||||
"template": {
|
|
||||||
"id": "embedders.rest.documentTemplate"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
{
|
{
|
||||||
@ -160,13 +121,8 @@ async fn document_template_on_fragmented_index() {
|
|||||||
async fn missing_fragment_name() {
|
async fn missing_fragment_name() {
|
||||||
let index = shared_index_for_fragments().await;
|
let index = shared_index_for_fragments().await;
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) =
|
||||||
.render(json! {{
|
index.render(json! {{ "template": { "id": "embedders.rest.indexingFragments" }}}).await;
|
||||||
"template": {
|
|
||||||
"id": "embedders.rest.indexingFragments"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
{
|
{
|
||||||
@ -177,13 +133,8 @@ async fn missing_fragment_name() {
|
|||||||
}
|
}
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) =
|
||||||
.render(json! {{
|
index.render(json! {{ "template": { "id": "embedders.rest.searchFragments" }}}).await;
|
||||||
"template": {
|
|
||||||
"id": "embedders.rest.searchFragments"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
{
|
{
|
||||||
@ -200,11 +151,7 @@ async fn wrong_fragment_name() {
|
|||||||
let index = shared_index_for_fragments().await;
|
let index = shared_index_for_fragments().await;
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) = index
|
||||||
.render(json! {{
|
.render(json! {{ "template": { "id": "embedders.rest.indexingFragments.wrong" }}})
|
||||||
"template": {
|
|
||||||
"id": "embedders.rest.indexingFragments.wrong"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
.await;
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
@ -216,13 +163,8 @@ async fn wrong_fragment_name() {
|
|||||||
}
|
}
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) =
|
||||||
.render(json! {{
|
index.render(json! {{ "template": { "id": "embedders.rest.searchFragments.wrong" }}}).await;
|
||||||
"template": {
|
|
||||||
"id": "embedders.rest.searchFragments.wrong"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
{
|
{
|
||||||
@ -239,11 +181,9 @@ async fn leftover_tokens() {
|
|||||||
let index = shared_index_for_fragments().await;
|
let index = shared_index_for_fragments().await;
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) = index
|
||||||
.render(json! {{
|
.render(
|
||||||
"template": {
|
json! {{ "template": { "id": "embedders.rest.indexingFragments.withBreed.leftover" }}},
|
||||||
"id": "embedders.rest.indexingFragments.withBreed.leftover"
|
)
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
.await;
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
@ -256,11 +196,7 @@ async fn leftover_tokens() {
|
|||||||
"#);
|
"#);
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) = index
|
||||||
.render(json! {{
|
.render(json! {{"template": { "id": "embedders.rest.searchFragments.justBreed.leftover" }}})
|
||||||
"template": {
|
|
||||||
"id": "embedders.rest.searchFragments.justBreed.leftover"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
.await;
|
||||||
snapshot!(code, @"400 Bad Request");
|
snapshot!(code, @"400 Bad Request");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
@ -278,11 +214,7 @@ async fn fragment_retrieval() {
|
|||||||
let index = shared_index_for_fragments().await;
|
let index = shared_index_for_fragments().await;
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) = index
|
||||||
.render(json! {{
|
.render(json! {{ "template": { "id": "embedders.rest.indexingFragments.withBreed" }}})
|
||||||
"template": {
|
|
||||||
"id": "embedders.rest.indexingFragments.withBreed"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
.await;
|
||||||
snapshot!(code, @"200 OK");
|
snapshot!(code, @"200 OK");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
@ -293,11 +225,7 @@ async fn fragment_retrieval() {
|
|||||||
"#);
|
"#);
|
||||||
|
|
||||||
let (value, code) = index
|
let (value, code) = index
|
||||||
.render(json! {{
|
.render(json! {{ "template": { "id": "embedders.rest.searchFragments.justBreed" }}})
|
||||||
"template": {
|
|
||||||
"id": "embedders.rest.searchFragments.justBreed"
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
.await;
|
.await;
|
||||||
snapshot!(code, @"200 OK");
|
snapshot!(code, @"200 OK");
|
||||||
snapshot!(value, @r#"
|
snapshot!(value, @r#"
|
||||||
|
@ -63,10 +63,7 @@ impl Error {
|
|||||||
/// Produces an error message when the error happened at rendering time.
|
/// Produces an error message when the error happened at rendering time.
|
||||||
pub fn rendering_error(&self, root: &str) -> String {
|
pub fn rendering_error(&self, root: &str) -> String {
|
||||||
if self.path.is_empty() {
|
if self.path.is_empty() {
|
||||||
format!(
|
format!("error while rendering template: {}", &self.template_error)
|
||||||
"error while rendering template: {}",
|
|
||||||
&self.template_error
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
"in `{}`, error while rendering template: {}",
|
"in `{}`, error while rendering template: {}",
|
||||||
@ -79,10 +76,7 @@ impl Error {
|
|||||||
/// Produces an error message when the error happened at parsing time.
|
/// Produces an error message when the error happened at parsing time.
|
||||||
pub fn parsing_error(&self, root: &str) -> String {
|
pub fn parsing_error(&self, root: &str) -> String {
|
||||||
if self.path.is_empty() {
|
if self.path.is_empty() {
|
||||||
format!(
|
format!("error while parsing template: {}", &self.template_error)
|
||||||
"error while parsing template: {}",
|
|
||||||
&self.template_error
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
"in `{}`, error while parsing template: {}",
|
"in `{}`, error while parsing template: {}",
|
||||||
@ -153,10 +147,7 @@ impl JsonTemplate {
|
|||||||
/// If its a map, values inside can be accessed directly by their keys.
|
/// If its a map, values inside can be accessed directly by their keys.
|
||||||
pub fn render_serializable<T: Serialize>(&self, object: &T) -> Result<Value, Error> {
|
pub fn render_serializable<T: Serialize>(&self, object: &T) -> Result<Value, Error> {
|
||||||
let object = liquid::to_object(object)
|
let object = liquid::to_object(object)
|
||||||
.map_err(|err| Error {
|
.map_err(|err| Error { template_error: err, path: ValuePath::new() })?;
|
||||||
template_error: err,
|
|
||||||
path: ValuePath::new(),
|
|
||||||
})?;
|
|
||||||
self.render(&object)
|
self.render(&object)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -886,9 +886,7 @@ impl EmbedderOptions {
|
|||||||
| EmbedderOptions::OpenAi(_)
|
| EmbedderOptions::OpenAi(_)
|
||||||
| EmbedderOptions::Ollama(_)
|
| EmbedderOptions::Ollama(_)
|
||||||
| EmbedderOptions::UserProvided(_) => None,
|
| EmbedderOptions::UserProvided(_) => None,
|
||||||
EmbedderOptions::Rest(embedder_options) => {
|
EmbedderOptions::Rest(embedder_options) => embedder_options.search_fragments.get(name),
|
||||||
embedder_options.search_fragments.get(name)
|
|
||||||
}
|
|
||||||
EmbedderOptions::Composite(embedder_options) => {
|
EmbedderOptions::Composite(embedder_options) => {
|
||||||
if let SubEmbedderOptions::Rest(embedder_options) = &embedder_options.search {
|
if let SubEmbedderOptions::Rest(embedder_options) = &embedder_options.search {
|
||||||
embedder_options.search_fragments.get(name)
|
embedder_options.search_fragments.get(name)
|
||||||
|
Reference in New Issue
Block a user