mirror of
https://github.com/rustmailer/bichon.git
synced 2026-08-03 07:48:34 +02:00
feat: Ability to add/remove tags from any list of messages #189
This commit is contained in:
+24
-12
@@ -40,7 +40,7 @@ use crate::{
|
||||
attachment::AttachmentMetadata,
|
||||
content::{AttachmentDetail, AttachmentInfo},
|
||||
search::{SearchFilter, SortBy},
|
||||
tags::TagCount,
|
||||
tags::{TagAction, TagCount, TagsRequest},
|
||||
},
|
||||
rest::response::DataPage,
|
||||
settings::{cli::SETTINGS, dir::DATA_DIR_MANAGER},
|
||||
@@ -611,20 +611,24 @@ impl DuckDBManager {
|
||||
Ok(contacts)
|
||||
}
|
||||
|
||||
pub fn update_envelope_tags(
|
||||
&self,
|
||||
updates: HashMap<u64, Vec<String>>,
|
||||
tags: Vec<String>,
|
||||
) -> BichonResult<()> {
|
||||
pub fn update_envelope_tags(&self, request: TagsRequest) -> BichonResult<()> {
|
||||
let mut conn = self.conn()?;
|
||||
let tags_json = serde_json::to_string(&tags)
|
||||
let tags_json = serde_json::to_string(&request.tags)
|
||||
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
|
||||
|
||||
let set_clause = match &request.action {
|
||||
TagAction::Overwrite => "SET tags = ?::JSON::VARCHAR[]",
|
||||
TagAction::Add => "SET tags = list_distinct(list_concat(tags, ?::JSON::VARCHAR[]))",
|
||||
TagAction::Remove => {
|
||||
"SET tags = list_filter(tags, x -> NOT list_contains(?::JSON::VARCHAR[], x))"
|
||||
}
|
||||
};
|
||||
|
||||
let tx = conn
|
||||
.transaction()
|
||||
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
|
||||
|
||||
for (account_id, ids) in updates {
|
||||
for (account_id, ids) in request.updates {
|
||||
if ids.is_empty() {
|
||||
continue;
|
||||
}
|
||||
@@ -633,23 +637,31 @@ impl DuckDBManager {
|
||||
let placeholders = vec!["?"; chunk.len()].join(", ");
|
||||
let query = format!(
|
||||
"UPDATE envelopes
|
||||
SET tags = CAST(json(?) AS VARCHAR[])
|
||||
{}
|
||||
WHERE account_id = ?
|
||||
AND id IN ({})",
|
||||
placeholders
|
||||
set_clause, placeholders
|
||||
);
|
||||
|
||||
let mut params: Vec<Box<dyn duckdb::ToSql>> = Vec::new();
|
||||
let mut params: Vec<Box<dyn duckdb::ToSql>> = Vec::with_capacity(chunk.len() + 2);
|
||||
|
||||
params.push(Box::new(tags_json.clone()));
|
||||
params.push(Box::new(account_id));
|
||||
|
||||
for id in chunk {
|
||||
params.push(Box::new(id.clone()));
|
||||
}
|
||||
|
||||
let param_refs: Vec<&dyn duckdb::ToSql> =
|
||||
params.iter().map(|p| p.as_ref()).collect();
|
||||
|
||||
tx.execute(&query, duckdb::params_from_iter(param_refs))
|
||||
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
|
||||
.map_err(|e| {
|
||||
raise_error!(
|
||||
format!("Update failed. Account: {}, Error: {}", account_id, e),
|
||||
ErrorCode::InternalError
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::modules::{
|
||||
attachment::AttachmentMetadata,
|
||||
content::{AttachmentDetail, AttachmentInfo},
|
||||
search::SortBy,
|
||||
tags::TagCount,
|
||||
tags::{TagCount, TagsRequest},
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
@@ -204,16 +204,12 @@ impl EnvelopeIndexManager {
|
||||
.map_err(|e| raise_error!(format!("{:?}", e), ErrorCode::InternalError))?
|
||||
}
|
||||
|
||||
pub async fn update_envelope_tags(
|
||||
&self,
|
||||
updates: HashMap<u64, Vec<String>>, // HashMap<account_id, envelope_ids>
|
||||
tags: Vec<String>,
|
||||
) -> BichonResult<()> {
|
||||
if updates.is_empty() {
|
||||
tracing::warn!("update_envelope_tags: updates is empty, nothing to update");
|
||||
pub async fn update_envelope_tags(&self, request: TagsRequest) -> BichonResult<()> {
|
||||
if request.updates.is_empty() {
|
||||
tracing::warn!("update_envelope_tags: request is empty, nothing to update");
|
||||
return Ok(());
|
||||
}
|
||||
tokio::task::spawn_blocking(move || duckdb()?.update_envelope_tags(updates, tags))
|
||||
tokio::task::spawn_blocking(move || duckdb()?.update_envelope_tags(request))
|
||||
.await
|
||||
.map_err(|e| raise_error!(format!("{:?}", e), ErrorCode::InternalError))?
|
||||
}
|
||||
|
||||
@@ -16,16 +16,16 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use poem_openapi::Object;
|
||||
use poem_openapi::{Enum, Object};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
pub struct UpdateTagsRequest {
|
||||
pub struct TagsRequest {
|
||||
pub updates: HashMap<u64, Vec<String>>, // account_id -> envelope_ids
|
||||
pub tags: Vec<String>,
|
||||
pub action: TagAction,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, Object)]
|
||||
@@ -33,3 +33,11 @@ pub struct TagCount {
|
||||
pub tag: String,
|
||||
pub count: u64,
|
||||
}
|
||||
|
||||
#[derive(Enum, Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TagAction {
|
||||
Add,
|
||||
Remove,
|
||||
#[default]
|
||||
Overwrite,
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ use crate::modules::message::delete::delete_messages_impl;
|
||||
use crate::modules::message::list::{get_thread_messages, list_messages_impl};
|
||||
use crate::modules::message::search::{search_messages_impl, SearchRequest};
|
||||
use crate::modules::message::tags::TagCount;
|
||||
use crate::modules::message::tags::UpdateTagsRequest;
|
||||
use crate::modules::message::tags::TagsRequest;
|
||||
use crate::modules::rest::api::ApiTags;
|
||||
use crate::modules::rest::response::DataPage;
|
||||
use crate::modules::rest::ApiResult;
|
||||
@@ -376,7 +376,7 @@ impl MessageApi {
|
||||
)]
|
||||
async fn update_envelope_tags(
|
||||
&self,
|
||||
req: Json<UpdateTagsRequest>,
|
||||
req: Json<TagsRequest>,
|
||||
context: ClientContext,
|
||||
) -> ApiResult<()> {
|
||||
let req = req.0;
|
||||
@@ -392,7 +392,7 @@ impl MessageApi {
|
||||
}
|
||||
|
||||
ENVELOPE_INDEX_MANAGER
|
||||
.update_envelope_tags(req.updates, req.tags)
|
||||
.update_envelope_tags(req)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user