Fix JMAP: SearchSnippet/get response structure
This commit is contained in:
@@ -20,6 +20,7 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If
|
|||||||
- Unchanged immutable `id` property is rejected on `/set`.
|
- Unchanged immutable `id` property is rejected on `/set`.
|
||||||
- `filter: null` rejected as `notRequest` on `/query` and `/queryChanges`.
|
- `filter: null` rejected as `notRequest` on `/query` and `/queryChanges`.
|
||||||
- `Email/query` total miscount when `collapseThreads` is enabled.
|
- `Email/query` total miscount when `collapseThreads` is enabled.
|
||||||
|
- `SearchSnippet/get` response structure.
|
||||||
- OIDC: Add default domain name to groups that are not email addresses.
|
- OIDC: Add default domain name to groups that are not email addresses.
|
||||||
- RocksDB: Enable blob garbage collection to reclaim disk space from deleted blobs.
|
- RocksDB: Enable blob garbage collection to reclaim disk space from deleted blobs.
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,7 @@ pub struct GetSearchSnippetResponse {
|
|||||||
pub list: Vec<SearchSnippet>,
|
pub list: Vec<SearchSnippet>,
|
||||||
|
|
||||||
#[serde(rename = "notFound")]
|
#[serde(rename = "notFound")]
|
||||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
pub not_found: Option<Vec<MaybeInvalid<Id>>>,
|
||||||
pub not_found: Vec<Id>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize, Clone, Debug)]
|
#[derive(serde::Serialize, Clone, Debug)]
|
||||||
@@ -42,10 +41,8 @@ pub struct SearchSnippet {
|
|||||||
#[serde(rename = "emailId")]
|
#[serde(rename = "emailId")]
|
||||||
pub email_id: Id,
|
pub email_id: Id,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub subject: Option<String>,
|
pub subject: Option<String>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub preview: Option<String>,
|
pub preview: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,6 +189,18 @@ impl<'de, V: FromStr> serde::Deserialize<'de> for MaybeInvalid<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<V: FromStr + serde::Serialize> serde::Serialize for MaybeInvalid<V> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
MaybeInvalid::Value(v) => v.serialize(serializer),
|
||||||
|
MaybeInvalid::Invalid(s) => serializer.serialize_str(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<V: FromStr> Default for MaybeInvalid<V> {
|
impl<V: FromStr> Default for MaybeInvalid<V> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
MaybeInvalid::Invalid("".to_string())
|
MaybeInvalid::Invalid("".to_string())
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use jmap_proto::{
|
|||||||
search_snippet::{GetSearchSnippetRequest, GetSearchSnippetResponse, SearchSnippet},
|
search_snippet::{GetSearchSnippetRequest, GetSearchSnippetResponse, SearchSnippet},
|
||||||
},
|
},
|
||||||
object::email::EmailFilter,
|
object::email::EmailFilter,
|
||||||
request::IntoValid,
|
request::MaybeInvalid,
|
||||||
};
|
};
|
||||||
use mail_parser::decoders::html::html_to_text;
|
use mail_parser::decoders::html::html_to_text;
|
||||||
use nlp::language::{Language, search_snippet::generate_snippet, stemmer::Stemmer};
|
use nlp::language::{Language, search_snippet::generate_snippet, stemmer::Stemmer};
|
||||||
@@ -108,14 +108,22 @@ impl EmailSearchSnippet for Server {
|
|||||||
let mut response = GetSearchSnippetResponse {
|
let mut response = GetSearchSnippetResponse {
|
||||||
account_id: request.account_id,
|
account_id: request.account_id,
|
||||||
list: Vec::with_capacity(email_ids.len()),
|
list: Vec::with_capacity(email_ids.len()),
|
||||||
not_found: vec![],
|
not_found: None,
|
||||||
};
|
};
|
||||||
|
let mut not_found = Vec::new();
|
||||||
|
|
||||||
if email_ids.len() > self.core.jmap.snippet_max_results {
|
if email_ids.len() > self.core.jmap.snippet_max_results {
|
||||||
return Err(trc::JmapEvent::RequestTooLarge.into_err());
|
return Err(trc::JmapEvent::RequestTooLarge.into_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
for email_id in email_ids.into_valid() {
|
for email_id in email_ids {
|
||||||
|
let email_id = match email_id {
|
||||||
|
MaybeInvalid::Value(email_id) => email_id,
|
||||||
|
invalid => {
|
||||||
|
not_found.push(invalid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
let document_id = email_id.document_id();
|
let document_id = email_id.document_id();
|
||||||
let mut snippet = SearchSnippet {
|
let mut snippet = SearchSnippet {
|
||||||
email_id,
|
email_id,
|
||||||
@@ -123,7 +131,7 @@ impl EmailSearchSnippet for Server {
|
|||||||
preview: None,
|
preview: None,
|
||||||
};
|
};
|
||||||
if !document_ids.contains(document_id) {
|
if !document_ids.contains(document_id) {
|
||||||
response.not_found.push(email_id);
|
not_found.push(MaybeInvalid::Value(email_id));
|
||||||
continue;
|
continue;
|
||||||
} else if terms.is_empty() {
|
} else if terms.is_empty() {
|
||||||
response.list.push(snippet);
|
response.list.push(snippet);
|
||||||
@@ -141,7 +149,7 @@ impl EmailSearchSnippet for Server {
|
|||||||
{
|
{
|
||||||
Some(metadata) => metadata,
|
Some(metadata) => metadata,
|
||||||
None => {
|
None => {
|
||||||
response.not_found.push(email_id);
|
not_found.push(MaybeInvalid::Value(email_id));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -178,7 +186,7 @@ impl EmailSearchSnippet for Server {
|
|||||||
CausedBy = trc::location!(),
|
CausedBy = trc::location!(),
|
||||||
);
|
);
|
||||||
|
|
||||||
response.not_found.push(email_id);
|
not_found.push(MaybeInvalid::Value(email_id));
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let raw_message = ChainedBytes::new(metadata.raw_headers.as_ref()).with_last(
|
let raw_message = ChainedBytes::new(metadata.raw_headers.as_ref()).with_last(
|
||||||
@@ -246,6 +254,10 @@ impl EmailSearchSnippet for Server {
|
|||||||
response.list.push(snippet);
|
response.list.push(snippet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !not_found.is_empty() {
|
||||||
|
response.not_found = Some(not_found);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user