From a3328ea2de1e675b1418b4e2ca0c23f88828c558 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Thu, 6 Nov 2025 13:53:48 +0100 Subject: [PATCH] api!(jsonrpc): `chat_type` now contains a variant of a string enum/union. Affected places: `FullChat.chat_type`, `BasicChat.chat_type`, `ChatListItemFetchResult::ChatListItem.chat_type`, `Event:: SecurejoinInviterProgress.chat_type` and `MessageSearchResult.chat_type` (#7285) Actually it will be not as breaking if you used the constants, because this pr also changes the constants. closes #7029 Note that I had to change the constants from enum to namespace, this has the side effect, that you can no longer also use the constants as types, you need to instead prefix them with `typeof ` now. --- deltachat-jsonrpc/src/api/types/chat.rs | 43 ++++++++++++++++--- deltachat-jsonrpc/src/api/types/chat_list.rs | 5 ++- deltachat-jsonrpc/src/api/types/events.rs | 7 +-- deltachat-jsonrpc/src/api/types/message.rs | 5 ++- .../typescript/scripts/generate-constants.js | 23 ++++++++-- .../src/deltachat_rpc_client/const.py | 14 +++--- 6 files changed, 73 insertions(+), 24 deletions(-) diff --git a/deltachat-jsonrpc/src/api/types/chat.rs b/deltachat-jsonrpc/src/api/types/chat.rs index 3e62e9c52..66403ef3a 100644 --- a/deltachat-jsonrpc/src/api/types/chat.rs +++ b/deltachat-jsonrpc/src/api/types/chat.rs @@ -6,7 +6,6 @@ use deltachat::chat::{Chat, ChatId}; use deltachat::constants::Chattype; use deltachat::contact::{Contact, ContactId}; use deltachat::context::Context; -use num_traits::cast::ToPrimitive; use serde::{Deserialize, Serialize}; use typescript_type_def::TypeDef; @@ -46,7 +45,7 @@ pub struct FullChat { archived: bool, pinned: bool, // subtitle - will be moved to frontend because it uses translation functions - chat_type: u32, + chat_type: JsonrpcChatType, is_unpromoted: bool, is_self_talk: bool, contacts: Vec, @@ -130,7 +129,7 @@ impl FullChat { profile_image, //BLOBS ? archived: chat.get_visibility() == chat::ChatVisibility::Archived, pinned: chat.get_visibility() == chat::ChatVisibility::Pinned, - chat_type: chat.get_type().to_u32().context("unknown chat type id")?, + chat_type: chat.get_type().into(), is_unpromoted: chat.is_unpromoted(), is_self_talk: chat.is_self_talk(), contacts, @@ -192,7 +191,7 @@ pub struct BasicChat { profile_image: Option, //BLOBS ? archived: bool, pinned: bool, - chat_type: u32, + chat_type: JsonrpcChatType, is_unpromoted: bool, is_self_talk: bool, color: String, @@ -220,7 +219,7 @@ impl BasicChat { profile_image, //BLOBS ? archived: chat.get_visibility() == chat::ChatVisibility::Archived, pinned: chat.get_visibility() == chat::ChatVisibility::Pinned, - chat_type: chat.get_type().to_u32().context("unknown chat type id")?, + chat_type: chat.get_type().into(), is_unpromoted: chat.is_unpromoted(), is_self_talk: chat.is_self_talk(), color, @@ -274,3 +273,37 @@ impl JsonrpcChatVisibility { } } } + +#[derive(Clone, Serialize, Deserialize, PartialEq, TypeDef, schemars::JsonSchema)] +#[serde(rename = "ChatType")] +pub enum JsonrpcChatType { + Single, + Group, + Mailinglist, + OutBroadcast, + InBroadcast, +} + +impl From for JsonrpcChatType { + fn from(chattype: Chattype) -> Self { + match chattype { + Chattype::Single => JsonrpcChatType::Single, + Chattype::Group => JsonrpcChatType::Group, + Chattype::Mailinglist => JsonrpcChatType::Mailinglist, + Chattype::OutBroadcast => JsonrpcChatType::OutBroadcast, + Chattype::InBroadcast => JsonrpcChatType::InBroadcast, + } + } +} + +impl From for Chattype { + fn from(chattype: JsonrpcChatType) -> Self { + match chattype { + JsonrpcChatType::Single => Chattype::Single, + JsonrpcChatType::Group => Chattype::Group, + JsonrpcChatType::Mailinglist => Chattype::Mailinglist, + JsonrpcChatType::OutBroadcast => Chattype::OutBroadcast, + JsonrpcChatType::InBroadcast => Chattype::InBroadcast, + } + } +} diff --git a/deltachat-jsonrpc/src/api/types/chat_list.rs b/deltachat-jsonrpc/src/api/types/chat_list.rs index 2157967ea..a07641b2b 100644 --- a/deltachat-jsonrpc/src/api/types/chat_list.rs +++ b/deltachat-jsonrpc/src/api/types/chat_list.rs @@ -11,6 +11,7 @@ use num_traits::cast::ToPrimitive; use serde::Serialize; use typescript_type_def::TypeDef; +use super::chat::JsonrpcChatType; use super::color_int_to_hex_string; use super::message::MessageViewtype; @@ -23,7 +24,7 @@ pub enum ChatListItemFetchResult { name: String, avatar_path: Option, color: String, - chat_type: u32, + chat_type: JsonrpcChatType, last_updated: Option, summary_text1: String, summary_text2: String, @@ -151,7 +152,7 @@ pub(crate) async fn get_chat_list_item_by_id( name: chat.get_name().to_owned(), avatar_path, color, - chat_type: chat.get_type().to_u32().context("unknown chat type id")?, + chat_type: chat.get_type().into(), last_updated, summary_text1, summary_text2, diff --git a/deltachat-jsonrpc/src/api/types/events.rs b/deltachat-jsonrpc/src/api/types/events.rs index d957f82e9..f7957e32d 100644 --- a/deltachat-jsonrpc/src/api/types/events.rs +++ b/deltachat-jsonrpc/src/api/types/events.rs @@ -1,8 +1,9 @@ use deltachat::{Event as CoreEvent, EventType as CoreEventType}; -use num_traits::ToPrimitive; use serde::Serialize; use typescript_type_def::TypeDef; +use super::chat::JsonrpcChatType; + #[derive(Serialize, TypeDef, schemars::JsonSchema)] #[serde(rename_all = "camelCase")] pub struct Event { @@ -307,7 +308,7 @@ pub enum EventType { /// The type of the joined chat. /// This can take the same values /// as `BasicChat.chatType` ([`crate::api::types::chat::BasicChat::chat_type`]). - chat_type: u32, + chat_type: JsonrpcChatType, /// ID of the chat in case of success. chat_id: u32, @@ -570,7 +571,7 @@ impl From for EventType { progress, } => SecurejoinInviterProgress { contact_id: contact_id.to_u32(), - chat_type: chat_type.to_u32().unwrap_or(0), + chat_type: chat_type.into(), chat_id: chat_id.to_u32(), progress, }, diff --git a/deltachat-jsonrpc/src/api/types/message.rs b/deltachat-jsonrpc/src/api/types/message.rs index dd5a2023f..567e3ffdc 100644 --- a/deltachat-jsonrpc/src/api/types/message.rs +++ b/deltachat-jsonrpc/src/api/types/message.rs @@ -16,6 +16,7 @@ use num_traits::cast::ToPrimitive; use serde::{Deserialize, Serialize}; use typescript_type_def::TypeDef; +use super::chat::JsonrpcChatType; use super::color_int_to_hex_string; use super::contact::ContactObject; use super::reactions::JsonrpcReactions; @@ -531,7 +532,7 @@ pub struct MessageSearchResult { chat_profile_image: Option, chat_color: String, chat_name: String, - chat_type: u32, + chat_type: JsonrpcChatType, is_chat_contact_request: bool, is_chat_archived: bool, message: String, @@ -569,7 +570,7 @@ impl MessageSearchResult { chat_id: chat.id.to_u32(), chat_name: chat.get_name().to_owned(), chat_color, - chat_type: chat.get_type().to_u32().context("unknown chat type id")?, + chat_type: chat.get_type().into(), chat_profile_image, is_chat_contact_request: chat.is_contact_request(), is_chat_archived: chat.get_visibility() == ChatVisibility::Archived, diff --git a/deltachat-jsonrpc/typescript/scripts/generate-constants.js b/deltachat-jsonrpc/typescript/scripts/generate-constants.js index 3bc83f969..e8b09d2e1 100755 --- a/deltachat-jsonrpc/typescript/scripts/generate-constants.js +++ b/deltachat-jsonrpc/typescript/scripts/generate-constants.js @@ -45,15 +45,30 @@ const constants = data key.startsWith("DC_SOCKET_") || key.startsWith("DC_LP_AUTH_") || key.startsWith("DC_PUSH_") || - key.startsWith("DC_TEXT1_") + key.startsWith("DC_TEXT1_") || + key.startsWith("DC_CHAT_TYPE") ); }) .map((row) => { - return ` ${row.key}: ${row.value}`; + return ` export const ${row.key} = ${row.value};`; }) - .join(",\n"); + .join("\n"); writeFileSync( resolve(__dirname, "../generated/constants.ts"), - `// Generated!\n\nexport enum C {\n${constants.replace(/:/g, " =")},\n}\n`, + `// Generated! + +export namespace C { +${constants} + /** @deprecated 10-8-2025 compare string directly with \`== "Group"\` */ + export const DC_CHAT_TYPE_GROUP = "Group"; + /** @deprecated 10-8-2025 compare string directly with \`== "InBroadcast"\`*/ + export const DC_CHAT_TYPE_IN_BROADCAST = "InBroadcast"; + /** @deprecated 10-8-2025 compare string directly with \`== "Mailinglist"\` */ + export const DC_CHAT_TYPE_MAILINGLIST = "Mailinglist"; + /** @deprecated 10-8-2025 compare string directly with \`== "OutBroadcast"\` */ + export const DC_CHAT_TYPE_OUT_BROADCAST = "OutBroadcast"; + /** @deprecated 10-8-2025 compare string directly with \`== "Single"\` */ + export const DC_CHAT_TYPE_SINGLE = "Single"; +}\n`, ); diff --git a/deltachat-rpc-client/src/deltachat_rpc_client/const.py b/deltachat-rpc-client/src/deltachat_rpc_client/const.py index c985bdfe1..03ae2d7b3 100644 --- a/deltachat-rpc-client/src/deltachat_rpc_client/const.py +++ b/deltachat-rpc-client/src/deltachat_rpc_client/const.py @@ -91,19 +91,17 @@ class ChatId(IntEnum): LAST_SPECIAL = 9 -class ChatType(IntEnum): +class ChatType(str, Enum): """Chat type.""" - UNDEFINED = 0 - - SINGLE = 100 + SINGLE = "Single" """1:1 chat, i.e. a direct chat with a single contact""" - GROUP = 120 + GROUP = "Group" - MAILINGLIST = 140 + MAILINGLIST = "Mailinglist" - OUT_BROADCAST = 160 + OUT_BROADCAST = "OutBroadcast" """Outgoing broadcast channel, called "Channel" in the UI. The user can send into this channel, @@ -115,7 +113,7 @@ class ChatType(IntEnum): which would make it hard to grep for it. """ - IN_BROADCAST = 165 + IN_BROADCAST = "InBroadcast" """Incoming broadcast channel, called "Channel" in the UI. This channel is read-only,