Added the field voter to the PollAnswer struct

This commit is contained in:
Сырцев Вадим Игоревич 2024-06-26 11:36:36 +03:00
parent 3016cbaf68
commit f12e55bd2c
2 changed files with 112 additions and 7 deletions

View file

@ -1,17 +1,117 @@
use crate::types::User;
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize};
use crate::types::{Chat, User};
#[serde_with_macros::skip_serializing_none]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct PollAnswer {
/// Unique poll identifier.
pub poll_id: String,
/// The user, who changed the answer to the poll.
pub user: User,
/// If the voter is anonymous, stores the chat that changed the answer to
/// the poll.
///
/// If the voter isn't anonymous, stores the user that changed
/// the answer to the poll
#[serde(deserialize_with = "deserialize_voter", flatten)]
pub voter: Voter,
/// 0-based identifiers of answer options, chosen by the user.
///
/// May be empty if the user retracted their vote.
pub option_ids: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Voter {
Chat(Chat),
User(User),
}
impl Voter {
#[must_use]
pub fn chat(&self) -> Option<&Chat> {
match self {
Self::Chat(chat) => Some(chat),
_ => None,
}
}
#[must_use]
pub fn user(&self) -> Option<&User> {
match self {
Self::User(user) => Some(user),
_ => None,
}
}
}
/// These fields `chat` and `user` from the original [`PollAnswer`] should be
/// exclusive, but in cases when the `voter_chat` is presented the `user` isn't
/// `None`, but rather actual value for backward compatibility, the field `user`
/// in such objects will contain the user 136817688 (@Channel_Bot).
#[derive(Deserialize)]
struct VoterDe {
/// The chat that changed the answer to the poll, if the voter is anonymous
pub voter_chat: Option<Chat>,
/// The user that changed the answer to the poll, if the voter isn't
/// anonymous
pub user: Option<User>,
}
fn deserialize_voter<'d, D: Deserializer<'d>>(d: D) -> Result<Voter, D::Error> {
let VoterDe { voter_chat, user } = VoterDe::deserialize(d)?;
Ok(voter_chat.map(Voter::Chat).or(user.map(Voter::User)).unwrap())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_poll_answer_with_user_de() {
let json = r#"{
"poll_id":"POLL_ID",
"user": {"id":42,"is_bot":false,"first_name":"blah"},
"option_ids": []
}"#;
let poll_answer: PollAnswer = serde_json::from_str(json).unwrap();
assert!(matches!(poll_answer.voter, Voter::User(_)));
}
#[test]
fn test_poll_answer_with_voter_chat_de() {
let json = r#"{
"poll_id":"POLL_ID",
"voter_chat": {
"id": -1001160242915,
"title": "a",
"type": "group"
},
"option_ids": []
}"#;
let poll_answer: PollAnswer = serde_json::from_str(json).unwrap();
assert!(matches!(poll_answer.voter, Voter::Chat(_)));
}
#[test]
fn test_poll_answer_with_both_user_and_voter_chat_de() {
let json = r#"{
"poll_id":"POLL_ID",
"voter_chat": {
"id": -1001160242915,
"title": "a",
"type": "group"
},
"user": {"id":136817688,"is_bot":true,"first_name":"Channel_Bot"},
"option_ids": []
}"#;
let poll_answer: PollAnswer = serde_json::from_str(json).unwrap();
assert!(matches!(poll_answer.voter, Voter::Chat(_)));
}
}

View file

@ -136,7 +136,7 @@ impl Update {
InlineQuery(query) => &query.from,
ShippingQuery(query) => &query.from,
PreCheckoutQuery(query) => &query.from,
PollAnswer(answer) => &answer.user,
PollAnswer(answer) => return answer.voter.user(),
MyChatMember(m) | ChatMember(m) => &m.from,
ChatJoinRequest(r) => &r.from,
@ -198,7 +198,12 @@ impl Update {
UpdateKind::PreCheckoutQuery(query) => i1(once(&query.from)),
UpdateKind::Poll(poll) => i3(poll.mentioned_users()),
UpdateKind::PollAnswer(answer) => i1(once(&answer.user)),
UpdateKind::PollAnswer(answer) => {
if let Some(user) = answer.voter.user() {
return i1(once(user));
}
i6(empty())
}
UpdateKind::MyChatMember(member) | UpdateKind::ChatMember(member) => {
i4(member.mentioned_users())