mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 05:22:14 +03:00
globally search for media (#3528)
* get_chat_media() from any chat similar to search_msgs() * do not return hidden media this fixes the issue that drafts and other hidden messages pop up in the gallery. * add a test for get_chat_media() * use None instead of ChatId::new(0) * clarify scope of 'any' in get_chat_media() * adapt json rpc to changed get_chat_media() * jsonrpc: chat_get_media turn chat_id into option and also still allow `0` for dev convenience (though I'm not totally sure if thats the right decision) * cargo fmt Co-authored-by: Simon Laux <mobile.info@simonlaux.de>
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
### Changes
|
||||
- refactorings #3545 #3551
|
||||
- use [pathlib](https://docs.python.org/3/library/pathlib.html) in provider update script #3543
|
||||
- `dc_get_chat_media()` can return media globally #3528
|
||||
|
||||
### Fixes
|
||||
- improved error handling for account setup from qrcode #3474
|
||||
|
||||
@@ -1263,7 +1263,7 @@ void dc_marknoticed_chat (dc_context_t* context, uint32_t ch
|
||||
|
||||
|
||||
/**
|
||||
* Returns all message IDs of the given types in a chat.
|
||||
* Returns all message IDs of the given types in a given chat or any chat.
|
||||
* Typically used to show a gallery.
|
||||
* The result must be dc_array_unref()'d
|
||||
*
|
||||
@@ -1273,7 +1273,8 @@ void dc_marknoticed_chat (dc_context_t* context, uint32_t ch
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object as returned from dc_context_new().
|
||||
* @param chat_id The chat ID to get all messages with media from.
|
||||
* @param chat_id >0: get messages with media from this chat ID.
|
||||
* 0: get messages with media from any chat of the currently used account.
|
||||
* @param msg_type Specify a message type to query here, one of the @ref DC_MSG constants.
|
||||
* @param msg_type2 Alternative message type to search for. 0 to skip.
|
||||
* @param msg_type3 Alternative message type to search for. 0 to skip.
|
||||
@@ -1284,7 +1285,6 @@ dc_array_t* dc_get_chat_media (dc_context_t* context, uint32_t ch
|
||||
|
||||
/**
|
||||
* Search next/previous message based on a given message and a list of types.
|
||||
* The
|
||||
* Typically used to implement the "next" and "previous" buttons
|
||||
* in a gallery or in a media player.
|
||||
*
|
||||
|
||||
@@ -1208,6 +1208,11 @@ pub unsafe extern "C" fn dc_get_chat_media(
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let ctx = &*context;
|
||||
let chat_id = if chat_id == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(ChatId::new(chat_id))
|
||||
};
|
||||
let msg_type = from_prim(msg_type).expect(&format!("invalid msg_type = {}", msg_type));
|
||||
let or_msg_type2 =
|
||||
from_prim(or_msg_type2).expect(&format!("incorrect or_msg_type2 = {}", or_msg_type2));
|
||||
@@ -1216,16 +1221,10 @@ pub unsafe extern "C" fn dc_get_chat_media(
|
||||
|
||||
block_on(async move {
|
||||
Box::into_raw(Box::new(
|
||||
chat::get_chat_media(
|
||||
ctx,
|
||||
ChatId::new(chat_id),
|
||||
msg_type,
|
||||
or_msg_type2,
|
||||
or_msg_type3,
|
||||
)
|
||||
.await
|
||||
.unwrap_or_log_default(ctx, "Failed get_chat_media")
|
||||
.into(),
|
||||
chat::get_chat_media(ctx, chat_id, msg_type, or_msg_type2, or_msg_type3)
|
||||
.await
|
||||
.unwrap_or_log_default(ctx, "Failed get_chat_media")
|
||||
.into(),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -577,28 +577,28 @@ impl CommandApi {
|
||||
/// The list is already sorted and starts with the oldest message.
|
||||
/// Clients should not try to re-sort the list as this would be an expensive action
|
||||
/// and would result in inconsistencies between clients.
|
||||
///
|
||||
/// Setting `chat_id` to `None` (`null` in typescript) means get messages with media
|
||||
/// from any chat of the currently used account.
|
||||
async fn chat_get_media(
|
||||
&self,
|
||||
account_id: u32,
|
||||
chat_id: u32,
|
||||
chat_id: Option<u32>,
|
||||
message_type: MessageViewtype,
|
||||
or_message_type2: Option<MessageViewtype>,
|
||||
or_message_type3: Option<MessageViewtype>,
|
||||
) -> Result<Vec<u32>> {
|
||||
let ctx = self.get_context(account_id).await?;
|
||||
|
||||
let chat_id = match chat_id {
|
||||
None | Some(0) => None,
|
||||
Some(id) => Some(ChatId::new(id)),
|
||||
};
|
||||
let msg_type = message_type.into();
|
||||
let or_msg_type2 = or_message_type2.map_or(Viewtype::Unknown, |v| v.into());
|
||||
let or_msg_type3 = or_message_type3.map_or(Viewtype::Unknown, |v| v.into());
|
||||
|
||||
let media = get_chat_media(
|
||||
&ctx,
|
||||
ChatId::new(chat_id),
|
||||
msg_type,
|
||||
or_msg_type2,
|
||||
or_msg_type3,
|
||||
)
|
||||
.await?;
|
||||
let media = get_chat_media(&ctx, chat_id, msg_type, or_msg_type2, or_msg_type3).await?;
|
||||
Ok(media.iter().map(|msg_id| msg_id.to_u32()).collect())
|
||||
}
|
||||
|
||||
|
||||
@@ -299,8 +299,11 @@ export class RawClient {
|
||||
* The list is already sorted and starts with the oldest message.
|
||||
* Clients should not try to re-sort the list as this would be an expensive action
|
||||
* and would result in inconsistencies between clients.
|
||||
*
|
||||
* Setting `chat_id` to `None` (`null` in typescript) means get messages with media
|
||||
* from any chat of the currently used account.
|
||||
*/
|
||||
public chatGetMedia(accountId: T.U32, chatId: T.U32, messageType: T.Viewtype, orMessageType2: (T.Viewtype|null), orMessageType3: (T.Viewtype|null)): Promise<(T.U32)[]> {
|
||||
public chatGetMedia(accountId: T.U32, chatId: (T.U32|null), messageType: T.Viewtype, orMessageType2: (T.Viewtype|null), orMessageType3: (T.Viewtype|null)): Promise<(T.U32)[]> {
|
||||
return (this._transport.request('chat_get_media', [accountId, chatId, messageType, orMessageType2, orMessageType3] as RPC.Params)) as Promise<(T.U32)[]>;
|
||||
}
|
||||
|
||||
|
||||
@@ -95,4 +95,4 @@ export type WebxdcMessageInfo={
|
||||
* Implementations may offer an menu or a button to open this URL.
|
||||
*/
|
||||
"sourceCodeUrl":(string|null);};
|
||||
export type __AllTyps=[string,boolean,Record<string,string>,U32,U32,null,(U32)[],U32,null,(U32|null),(Account)[],U32,Account,U32,string,(ProviderInfo|null),U32,boolean,U32,Record<string,string>,U32,string,(string|null),null,U32,Record<string,(string|null)>,null,U32,string,null,U32,string,Qr,U32,string,(string|null),U32,(string)[],Record<string,(string|null)>,U32,null,U32,null,U32,(U32)[],U32,U32,Usize,U32,string,U32,U32,string,null,U32,(U32|null),(string|null),(U32|null),(ChatListEntry)[],U32,(ChatListEntry)[],Record<U32,ChatListItemFetchResult>,U32,U32,FullChat,U32,U32,null,U32,U32,null,U32,string,string,U32,U32,U32,U32,(U32)[],U32,U32,Message,U32,(U32)[],Record<U32,Message>,U32,U32,Contact,U32,string,(string|null),U32,U32,U32,U32,U32,U32,null,U32,U32,null,U32,(Contact)[],U32,U32,(string|null),(U32)[],U32,U32,(string|null),(Contact)[],U32,(U32)[],Record<U32,Contact>,U32,U32,Viewtype,(Viewtype|null),(Viewtype|null),(U32)[],U32,U32,string,string,null,U32,U32,U32,string,U32,U32,WebxdcMessageInfo,U32,string,U32,U32];
|
||||
export type __AllTyps=[string,boolean,Record<string,string>,U32,U32,null,(U32)[],U32,null,(U32|null),(Account)[],U32,Account,U32,string,(ProviderInfo|null),U32,boolean,U32,Record<string,string>,U32,string,(string|null),null,U32,Record<string,(string|null)>,null,U32,string,null,U32,string,Qr,U32,string,(string|null),U32,(string)[],Record<string,(string|null)>,U32,null,U32,null,U32,(U32)[],U32,U32,Usize,U32,string,U32,U32,string,null,U32,(U32|null),(string|null),(U32|null),(ChatListEntry)[],U32,(ChatListEntry)[],Record<U32,ChatListItemFetchResult>,U32,U32,FullChat,U32,U32,null,U32,U32,null,U32,string,string,U32,U32,U32,U32,(U32)[],U32,U32,Message,U32,(U32)[],Record<U32,Message>,U32,U32,Contact,U32,string,(string|null),U32,U32,U32,U32,U32,U32,null,U32,U32,null,U32,(Contact)[],U32,U32,(string|null),(U32)[],U32,U32,(string|null),(Contact)[],U32,(U32)[],Record<U32,Contact>,U32,(U32|null),Viewtype,(Viewtype|null),(Viewtype|null),(U32)[],U32,U32,string,string,null,U32,U32,U32,string,U32,U32,WebxdcMessageInfo,U32,string,U32,U32];
|
||||
|
||||
@@ -983,11 +983,9 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
||||
chat::add_device_msg(&context, None, Some(&mut msg)).await?;
|
||||
}
|
||||
"listmedia" => {
|
||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||
|
||||
let images = chat::get_chat_media(
|
||||
&context,
|
||||
sel_chat.as_ref().unwrap().get_id(),
|
||||
sel_chat.map(|c| c.id),
|
||||
Viewtype::Image,
|
||||
Viewtype::Gif,
|
||||
Viewtype::Video,
|
||||
|
||||
164
src/chat.rs
164
src/chat.rs
@@ -2423,7 +2423,7 @@ pub(crate) async fn mark_old_messages_as_noticed(
|
||||
|
||||
pub async fn get_chat_media(
|
||||
context: &Context,
|
||||
chat_id: ChatId,
|
||||
chat_id: Option<ChatId>,
|
||||
msg_type: Viewtype,
|
||||
msg_type2: Viewtype,
|
||||
msg_type3: Viewtype,
|
||||
@@ -2434,11 +2434,13 @@ pub async fn get_chat_media(
|
||||
.query_map(
|
||||
"SELECT id
|
||||
FROM msgs
|
||||
WHERE chat_id=?
|
||||
WHERE (1=? OR chat_id=?)
|
||||
AND (type=? OR type=? OR type=?)
|
||||
AND hidden=0
|
||||
ORDER BY timestamp, id;",
|
||||
paramsv![
|
||||
chat_id,
|
||||
if chat_id.is_none() { 1i32 } else { 0i32 },
|
||||
chat_id.unwrap_or_else(|| ChatId::new(0)),
|
||||
msg_type,
|
||||
if msg_type2 != Viewtype::Unknown {
|
||||
msg_type2
|
||||
@@ -2479,7 +2481,7 @@ pub async fn get_next_media(
|
||||
if let Ok(msg) = Message::load_from_db(context, curr_msg_id).await {
|
||||
let list: Vec<MsgId> = get_chat_media(
|
||||
context,
|
||||
msg.chat_id,
|
||||
Some(msg.chat_id),
|
||||
if msg_type != Viewtype::Unknown {
|
||||
msg_type
|
||||
} else {
|
||||
@@ -5486,4 +5488,158 @@ mod tests {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_get_chat_media() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
let chat_id1 = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
|
||||
let chat_id2 = create_group_chat(&t, ProtectionStatus::Unprotected, "bar").await?;
|
||||
|
||||
assert_eq!(
|
||||
get_chat_media(
|
||||
&t,
|
||||
Some(chat_id1),
|
||||
Viewtype::Image,
|
||||
Viewtype::Sticker,
|
||||
Viewtype::Unknown
|
||||
)
|
||||
.await?
|
||||
.len(),
|
||||
0
|
||||
);
|
||||
|
||||
async fn send_media(
|
||||
t: &TestContext,
|
||||
chat_id: ChatId,
|
||||
msg_type: Viewtype,
|
||||
name: &str,
|
||||
bytes: &[u8],
|
||||
) -> Result<MsgId> {
|
||||
let file = t.get_blobdir().join(name);
|
||||
tokio::fs::write(&file, bytes).await?;
|
||||
let mut msg = Message::new(msg_type);
|
||||
msg.set_file(file.to_str().unwrap(), None);
|
||||
send_msg(t, chat_id, &mut msg).await
|
||||
}
|
||||
|
||||
send_media(
|
||||
&t,
|
||||
chat_id1,
|
||||
Viewtype::Image,
|
||||
"a.jpg",
|
||||
include_bytes!("../test-data/image/rectangle200x180-rotated.jpg"),
|
||||
)
|
||||
.await?;
|
||||
send_media(
|
||||
&t,
|
||||
chat_id1,
|
||||
Viewtype::Sticker,
|
||||
"b.png",
|
||||
include_bytes!("../test-data/image/avatar64x64.png"),
|
||||
)
|
||||
.await?;
|
||||
send_media(
|
||||
&t,
|
||||
chat_id2,
|
||||
Viewtype::Image,
|
||||
"c.jpg",
|
||||
include_bytes!("../test-data/image/avatar64x64.png"),
|
||||
)
|
||||
.await?;
|
||||
send_media(
|
||||
&t,
|
||||
chat_id2,
|
||||
Viewtype::Webxdc,
|
||||
"d.xdc",
|
||||
include_bytes!("../test-data/webxdc/minimal.xdc"),
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_eq!(
|
||||
get_chat_media(
|
||||
&t,
|
||||
Some(chat_id1),
|
||||
Viewtype::Image,
|
||||
Viewtype::Unknown,
|
||||
Viewtype::Unknown,
|
||||
)
|
||||
.await?
|
||||
.len(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
get_chat_media(
|
||||
&t,
|
||||
Some(chat_id1),
|
||||
Viewtype::Sticker,
|
||||
Viewtype::Unknown,
|
||||
Viewtype::Unknown,
|
||||
)
|
||||
.await?
|
||||
.len(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
get_chat_media(
|
||||
&t,
|
||||
Some(chat_id1),
|
||||
Viewtype::Sticker,
|
||||
Viewtype::Image,
|
||||
Viewtype::Unknown,
|
||||
)
|
||||
.await?
|
||||
.len(),
|
||||
2
|
||||
);
|
||||
assert_eq!(
|
||||
get_chat_media(
|
||||
&t,
|
||||
Some(chat_id2),
|
||||
Viewtype::Webxdc,
|
||||
Viewtype::Unknown,
|
||||
Viewtype::Unknown,
|
||||
)
|
||||
.await?
|
||||
.len(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
get_chat_media(
|
||||
&t,
|
||||
None,
|
||||
Viewtype::Image,
|
||||
Viewtype::Unknown,
|
||||
Viewtype::Unknown,
|
||||
)
|
||||
.await?
|
||||
.len(),
|
||||
2
|
||||
);
|
||||
assert_eq!(
|
||||
get_chat_media(
|
||||
&t,
|
||||
None,
|
||||
Viewtype::Image,
|
||||
Viewtype::Sticker,
|
||||
Viewtype::Unknown,
|
||||
)
|
||||
.await?
|
||||
.len(),
|
||||
3
|
||||
);
|
||||
assert_eq!(
|
||||
get_chat_media(
|
||||
&t,
|
||||
None,
|
||||
Viewtype::Image,
|
||||
Viewtype::Sticker,
|
||||
Viewtype::Webxdc,
|
||||
)
|
||||
.await?
|
||||
.len(),
|
||||
4
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user