Bitfl0wer/issue258 (#403)
This commit is contained in:
commit
ba0b143707
|
@ -16,7 +16,7 @@ serde_json = { version = "1.0.103", features = ["raw_value"] }
|
||||||
serde-aux = "4.2.0"
|
serde-aux = "4.2.0"
|
||||||
serde_with = "3.0.0"
|
serde_with = "3.0.0"
|
||||||
serde_repr = "0.1.14"
|
serde_repr = "0.1.14"
|
||||||
reqwest = { version = "0.11.18", features = ["multipart"] }
|
reqwest = { version = "0.11.18", features = ["multipart", "json"] }
|
||||||
url = "2.4.0"
|
url = "2.4.0"
|
||||||
chrono = { version = "0.4.26", features = ["serde"] }
|
chrono = { version = "0.4.26", features = ["serde"] }
|
||||||
regex = "1.9.1"
|
regex = "1.9.1"
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
use http::header::CONTENT_DISPOSITION;
|
use http::header::CONTENT_DISPOSITION;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use reqwest::{multipart, Client};
|
use reqwest::{multipart, Client};
|
||||||
use serde_json::to_string;
|
use serde_json::{from_value, to_string, Value};
|
||||||
|
|
||||||
use crate::api::LimitType;
|
use crate::api::LimitType;
|
||||||
use crate::errors::ChorusResult;
|
use crate::errors::{ChorusError, ChorusResult};
|
||||||
use crate::instance::UserMeta;
|
use crate::instance::UserMeta;
|
||||||
use crate::ratelimiter::ChorusRequest;
|
use crate::ratelimiter::ChorusRequest;
|
||||||
use crate::types::{Message, MessageSendSchema, Snowflake};
|
use crate::types::{
|
||||||
|
Channel, Message, MessageSearchEndpoint, MessageSearchQuery, MessageSendSchema, Snowflake,
|
||||||
|
};
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
/// Sends a message in the channel with the provided channel_id.
|
/// Sends a message in the channel with the provided channel_id.
|
||||||
|
@ -70,6 +72,71 @@ impl Message {
|
||||||
chorus_request.deserialize_response::<Message>(user).await
|
chorus_request.deserialize_response::<Message>(user).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns messages without the reactions key that match a search query in the guild or channel.
|
||||||
|
/// The messages that are direct results will have an extra hit key set to true.
|
||||||
|
/// If operating on a guild channel, this endpoint requires the `READ_MESSAGE_HISTORY`
|
||||||
|
/// permission to be present on the current user.
|
||||||
|
///
|
||||||
|
/// If the guild/channel you are searching is not yet indexed, the endpoint will return a 202 accepted response.
|
||||||
|
/// In this case, the method will return a [`ChorusError::InvalidResponse`] error.
|
||||||
|
///
|
||||||
|
/// # Reference:
|
||||||
|
/// See <https://discord-userdoccers.vercel.app/resources/message#search-messages>
|
||||||
|
pub(crate) async fn search(
|
||||||
|
endpoint: MessageSearchEndpoint,
|
||||||
|
query: MessageSearchQuery,
|
||||||
|
user: &mut UserMeta,
|
||||||
|
) -> ChorusResult<Vec<Message>> {
|
||||||
|
let limit_type = match &endpoint {
|
||||||
|
MessageSearchEndpoint::Channel(id) => LimitType::Channel(*id),
|
||||||
|
MessageSearchEndpoint::GuildChannel(id) => LimitType::Guild(*id),
|
||||||
|
};
|
||||||
|
let request = ChorusRequest {
|
||||||
|
limit_type,
|
||||||
|
request: Client::new()
|
||||||
|
.get(format!(
|
||||||
|
"{}/{}/messages/search",
|
||||||
|
&user.belongs_to.borrow().urls.api,
|
||||||
|
endpoint
|
||||||
|
))
|
||||||
|
.header("Authorization", user.token())
|
||||||
|
.body(to_string(&query).unwrap()),
|
||||||
|
};
|
||||||
|
let result = request.send_request(user).await?;
|
||||||
|
let result_json = result.json::<Value>().await.unwrap();
|
||||||
|
if !result_json.is_object() {
|
||||||
|
return Err(search_error(result_json.to_string()));
|
||||||
|
}
|
||||||
|
let value_map = result_json.as_object().unwrap();
|
||||||
|
if let Some(messages) = value_map.get("messages") {
|
||||||
|
if let Ok(response) = from_value::<Vec<Vec<Message>>>(messages.clone()) {
|
||||||
|
let result_messages: Vec<Message> = response.into_iter().flatten().collect();
|
||||||
|
return Ok(result_messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The code below might be incorrect. We'll cross that bridge when we come to it
|
||||||
|
if !value_map.contains_key("code") || !value_map.contains_key("retry_after") {
|
||||||
|
return Err(search_error(result_json.to_string()));
|
||||||
|
}
|
||||||
|
let code = value_map.get("code").unwrap().as_u64().unwrap();
|
||||||
|
let retry_after = value_map.get("retry_after").unwrap().as_u64().unwrap();
|
||||||
|
Err(ChorusError::NotFound {
|
||||||
|
error: format!(
|
||||||
|
"Index not yet available. Try again later. Code: {}. Retry after {}s",
|
||||||
|
code, retry_after
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_error(result_text: String) -> ChorusError {
|
||||||
|
ChorusError::InvalidResponse {
|
||||||
|
error: format!(
|
||||||
|
"Got unexpected Response, or Response which is not valid JSON. Response: \n{}",
|
||||||
|
result_text
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserMeta {
|
impl UserMeta {
|
||||||
|
@ -89,3 +156,23 @@ impl UserMeta {
|
||||||
Message::send(self, channel_id, message).await
|
Message::send(self, channel_id, message).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Channel {
|
||||||
|
/// Returns messages without the reactions key that match a search query in the channel.
|
||||||
|
/// The messages that are direct results will have an extra hit key set to true.
|
||||||
|
/// If operating on a guild channel, this endpoint requires the `READ_MESSAGE_HISTORY`
|
||||||
|
/// permission to be present on the current user.
|
||||||
|
///
|
||||||
|
/// If the guild/channel you are searching is not yet indexed, the endpoint will return a 202 accepted response.
|
||||||
|
/// In this case, the method will return a [`ChorusError::InvalidResponse`] error.
|
||||||
|
///
|
||||||
|
/// # Reference:
|
||||||
|
/// See <https://discord-userdoccers.vercel.app/resources/message#search-messages>
|
||||||
|
pub async fn search_messages(
|
||||||
|
channel_id: Snowflake,
|
||||||
|
query: MessageSearchQuery,
|
||||||
|
user: &mut UserMeta,
|
||||||
|
) -> ChorusResult<Vec<Message>> {
|
||||||
|
Message::search(MessageSearchEndpoint::Channel(channel_id), query, user).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
use crate::errors::ChorusResult;
|
||||||
|
use crate::instance::UserMeta;
|
||||||
|
use crate::types::{Guild, Message, MessageSearchQuery, Snowflake};
|
||||||
|
|
||||||
|
impl Guild {
|
||||||
|
/// Returns messages without the reactions key that match a search query in the guild.
|
||||||
|
/// The messages that are direct results will have an extra hit key set to true.
|
||||||
|
/// If operating on a guild channel, this endpoint requires the `READ_MESSAGE_HISTORY`
|
||||||
|
/// permission to be present on the current user.
|
||||||
|
///
|
||||||
|
/// If the guild/channel you are searching is not yet indexed, the endpoint will return a 202 accepted response.
|
||||||
|
/// In this case, the method will return a [`ChorusError::InvalidResponse`] error.
|
||||||
|
///
|
||||||
|
/// # Reference:
|
||||||
|
/// See <https://discord-userdoccers.vercel.app/resources/message#search-messages>
|
||||||
|
pub async fn search_messages(
|
||||||
|
guild_id: Snowflake,
|
||||||
|
query: MessageSearchQuery,
|
||||||
|
user: &mut UserMeta,
|
||||||
|
) -> ChorusResult<Vec<Message>> {
|
||||||
|
Message::search(
|
||||||
|
crate::types::MessageSearchEndpoint::GuildChannel(guild_id),
|
||||||
|
query,
|
||||||
|
user,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
pub use guilds::*;
|
pub use guilds::*;
|
||||||
|
pub use messages::*;
|
||||||
pub use roles::*;
|
pub use roles::*;
|
||||||
pub use roles::*;
|
pub use roles::*;
|
||||||
|
|
||||||
pub mod guilds;
|
pub mod guilds;
|
||||||
pub mod member;
|
pub mod member;
|
||||||
|
pub mod messages;
|
||||||
pub mod roles;
|
pub mod roles;
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub struct Attachment {
|
||||||
pub content: Option<Vec<u8>>,
|
pub content: Option<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
pub struct PartialDiscordFileAttachment {
|
pub struct PartialDiscordFileAttachment {
|
||||||
pub id: Option<i16>,
|
pub id: Option<i16>,
|
||||||
pub filename: String,
|
pub filename: String,
|
||||||
|
|
|
@ -176,10 +176,22 @@ pub struct DefaultReaction {
|
||||||
pub emoji_name: Option<String>,
|
pub emoji_name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy, Debug, Serialize_repr, Deserialize_repr, PartialEq, Eq, Hash)]
|
#[derive(
|
||||||
|
Default,
|
||||||
|
Clone,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
Serialize_repr,
|
||||||
|
Deserialize_repr,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
Hash,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
|
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
#[repr(i32)]
|
#[repr(u32)]
|
||||||
/// # Reference
|
/// # Reference
|
||||||
/// See <https://discord-userdoccers.vercel.app/resources/channel#channel-type>
|
/// See <https://discord-userdoccers.vercel.app/resources/channel#channel-type>
|
||||||
pub enum ChannelType {
|
pub enum ChannelType {
|
||||||
|
|
|
@ -114,7 +114,7 @@ pub struct ChannelMention {
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct Embed {
|
pub struct Embed {
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -132,14 +132,14 @@ pub struct Embed {
|
||||||
fields: Option<Vec<EmbedField>>,
|
fields: Option<Vec<EmbedField>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct EmbedFooter {
|
pub struct EmbedFooter {
|
||||||
text: String,
|
text: String,
|
||||||
icon_url: Option<String>,
|
icon_url: Option<String>,
|
||||||
proxy_icon_url: Option<String>,
|
proxy_icon_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||||
pub struct EmbedImage {
|
pub struct EmbedImage {
|
||||||
url: String,
|
url: String,
|
||||||
proxy_url: String,
|
proxy_url: String,
|
||||||
|
@ -147,7 +147,7 @@ pub struct EmbedImage {
|
||||||
width: Option<i32>,
|
width: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||||
pub struct EmbedThumbnail {
|
pub struct EmbedThumbnail {
|
||||||
url: String,
|
url: String,
|
||||||
proxy_url: Option<String>,
|
proxy_url: Option<String>,
|
||||||
|
@ -155,7 +155,7 @@ pub struct EmbedThumbnail {
|
||||||
width: Option<i32>,
|
width: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||||
struct EmbedVideo {
|
struct EmbedVideo {
|
||||||
url: Option<String>,
|
url: Option<String>,
|
||||||
proxy_url: Option<String>,
|
proxy_url: Option<String>,
|
||||||
|
@ -163,13 +163,13 @@ struct EmbedVideo {
|
||||||
width: Option<i32>,
|
width: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||||
pub struct EmbedProvider {
|
pub struct EmbedProvider {
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
url: Option<String>,
|
url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||||
pub struct EmbedAuthor {
|
pub struct EmbedAuthor {
|
||||||
name: String,
|
name: String,
|
||||||
url: Option<String>,
|
url: Option<String>,
|
||||||
|
@ -177,7 +177,7 @@ pub struct EmbedAuthor {
|
||||||
proxy_icon_url: Option<String>,
|
proxy_icon_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||||
pub struct EmbedField {
|
pub struct EmbedField {
|
||||||
name: String,
|
name: String,
|
||||||
value: String,
|
value: String,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::types::ChannelType;
|
||||||
use crate::types::{entities::PermissionOverwrite, Snowflake};
|
use crate::types::{entities::PermissionOverwrite, Snowflake};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Default, PartialEq, PartialOrd)]
|
#[derive(Debug, Deserialize, Serialize, Default, PartialEq, PartialOrd)]
|
||||||
|
@ -8,7 +9,7 @@ use crate::types::{entities::PermissionOverwrite, Snowflake};
|
||||||
pub struct ChannelCreateSchema {
|
pub struct ChannelCreateSchema {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub channel_type: Option<u8>,
|
pub channel_type: Option<ChannelType>,
|
||||||
pub topic: Option<String>,
|
pub topic: Option<String>,
|
||||||
pub icon: Option<String>,
|
pub icon: Option<String>,
|
||||||
pub bitrate: Option<i32>,
|
pub bitrate: Option<i32>,
|
||||||
|
|
|
@ -3,8 +3,9 @@ use serde::{Deserialize, Serialize};
|
||||||
use crate::types::entities::{
|
use crate::types::entities::{
|
||||||
AllowedMention, Component, Embed, MessageReference, PartialDiscordFileAttachment,
|
AllowedMention, Component, Embed, MessageReference, PartialDiscordFileAttachment,
|
||||||
};
|
};
|
||||||
|
use crate::types::Snowflake;
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct MessageSendSchema {
|
pub struct MessageSendSchema {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
@ -19,3 +20,79 @@ pub struct MessageSendSchema {
|
||||||
pub sticker_ids: Option<Vec<String>>,
|
pub sticker_ids: Option<Vec<String>>,
|
||||||
pub attachments: Option<Vec<PartialDiscordFileAttachment>>,
|
pub attachments: Option<Vec<PartialDiscordFileAttachment>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum MessageSearchEndpoint {
|
||||||
|
GuildChannel(Snowflake),
|
||||||
|
Channel(Snowflake),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for MessageSearchEndpoint {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
MessageSearchEndpoint::Channel(id) => {
|
||||||
|
write!(f, "channels/{}", &id.to_string())
|
||||||
|
}
|
||||||
|
MessageSearchEndpoint::GuildChannel(id) => {
|
||||||
|
write!(f, "guilds/{}", &id.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
/// Represents a Message Search Query JSON Body.
|
||||||
|
/// The `channel_id` field is not applicable when using the `GET /channels/{channel.id}/messages/search` endpoint.
|
||||||
|
///
|
||||||
|
/// # Reference:
|
||||||
|
/// See <https://discord-userdoccers.vercel.app/resources/message#search-messages>
|
||||||
|
pub struct MessageSearchQuery {
|
||||||
|
pub attachment_extension: Option<Vec<String>>,
|
||||||
|
pub attachment_filename: Option<Vec<String>>,
|
||||||
|
pub author_id: Option<Vec<Snowflake>>,
|
||||||
|
pub author_type: Option<Vec<String>>,
|
||||||
|
pub channel_id: Option<Vec<Snowflake>>,
|
||||||
|
pub command_id: Option<Vec<Snowflake>>,
|
||||||
|
pub content: Option<String>,
|
||||||
|
pub embed_provider: Option<Vec<String>>,
|
||||||
|
pub embed_type: Option<Vec<String>>,
|
||||||
|
pub has: Option<Vec<String>>,
|
||||||
|
pub include_nsfw: Option<bool>,
|
||||||
|
pub limit: Option<i32>,
|
||||||
|
pub link_hostname: Option<Vec<String>>,
|
||||||
|
pub max_id: Option<String>,
|
||||||
|
pub mention_everyone: Option<bool>,
|
||||||
|
pub mentions: Option<Vec<Snowflake>>,
|
||||||
|
pub min_id: Option<String>,
|
||||||
|
pub offset: Option<i32>,
|
||||||
|
pub pinned: Option<bool>,
|
||||||
|
pub sort_by: Option<String>,
|
||||||
|
pub sort_order: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::default::Default for MessageSearchQuery {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
attachment_extension: Default::default(),
|
||||||
|
attachment_filename: Default::default(),
|
||||||
|
author_id: Default::default(),
|
||||||
|
author_type: Default::default(),
|
||||||
|
channel_id: Default::default(),
|
||||||
|
command_id: Default::default(),
|
||||||
|
content: Default::default(),
|
||||||
|
embed_provider: Default::default(),
|
||||||
|
embed_type: Default::default(),
|
||||||
|
has: Default::default(),
|
||||||
|
include_nsfw: Some(false),
|
||||||
|
limit: Some(25),
|
||||||
|
link_hostname: Default::default(),
|
||||||
|
max_id: Default::default(),
|
||||||
|
mention_everyone: Default::default(),
|
||||||
|
mentions: Default::default(),
|
||||||
|
min_id: Default::default(),
|
||||||
|
offset: Some(0),
|
||||||
|
pinned: Default::default(),
|
||||||
|
sort_by: Default::default(),
|
||||||
|
sort_order: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ pub(crate) async fn setup() -> TestBundle {
|
||||||
};
|
};
|
||||||
let channel_create_schema = ChannelCreateSchema {
|
let channel_create_schema = ChannelCreateSchema {
|
||||||
name: "testchannel".to_string(),
|
name: "testchannel".to_string(),
|
||||||
channel_type: Some(0),
|
channel_type: Some(chorus::types::ChannelType::GuildText),
|
||||||
topic: None,
|
topic: None,
|
||||||
icon: None,
|
icon: None,
|
||||||
bitrate: None,
|
bitrate: None,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufReader, Read};
|
use std::io::{BufReader, Read};
|
||||||
|
|
||||||
use chorus::types;
|
use chorus::types::{self, Guild, MessageSearchQuery};
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
|
@ -53,3 +53,49 @@ async fn send_message_attachment() {
|
||||||
bundle.user.send_message(message, channel.id).await.unwrap();
|
bundle.user.send_message(message, channel.id).await.unwrap();
|
||||||
common::teardown(bundle).await
|
common::teardown(bundle).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn search_messages() {
|
||||||
|
let f = File::open("./README.md").unwrap();
|
||||||
|
let mut reader = BufReader::new(f);
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
let mut bundle = common::setup().await;
|
||||||
|
|
||||||
|
reader.read_to_end(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
let attachment = types::PartialDiscordFileAttachment {
|
||||||
|
id: None,
|
||||||
|
filename: "README.md".to_string(),
|
||||||
|
description: None,
|
||||||
|
content_type: None,
|
||||||
|
size: None,
|
||||||
|
url: None,
|
||||||
|
proxy_url: None,
|
||||||
|
width: None,
|
||||||
|
height: None,
|
||||||
|
ephemeral: None,
|
||||||
|
duration_secs: None,
|
||||||
|
waveform: None,
|
||||||
|
content: buffer,
|
||||||
|
};
|
||||||
|
|
||||||
|
let message = types::MessageSendSchema {
|
||||||
|
content: Some("trans rights now".to_string()),
|
||||||
|
attachments: Some(vec![attachment.clone()]),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let channel = bundle.channel.read().unwrap().clone();
|
||||||
|
let vec_attach = vec![attachment.clone()];
|
||||||
|
let _arg = Some(&vec_attach);
|
||||||
|
let message = bundle.user.send_message(message, channel.id).await.unwrap();
|
||||||
|
let query = MessageSearchQuery {
|
||||||
|
author_id: Some(Vec::from([bundle.user.object.read().unwrap().id])),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let guild_id = bundle.guild.read().unwrap().id;
|
||||||
|
let query_result = Guild::search_messages(guild_id, query, &mut bundle.user)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert!(!query_result.is_empty());
|
||||||
|
assert_eq!(query_result.get(0).unwrap().id, message.id);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue