Fix JMAP: VacationResponse singleton handling
This commit is contained in:
@@ -21,6 +21,7 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If
|
|||||||
- `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.
|
- `SearchSnippet/get` response structure.
|
||||||
|
- `VacationResponse` singleton handling.
|
||||||
- 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.
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
use super::get::VacationResponseGet;
|
use super::get::VacationResponseGet;
|
||||||
use crate::changes::state::StateManager;
|
use crate::changes::state::StateManager;
|
||||||
use common::{Server, auth::AccessToken, storage::index::ObjectIndexBuilder};
|
use common::{Server, auth::AccessToken, storage::index::ObjectIndexBuilder};
|
||||||
use email::sieve::{
|
use email::sieve::{SieveScript, VacationResponse, ingest::SieveScriptIngest};
|
||||||
SieveScript, VacationResponse, delete::SieveScriptDelete, ingest::SieveScriptIngest,
|
|
||||||
};
|
|
||||||
use jmap_proto::{
|
use jmap_proto::{
|
||||||
error::set::{SetError, SetErrorType},
|
error::set::{SetError, SetErrorType},
|
||||||
method::set::{SetRequest, SetResponse},
|
method::set::{SetRequest, SetResponse},
|
||||||
@@ -60,10 +58,13 @@ impl VacationResponseSet for Server {
|
|||||||
)
|
)
|
||||||
.await?,
|
.await?,
|
||||||
);
|
);
|
||||||
let will_destroy = request.unwrap_destroy().into_valid().collect::<Vec<_>>();
|
|
||||||
|
for id in request.unwrap_destroy().into_valid() {
|
||||||
|
response.not_destroyed.append(id, SetError::singleton());
|
||||||
|
}
|
||||||
|
|
||||||
// Process set or update requests
|
// Process set or update requests
|
||||||
let mut create_id = None;
|
let create_id = None;
|
||||||
let mut changes = None;
|
let mut changes = None;
|
||||||
match (request.create, request.update) {
|
match (request.create, request.update) {
|
||||||
(Some(create), Some(update)) if !create.is_empty() && !update.is_empty() => {
|
(Some(create), Some(update)) if !create.is_empty() && !update.is_empty() => {
|
||||||
@@ -72,37 +73,14 @@ impl VacationResponseSet for Server {
|
|||||||
.details("Creating and updating on the same request is not allowed."));
|
.details("Creating and updating on the same request is not allowed."));
|
||||||
}
|
}
|
||||||
(Some(create), _) if !create.is_empty() => {
|
(Some(create), _) if !create.is_empty() => {
|
||||||
for (id, obj) in create {
|
for (id, _obj) in create {
|
||||||
if will_destroy.contains(&Id::singleton()) {
|
response.not_created.append(id, SetError::singleton());
|
||||||
response.not_created.append(
|
|
||||||
id,
|
|
||||||
SetError::new(SetErrorType::WillDestroy)
|
|
||||||
.with_description("ID will be destroyed."),
|
|
||||||
);
|
|
||||||
} else if create_id.is_some() {
|
|
||||||
response.not_created.append(
|
|
||||||
id,
|
|
||||||
SetError::forbidden()
|
|
||||||
.with_description("Only one object can be created."),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
create_id = Some(id);
|
|
||||||
changes = Some(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(_, Some(update)) if !update.is_empty() => {
|
(_, Some(update)) if !update.is_empty() => {
|
||||||
for (id, obj) in update.into_valid() {
|
for (id, obj) in update.into_valid() {
|
||||||
if id.is_singleton() {
|
if id.is_singleton() {
|
||||||
if !will_destroy.contains(&id) {
|
changes = Some(obj);
|
||||||
changes = Some(obj);
|
|
||||||
} else {
|
|
||||||
response.not_updated.append(
|
|
||||||
id,
|
|
||||||
SetError::new(SetErrorType::WillDestroy)
|
|
||||||
.with_description("ID will be destroyed."),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
response.not_updated.append(
|
response.not_updated.append(
|
||||||
id,
|
id,
|
||||||
@@ -112,9 +90,7 @@ impl VacationResponseSet for Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if will_destroy.is_empty() {
|
return Ok(response);
|
||||||
return Ok(response);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,37 +316,6 @@ impl VacationResponseSet for Server {
|
|||||||
} else {
|
} else {
|
||||||
response.updated.append(Id::singleton(), None);
|
response.updated.append(Id::singleton(), None);
|
||||||
}
|
}
|
||||||
} else if !will_destroy.is_empty() {
|
|
||||||
for id in will_destroy {
|
|
||||||
if id.is_singleton()
|
|
||||||
&& let Some(document_id) = self.get_vacation_sieve_script_id(account_id).await?
|
|
||||||
{
|
|
||||||
self.sieve_script_delete(account_id, document_id, access_token, &mut batch)
|
|
||||||
.await?;
|
|
||||||
if active_script_id == Some(document_id) {
|
|
||||||
batch
|
|
||||||
.with_collection(Collection::Principal)
|
|
||||||
.with_document(0)
|
|
||||||
.clear(PrincipalField::ActiveScriptId);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.destroyed.push(id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
response.not_destroyed.append(id, SetError::not_found());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write changes
|
|
||||||
if !batch.is_empty() {
|
|
||||||
response.new_state = Some(
|
|
||||||
self.commit_batch(batch)
|
|
||||||
.await
|
|
||||||
.and_then(|ids| ids.last_change_id(account_id))
|
|
||||||
.caused_by(trc::location!())?
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
|
|||||||
Reference in New Issue
Block a user