mirror of
https://github.com/signalapp/libsignal.git
synced 2024-09-19 19:42:19 +02:00
backup: Be stricter about recipient kinds
This commit is contained in:
parent
358164c537
commit
6529c3d189
@ -6,7 +6,7 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use crate::backup::frame::RecipientId;
|
use crate::backup::frame::RecipientId;
|
||||||
use crate::backup::method::{Lookup, LookupPair};
|
use crate::backup::method::LookupPair;
|
||||||
use crate::backup::recipient::DestinationKind;
|
use crate::backup::recipient::DestinationKind;
|
||||||
use crate::backup::time::Timestamp;
|
use crate::backup::time::Timestamp;
|
||||||
use crate::backup::TryFromWith;
|
use crate::backup::TryFromWith;
|
||||||
@ -58,8 +58,12 @@ pub struct CallId(u64);
|
|||||||
pub enum CallError {
|
pub enum CallError {
|
||||||
/// call starter {0:?} not found,
|
/// call starter {0:?} not found,
|
||||||
UnknownCallStarter(RecipientId),
|
UnknownCallStarter(RecipientId),
|
||||||
|
/// call starter {0:?} is a {1:?}, not a contact or self
|
||||||
|
InvalidCallStarter(RecipientId, DestinationKind),
|
||||||
/// no record for ringer {0:?}
|
/// no record for ringer {0:?}
|
||||||
NoRingerRecipient(RecipientId),
|
NoRingerRecipient(RecipientId),
|
||||||
|
/// ringer {0:?} is a {1:?}, not a contact or self
|
||||||
|
InvalidRingerRecipient(RecipientId, DestinationKind),
|
||||||
/// no record for ad-hoc {0:?}
|
/// no record for ad-hoc {0:?}
|
||||||
NoAdHocRecipient(RecipientId),
|
NoAdHocRecipient(RecipientId),
|
||||||
/// ad-hoc recipient {0:?} is not a call link
|
/// ad-hoc recipient {0:?} is not a call link
|
||||||
@ -193,7 +197,9 @@ impl TryFrom<proto::IndividualCall> for IndividualCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Lookup<RecipientId, R>, R: Clone> TryFromWith<proto::GroupCall, C> for GroupCall<R> {
|
impl<C: LookupPair<RecipientId, DestinationKind, R>, R: Clone> TryFromWith<proto::GroupCall, C>
|
||||||
|
for GroupCall<R>
|
||||||
|
{
|
||||||
type Error = CallError;
|
type Error = CallError;
|
||||||
|
|
||||||
fn try_from_with(call: proto::GroupCall, context: &C) -> Result<Self, Self::Error> {
|
fn try_from_with(call: proto::GroupCall, context: &C) -> Result<Self, Self::Error> {
|
||||||
@ -211,20 +217,26 @@ impl<C: Lookup<RecipientId, R>, R: Clone> TryFromWith<proto::GroupCall, C> for G
|
|||||||
let started_call_recipient = startedCallRecipientId
|
let started_call_recipient = startedCallRecipientId
|
||||||
.map(|id| {
|
.map(|id| {
|
||||||
let id = RecipientId(id);
|
let id = RecipientId(id);
|
||||||
context
|
let (&starter_kind, starter) = context
|
||||||
.lookup(&id)
|
.lookup_pair(&id)
|
||||||
.ok_or(CallError::UnknownCallStarter(id))
|
.ok_or(CallError::UnknownCallStarter(id))?;
|
||||||
.cloned()
|
if !starter_kind.is_individual() {
|
||||||
|
return Err(CallError::InvalidCallStarter(id, starter_kind));
|
||||||
|
}
|
||||||
|
Ok(starter.clone())
|
||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
let ringer_recipient = ringerRecipientId
|
let ringer_recipient = ringerRecipientId
|
||||||
.map(|id| {
|
.map(|id| {
|
||||||
let id = RecipientId(id);
|
let id = RecipientId(id);
|
||||||
context
|
let (&ringer_kind, ringer) = context
|
||||||
.lookup(&id)
|
.lookup_pair(&id)
|
||||||
.ok_or(CallError::NoRingerRecipient(id))
|
.ok_or(CallError::NoRingerRecipient(id))?;
|
||||||
.cloned()
|
if !ringer_kind.is_individual() {
|
||||||
|
return Err(CallError::InvalidRingerRecipient(id, ringer_kind));
|
||||||
|
}
|
||||||
|
Ok(ringer.clone())
|
||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
@ -423,17 +435,19 @@ pub(crate) mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestContext;
|
impl CallLink {
|
||||||
|
pub(crate) fn from_proto_test_data() -> Self {
|
||||||
|
Self {
|
||||||
|
admin_approval: false,
|
||||||
|
root_key: TEST_CALL_LINK_ROOT_KEY,
|
||||||
|
admin_key: Some(TEST_CALL_LINK_ADMIN_KEY.to_vec()),
|
||||||
|
expiration: Timestamp::test_value(),
|
||||||
|
name: "".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Lookup<RecipientId, DestinationKind> for TestContext {
|
struct TestContext;
|
||||||
fn lookup(&self, key: &RecipientId) -> Option<&DestinationKind> {
|
|
||||||
match key {
|
|
||||||
RecipientId(proto::Recipient::TEST_ID) => Some(&DestinationKind::Contact),
|
|
||||||
&TEST_CALL_LINK_RECIPIENT_ID => Some(&DestinationKind::CallLink),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LookupPair<RecipientId, DestinationKind, RecipientId> for TestContext {
|
impl LookupPair<RecipientId, DestinationKind, RecipientId> for TestContext {
|
||||||
fn lookup_pair<'a>(
|
fn lookup_pair<'a>(
|
||||||
@ -480,7 +494,7 @@ pub(crate) mod test {
|
|||||||
id: None,
|
id: None,
|
||||||
state: GroupCallState::Accepted,
|
state: GroupCallState::Accepted,
|
||||||
started_call_recipient: None,
|
started_call_recipient: None,
|
||||||
ringer_recipient: Some(DestinationKind::Contact),
|
ringer_recipient: Some(RecipientId(proto::Recipient::TEST_ID)),
|
||||||
started_at: Timestamp::test_value(),
|
started_at: Timestamp::test_value(),
|
||||||
ended_at: Timestamp::test_value() + Duration::from_millis(1000),
|
ended_at: Timestamp::test_value() + Duration::from_millis(1000),
|
||||||
read: true,
|
read: true,
|
||||||
@ -488,11 +502,22 @@ pub(crate) mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test_case(|x| x.ringerRecipientId = None => Ok(()); "no_ringer_id")]
|
#[test_case(|x| x.ringerRecipientId = None => Ok(()); "no ringer")]
|
||||||
#[test_case(
|
#[test_case(|x| {
|
||||||
|x| x.ringerRecipientId = Some(NONEXISTENT_RECIPIENT.0) => Err(CallError::NoRingerRecipient(NONEXISTENT_RECIPIENT));
|
x.ringerRecipientId = Some(NONEXISTENT_RECIPIENT.0)
|
||||||
"wrong_wringer_id"
|
} => Err(CallError::NoRingerRecipient(NONEXISTENT_RECIPIENT)); "nonexistent ringer")]
|
||||||
)]
|
#[test_case(|x| {
|
||||||
|
x.ringerRecipientId = Some(TEST_CALL_LINK_RECIPIENT_ID.0)
|
||||||
|
} => Err(CallError::InvalidRingerRecipient(TEST_CALL_LINK_RECIPIENT_ID, DestinationKind::CallLink)); "invalid ringer")]
|
||||||
|
#[test_case(|x| {
|
||||||
|
x.startedCallRecipientId = Some(proto::Recipient::TEST_ID)
|
||||||
|
} => Ok(()); "has call starter")]
|
||||||
|
#[test_case(|x| {
|
||||||
|
x.startedCallRecipientId = Some(NONEXISTENT_RECIPIENT.0)
|
||||||
|
} => Err(CallError::UnknownCallStarter(NONEXISTENT_RECIPIENT)); "nonexistent call starter")]
|
||||||
|
#[test_case(|x| {
|
||||||
|
x.startedCallRecipientId = Some(TEST_CALL_LINK_RECIPIENT_ID.0)
|
||||||
|
} => Err(CallError::InvalidCallStarter(TEST_CALL_LINK_RECIPIENT_ID, DestinationKind::CallLink)); "invalid call starter")]
|
||||||
#[test_case(|x| x.state = EnumOrUnknown::default() => Err(CallError::UnknownState); "unknown_state")]
|
#[test_case(|x| x.state = EnumOrUnknown::default() => Err(CallError::UnknownState); "unknown_state")]
|
||||||
fn group_call(modifier: fn(&mut proto::GroupCall)) -> Result<(), CallError> {
|
fn group_call(modifier: fn(&mut proto::GroupCall)) -> Result<(), CallError> {
|
||||||
let mut call = proto::GroupCall::test_data();
|
let mut call = proto::GroupCall::test_data();
|
||||||
@ -531,13 +556,7 @@ pub(crate) mod test {
|
|||||||
fn valid_call_link() {
|
fn valid_call_link() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
proto::CallLink::test_data().try_into(),
|
proto::CallLink::test_data().try_into(),
|
||||||
Ok(CallLink {
|
Ok(CallLink::from_proto_test_data())
|
||||||
admin_approval: false,
|
|
||||||
root_key: TEST_CALL_LINK_ROOT_KEY,
|
|
||||||
admin_key: Some(TEST_CALL_LINK_ADMIN_KEY.to_vec()),
|
|
||||||
expiration: Timestamp::test_value(),
|
|
||||||
name: "".to_string(),
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,8 @@ use derive_where::derive_where;
|
|||||||
use crate::backup::chat::chat_style::{ChatStyle, ChatStyleError, CustomColorId};
|
use crate::backup::chat::chat_style::{ChatStyle, ChatStyleError, CustomColorId};
|
||||||
use crate::backup::file::{FilePointerError, MessageAttachmentError};
|
use crate::backup::file::{FilePointerError, MessageAttachmentError};
|
||||||
use crate::backup::frame::RecipientId;
|
use crate::backup::frame::RecipientId;
|
||||||
use crate::backup::method::{Lookup, Method};
|
use crate::backup::method::{Lookup, LookupPair, Method};
|
||||||
|
use crate::backup::recipient::DestinationKind;
|
||||||
use crate::backup::serialize::{SerializeOrder, UnorderedList};
|
use crate::backup::serialize::{SerializeOrder, UnorderedList};
|
||||||
use crate::backup::sticker::MessageStickerError;
|
use crate::backup::sticker::MessageStickerError;
|
||||||
use crate::backup::time::{Duration, Timestamp};
|
use crate::backup::time::{Duration, Timestamp};
|
||||||
@ -66,6 +67,8 @@ pub enum ChatError {
|
|||||||
DuplicateId,
|
DuplicateId,
|
||||||
/// no record for {0:?}
|
/// no record for {0:?}
|
||||||
NoRecipient(RecipientId),
|
NoRecipient(RecipientId),
|
||||||
|
/// cannot have a chat with recipient {0:?}, a {1:?}
|
||||||
|
InvalidRecipient(RecipientId, DestinationKind),
|
||||||
/// chat item: {0}
|
/// chat item: {0}
|
||||||
ChatItem(#[from] ChatItemError),
|
ChatItem(#[from] ChatItemError),
|
||||||
/// {0:?} already appeared
|
/// {0:?} already appeared
|
||||||
@ -81,6 +84,8 @@ pub enum ChatItemError {
|
|||||||
NoChatForItem,
|
NoChatForItem,
|
||||||
/// no record for chat item author {0:?}
|
/// no record for chat item author {0:?}
|
||||||
AuthorNotFound(RecipientId),
|
AuthorNotFound(RecipientId),
|
||||||
|
/// chat item author {0:?} is a {1:?}
|
||||||
|
InvalidAuthor(RecipientId, DestinationKind),
|
||||||
/// ChatItem.item is a oneof but is empty
|
/// ChatItem.item is a oneof but is empty
|
||||||
MissingItem,
|
MissingItem,
|
||||||
/// text: {0}
|
/// text: {0}
|
||||||
@ -238,6 +243,8 @@ impl<Recipient: SerializeOrder> SerializeOrder for Reaction<Recipient> {
|
|||||||
pub enum ReactionError {
|
pub enum ReactionError {
|
||||||
/// unknown author {0:?}
|
/// unknown author {0:?}
|
||||||
AuthorNotFound(RecipientId),
|
AuthorNotFound(RecipientId),
|
||||||
|
/// author {0:?} was a {1:?}, not a contact or self
|
||||||
|
InvalidAuthor(RecipientId, DestinationKind),
|
||||||
/// "emoji" is an empty string
|
/// "emoji" is an empty string
|
||||||
EmptyEmoji,
|
EmptyEmoji,
|
||||||
}
|
}
|
||||||
@ -292,6 +299,8 @@ pub enum DeliveryStatus {
|
|||||||
pub enum OutgoingSendError {
|
pub enum OutgoingSendError {
|
||||||
/// send status has unknown recipient {0:?}
|
/// send status has unknown recipient {0:?}
|
||||||
UnknownRecipient(RecipientId),
|
UnknownRecipient(RecipientId),
|
||||||
|
/// send status recipient {0:?} is a {1:?}, not a contact or self
|
||||||
|
InvalidRecipient(RecipientId, DestinationKind),
|
||||||
/// send status is missing
|
/// send status is missing
|
||||||
SendStatusMissing,
|
SendStatusMissing,
|
||||||
}
|
}
|
||||||
@ -318,7 +327,7 @@ impl std::fmt::Display for InvalidExpiration {
|
|||||||
|
|
||||||
impl<
|
impl<
|
||||||
M: Method + ReferencedTypes,
|
M: Method + ReferencedTypes,
|
||||||
C: Lookup<RecipientId, M::RecipientReference>
|
C: LookupPair<RecipientId, DestinationKind, M::RecipientReference>
|
||||||
+ Lookup<PinOrder, M::RecipientReference>
|
+ Lookup<PinOrder, M::RecipientReference>
|
||||||
+ Lookup<CustomColorId, M::CustomColorReference>,
|
+ Lookup<CustomColorId, M::CustomColorReference>,
|
||||||
> TryFromWith<proto::Chat, C> for ChatData<M>
|
> TryFromWith<proto::Chat, C> for ChatData<M>
|
||||||
@ -339,10 +348,19 @@ impl<
|
|||||||
special_fields: _,
|
special_fields: _,
|
||||||
} = value;
|
} = value;
|
||||||
|
|
||||||
let recipient = RecipientId(recipientId);
|
let recipient_id = RecipientId(recipientId);
|
||||||
let Some(recipient) = context.lookup(&recipient).cloned() else {
|
let Some((&kind, recipient)) = context.lookup_pair(&recipient_id) else {
|
||||||
return Err(ChatError::NoRecipient(recipient));
|
return Err(ChatError::NoRecipient(recipient_id));
|
||||||
};
|
};
|
||||||
|
let recipient = match kind {
|
||||||
|
DestinationKind::Contact
|
||||||
|
| DestinationKind::Group
|
||||||
|
| DestinationKind::Self_
|
||||||
|
| DestinationKind::ReleaseNotes => Ok(recipient.clone()),
|
||||||
|
DestinationKind::DistributionList | DestinationKind::CallLink => {
|
||||||
|
Err(ChatError::InvalidRecipient(recipient_id, kind))
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
|
||||||
let pinned_order = NonZeroU32::new(pinnedOrder).map(PinOrder);
|
let pinned_order = NonZeroU32::new(pinnedOrder).map(PinOrder);
|
||||||
if let Some(pinned_order) = pinned_order {
|
if let Some(pinned_order) = pinned_order {
|
||||||
@ -376,7 +394,7 @@ impl<
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
C: Lookup<RecipientId, M::RecipientReference> + AsRef<BackupMeta>,
|
C: LookupPair<RecipientId, DestinationKind, M::RecipientReference> + AsRef<BackupMeta>,
|
||||||
M: Method + ReferencedTypes,
|
M: Method + ReferencedTypes,
|
||||||
> TryFromWith<proto::ChatItem, C> for ChatItemData<M>
|
> TryFromWith<proto::ChatItem, C> for ChatItemData<M>
|
||||||
{
|
{
|
||||||
@ -396,11 +414,23 @@ impl<
|
|||||||
special_fields: _,
|
special_fields: _,
|
||||||
} = value;
|
} = value;
|
||||||
|
|
||||||
let author = RecipientId(authorId);
|
let author_id = RecipientId(authorId);
|
||||||
|
|
||||||
let Some(author) = context.lookup(&author).cloned() else {
|
let Some((&author_kind, author)) = context.lookup_pair(&author_id) else {
|
||||||
return Err(ChatItemError::AuthorNotFound(author));
|
return Err(ChatItemError::AuthorNotFound(author_id));
|
||||||
};
|
};
|
||||||
|
let author = match author_kind {
|
||||||
|
DestinationKind::Contact | DestinationKind::Self_ | DestinationKind::ReleaseNotes => {
|
||||||
|
Ok(author.clone())
|
||||||
|
}
|
||||||
|
// Even update messages in groups are still attributed to self (if not a specific
|
||||||
|
// author)
|
||||||
|
DestinationKind::Group
|
||||||
|
| DestinationKind::DistributionList
|
||||||
|
| DestinationKind::CallLink => {
|
||||||
|
Err(ChatItemError::InvalidAuthor(author_id, author_kind))
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
|
||||||
let message = item
|
let message = item
|
||||||
.ok_or(ChatItemError::MissingItem)?
|
.ok_or(ChatItemError::MissingItem)?
|
||||||
@ -494,8 +524,8 @@ impl<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::chat_item::DirectionalDetails, C>
|
impl<R: Clone, C: LookupPair<RecipientId, DestinationKind, R>>
|
||||||
for Direction<R>
|
TryFromWith<proto::chat_item::DirectionalDetails, C> for Direction<R>
|
||||||
{
|
{
|
||||||
type Error = ChatItemError;
|
type Error = ChatItemError;
|
||||||
|
|
||||||
@ -538,7 +568,9 @@ impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::chat_item::Directio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::SendStatus, C> for OutgoingSend<R> {
|
impl<R: Clone, C: LookupPair<RecipientId, DestinationKind, R>> TryFromWith<proto::SendStatus, C>
|
||||||
|
for OutgoingSend<R>
|
||||||
|
{
|
||||||
type Error = OutgoingSendError;
|
type Error = OutgoingSendError;
|
||||||
|
|
||||||
fn try_from_with(item: proto::SendStatus, context: &C) -> Result<Self, Self::Error> {
|
fn try_from_with(item: proto::SendStatus, context: &C) -> Result<Self, Self::Error> {
|
||||||
@ -550,9 +582,13 @@ impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::SendStatus, C> for
|
|||||||
} = item;
|
} = item;
|
||||||
|
|
||||||
let recipient_id = RecipientId(recipientId);
|
let recipient_id = RecipientId(recipientId);
|
||||||
let Some(recipient) = context.lookup(&recipient_id).cloned() else {
|
let Some((&kind, recipient)) = context.lookup_pair(&recipient_id) else {
|
||||||
return Err(OutgoingSendError::UnknownRecipient(recipient_id));
|
return Err(OutgoingSendError::UnknownRecipient(recipient_id));
|
||||||
};
|
};
|
||||||
|
if !kind.is_individual() {
|
||||||
|
return Err(OutgoingSendError::InvalidRecipient(recipient_id, kind));
|
||||||
|
}
|
||||||
|
let recipient = recipient.clone();
|
||||||
|
|
||||||
let Some(status) = deliveryStatus else {
|
let Some(status) = deliveryStatus else {
|
||||||
return Err(OutgoingSendError::SendStatusMissing);
|
return Err(OutgoingSendError::SendStatusMissing);
|
||||||
@ -617,7 +653,7 @@ impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::SendStatus, C> for
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
R: Lookup<RecipientId, M::RecipientReference> + AsRef<BackupMeta>,
|
R: LookupPair<RecipientId, DestinationKind, M::RecipientReference> + AsRef<BackupMeta>,
|
||||||
M: Method + ReferencedTypes,
|
M: Method + ReferencedTypes,
|
||||||
> TryFromWith<proto::chat_item::Item, R> for ChatItemMessage<M>
|
> TryFromWith<proto::chat_item::Item, R> for ChatItemMessage<M>
|
||||||
{
|
{
|
||||||
@ -660,7 +696,9 @@ impl<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::Reaction, C> for Reaction<R> {
|
impl<R: Clone, C: LookupPair<RecipientId, DestinationKind, R>> TryFromWith<proto::Reaction, C>
|
||||||
|
for Reaction<R>
|
||||||
|
{
|
||||||
type Error = ReactionError;
|
type Error = ReactionError;
|
||||||
|
|
||||||
fn try_from_with(item: proto::Reaction, context: &C) -> Result<Self, Self::Error> {
|
fn try_from_with(item: proto::Reaction, context: &C) -> Result<Self, Self::Error> {
|
||||||
@ -677,9 +715,13 @@ impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::Reaction, C> for Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
let author_id = RecipientId(authorId);
|
let author_id = RecipientId(authorId);
|
||||||
let Some(author) = context.lookup(&author_id).cloned() else {
|
let Some((&author_kind, author)) = context.lookup_pair(&author_id) else {
|
||||||
return Err(ReactionError::AuthorNotFound(author_id));
|
return Err(ReactionError::AuthorNotFound(author_id));
|
||||||
};
|
};
|
||||||
|
if !author_kind.is_individual() {
|
||||||
|
return Err(ReactionError::InvalidAuthor(author_id, author_kind));
|
||||||
|
}
|
||||||
|
let author = author.clone();
|
||||||
|
|
||||||
let sent_timestamp = Timestamp::from_millis(sentTimestamp, "Reaction.sentTimestamp");
|
let sent_timestamp = Timestamp::from_millis(sentTimestamp, "Reaction.sentTimestamp");
|
||||||
|
|
||||||
@ -801,6 +843,12 @@ mod test {
|
|||||||
Err(ChatError::DuplicatePinnedOrder(TestContext::DUPLICATE_PINNED_ORDER,));
|
Err(ChatError::DuplicatePinnedOrder(TestContext::DUPLICATE_PINNED_ORDER,));
|
||||||
"duplicate_pinned_order"
|
"duplicate_pinned_order"
|
||||||
)]
|
)]
|
||||||
|
#[test_case(|x| {
|
||||||
|
x.recipientId = TestContext::CALL_LINK_ID.0;
|
||||||
|
} => Err(ChatError::InvalidRecipient(TestContext::CALL_LINK_ID, DestinationKind::CallLink)); "call link chat")]
|
||||||
|
#[test_case(|x| {
|
||||||
|
x.recipientId = 0;
|
||||||
|
} => Err(ChatError::NoRecipient(RecipientId(0))); "unknown recipient")]
|
||||||
fn chat(modifier: fn(&mut proto::Chat)) -> Result<(), ChatError> {
|
fn chat(modifier: fn(&mut proto::Chat)) -> Result<(), ChatError> {
|
||||||
let mut chat = proto::Chat::test_data();
|
let mut chat = proto::Chat::test_data();
|
||||||
modifier(&mut chat);
|
modifier(&mut chat);
|
||||||
@ -833,6 +881,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test_case(|x| x.authorId = 0xffff => Err(ChatItemError::AuthorNotFound(RecipientId(0xffff))); "unknown_author")]
|
#[test_case(|x| x.authorId = 0xffff => Err(ChatItemError::AuthorNotFound(RecipientId(0xffff))); "unknown_author")]
|
||||||
|
#[test_case(|x| x.authorId = TestContext::GROUP_ID.0 => Err(ChatItemError::InvalidAuthor(TestContext::GROUP_ID, DestinationKind::Group)); "invalid author")]
|
||||||
#[test_case(|x| x.directionalDetails = None => Err(ChatItemError::NoDirection); "no_direction")]
|
#[test_case(|x| x.directionalDetails = None => Err(ChatItemError::NoDirection); "no_direction")]
|
||||||
#[test_case(|x| x.directionalDetails = Some(proto::chat_item::OutgoingMessageDetails::test_data().into()) => Ok(()); "outgoing_valid")]
|
#[test_case(|x| x.directionalDetails = Some(proto::chat_item::OutgoingMessageDetails::test_data().into()) => Ok(()); "outgoing_valid")]
|
||||||
#[test_case(|x| x.directionalDetails = Some(
|
#[test_case(|x| x.directionalDetails = Some(
|
||||||
@ -875,6 +924,18 @@ mod test {
|
|||||||
.into(),
|
.into(),
|
||||||
) => Err(ChatItemError::Outgoing(OutgoingSendError::UnknownRecipient(RecipientId(0xffff)))); "outgoing_unknown_recipient"
|
) => Err(ChatItemError::Outgoing(OutgoingSendError::UnknownRecipient(RecipientId(0xffff)))); "outgoing_unknown_recipient"
|
||||||
)]
|
)]
|
||||||
|
#[test_case(
|
||||||
|
|x| x.directionalDetails = Some(
|
||||||
|
proto::chat_item::OutgoingMessageDetails {
|
||||||
|
sendStatus: vec![proto::SendStatus {
|
||||||
|
recipientId: TestContext::GROUP_ID.0,
|
||||||
|
..proto::SendStatus::test_data()
|
||||||
|
}],
|
||||||
|
..proto::chat_item::OutgoingMessageDetails::test_data()
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
) => Err(ChatItemError::Outgoing(OutgoingSendError::InvalidRecipient(TestContext::GROUP_ID, DestinationKind::Group))); "outgoing invalid recipient"
|
||||||
|
)]
|
||||||
#[test_case(|x| x.directionalDetails = Some(proto::chat_item::DirectionlessMessageDetails::default().into()) => Err(ChatItemError::DirectionlessMessage); "directionless_non_update")]
|
#[test_case(|x| x.directionalDetails = Some(proto::chat_item::DirectionlessMessageDetails::default().into()) => Err(ChatItemError::DirectionlessMessage); "directionless_non_update")]
|
||||||
#[test_case(|x| {
|
#[test_case(|x| {
|
||||||
x.directionalDetails = Some(proto::chat_item::DirectionlessMessageDetails::default().into());
|
x.directionalDetails = Some(proto::chat_item::DirectionlessMessageDetails::default().into());
|
||||||
@ -905,7 +966,11 @@ mod test {
|
|||||||
|
|
||||||
#[test_case(
|
#[test_case(
|
||||||
|x| x.authorId = proto::Recipient::TEST_ID + 2 => Err(ReactionError::AuthorNotFound(RecipientId(proto::Recipient::TEST_ID + 2)));
|
|x| x.authorId = proto::Recipient::TEST_ID + 2 => Err(ReactionError::AuthorNotFound(RecipientId(proto::Recipient::TEST_ID + 2)));
|
||||||
"invalid_author_id"
|
"unknown author id"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
|x| x.authorId = TestContext::GROUP_ID.0 => Err(ReactionError::InvalidAuthor(TestContext::GROUP_ID, DestinationKind::Group));
|
||||||
|
"invalid author id"
|
||||||
)]
|
)]
|
||||||
fn reaction(modifier: fn(&mut proto::Reaction)) -> Result<(), ReactionError> {
|
fn reaction(modifier: fn(&mut proto::Reaction)) -> Result<(), ReactionError> {
|
||||||
let mut reaction = proto::Reaction::test_data();
|
let mut reaction = proto::Reaction::test_data();
|
||||||
|
@ -407,8 +407,8 @@ mod test {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::backup::chat::chat_style::Color;
|
use crate::backup::chat::chat_style::Color;
|
||||||
use crate::backup::testutil::TestContext;
|
|
||||||
use crate::backup::method::Store;
|
use crate::backup::method::Store;
|
||||||
|
use crate::backup::testutil::TestContext;
|
||||||
|
|
||||||
impl proto::ChatStyle {
|
impl proto::ChatStyle {
|
||||||
fn test_data() -> Self {
|
fn test_data() -> Self {
|
||||||
|
@ -7,7 +7,8 @@ use protobuf::EnumOrUnknown;
|
|||||||
use crate::backup::chat::{ChatItemError, Reaction};
|
use crate::backup::chat::{ChatItemError, Reaction};
|
||||||
use crate::backup::file::{FilePointer, FilePointerError};
|
use crate::backup::file::{FilePointer, FilePointerError};
|
||||||
use crate::backup::frame::RecipientId;
|
use crate::backup::frame::RecipientId;
|
||||||
use crate::backup::method::Lookup;
|
use crate::backup::method::LookupPair;
|
||||||
|
use crate::backup::recipient::DestinationKind;
|
||||||
use crate::backup::serialize::{SerializeOrder, UnorderedList};
|
use crate::backup::serialize::{SerializeOrder, UnorderedList};
|
||||||
use crate::backup::{TryFromWith, TryIntoWith as _};
|
use crate::backup::{TryFromWith, TryIntoWith as _};
|
||||||
use crate::proto::backup as proto;
|
use crate::proto::backup as proto;
|
||||||
@ -45,7 +46,7 @@ pub enum ContactAttachmentError {
|
|||||||
Avatar(FilePointerError),
|
Avatar(FilePointerError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::ContactMessage, C>
|
impl<R: Clone, C: LookupPair<RecipientId, DestinationKind, R>> TryFromWith<proto::ContactMessage, C>
|
||||||
for ContactMessage<R>
|
for ContactMessage<R>
|
||||||
{
|
{
|
||||||
type Error = ChatItemError;
|
type Error = ChatItemError;
|
||||||
@ -172,9 +173,9 @@ mod test {
|
|||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::backup::testutil::TestContext;
|
|
||||||
use crate::backup::chat::ReactionError;
|
use crate::backup::chat::ReactionError;
|
||||||
use crate::backup::recipient::FullRecipientData;
|
use crate::backup::recipient::FullRecipientData;
|
||||||
|
use crate::backup::testutil::TestContext;
|
||||||
|
|
||||||
impl proto::ContactMessage {
|
impl proto::ContactMessage {
|
||||||
fn test_data() -> Self {
|
fn test_data() -> Self {
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
use crate::backup::chat::text::{MessageText, TextError};
|
use crate::backup::chat::text::{MessageText, TextError};
|
||||||
use crate::backup::file::{MessageAttachment, MessageAttachmentError};
|
use crate::backup::file::{MessageAttachment, MessageAttachmentError};
|
||||||
use crate::backup::frame::RecipientId;
|
use crate::backup::frame::RecipientId;
|
||||||
use crate::backup::method::Lookup;
|
use crate::backup::method::LookupPair;
|
||||||
|
use crate::backup::recipient::DestinationKind;
|
||||||
use crate::backup::time::Timestamp;
|
use crate::backup::time::Timestamp;
|
||||||
use crate::backup::TryFromWith;
|
use crate::backup::TryFromWith;
|
||||||
use crate::proto::backup as proto;
|
use crate::proto::backup as proto;
|
||||||
@ -47,6 +48,8 @@ pub struct QuotedAttachment {
|
|||||||
pub enum QuoteError {
|
pub enum QuoteError {
|
||||||
/// has unknown author {0:?}
|
/// has unknown author {0:?}
|
||||||
AuthorNotFound(RecipientId),
|
AuthorNotFound(RecipientId),
|
||||||
|
/// author {0:?} is a {1:?}, not a contact or self
|
||||||
|
InvalidAuthor(RecipientId, DestinationKind),
|
||||||
/// "type" is unknown
|
/// "type" is unknown
|
||||||
TypeUnknown,
|
TypeUnknown,
|
||||||
/// text error: {0}
|
/// text error: {0}
|
||||||
@ -57,7 +60,9 @@ pub enum QuoteError {
|
|||||||
AttachmentThumbnailWrongFlag(proto::message_attachment::Flag),
|
AttachmentThumbnailWrongFlag(proto::message_attachment::Flag),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::Quote, C> for Quote<R> {
|
impl<R: Clone, C: LookupPair<RecipientId, DestinationKind, R>> TryFromWith<proto::Quote, C>
|
||||||
|
for Quote<R>
|
||||||
|
{
|
||||||
type Error = QuoteError;
|
type Error = QuoteError;
|
||||||
|
|
||||||
fn try_from_with(item: proto::Quote, context: &C) -> Result<Self, Self::Error> {
|
fn try_from_with(item: proto::Quote, context: &C) -> Result<Self, Self::Error> {
|
||||||
@ -71,9 +76,21 @@ impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::Quote, C> for Quote
|
|||||||
} = item;
|
} = item;
|
||||||
|
|
||||||
let author_id = RecipientId(authorId);
|
let author_id = RecipientId(authorId);
|
||||||
let Some(author) = context.lookup(&author_id).cloned() else {
|
let Some((&author_kind, author)) = context.lookup_pair(&author_id) else {
|
||||||
return Err(QuoteError::AuthorNotFound(author_id));
|
return Err(QuoteError::AuthorNotFound(author_id));
|
||||||
};
|
};
|
||||||
|
let author = match author_kind {
|
||||||
|
DestinationKind::Contact
|
||||||
|
| DestinationKind::Self_
|
||||||
|
// As of Sep 2024, the release notes channel doesn't currently quote messages,
|
||||||
|
// but there's no reason it couldn't.
|
||||||
|
| DestinationKind::ReleaseNotes => {
|
||||||
|
Ok(author.clone())
|
||||||
|
}
|
||||||
|
DestinationKind::Group
|
||||||
|
| DestinationKind::DistributionList
|
||||||
|
| DestinationKind::CallLink => Err(QuoteError::InvalidAuthor(author_id, author_kind)),
|
||||||
|
}?;
|
||||||
|
|
||||||
let target_sent_timestamp = targetSentTimestamp
|
let target_sent_timestamp = targetSentTimestamp
|
||||||
.map(|timestamp| Timestamp::from_millis(timestamp, "Quote.targetSentTimestamp"));
|
.map(|timestamp| Timestamp::from_millis(timestamp, "Quote.targetSentTimestamp"));
|
||||||
@ -142,8 +159,8 @@ mod test {
|
|||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::backup::testutil::TestContext;
|
|
||||||
use crate::backup::recipient::FullRecipientData;
|
use crate::backup::recipient::FullRecipientData;
|
||||||
|
use crate::backup::testutil::TestContext;
|
||||||
use crate::backup::time::testutil::MillisecondsSinceEpoch;
|
use crate::backup::time::testutil::MillisecondsSinceEpoch;
|
||||||
|
|
||||||
impl proto::quote::QuotedAttachment {
|
impl proto::quote::QuotedAttachment {
|
||||||
@ -216,4 +233,16 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case(|_| {} => Ok(()); "valid")]
|
||||||
|
#[test_case(|x| x.authorId = 0 => Err(QuoteError::AuthorNotFound(RecipientId(0))); "unknown author")]
|
||||||
|
#[test_case(|x| {
|
||||||
|
x.authorId = TestContext::GROUP_ID.0
|
||||||
|
} => Err(QuoteError::InvalidAuthor(TestContext::GROUP_ID, DestinationKind::Group)); "invalid author")]
|
||||||
|
#[test_case(|x| x.type_ = proto::quote::Type::UNKNOWN.into() => Err(QuoteError::TypeUnknown); "unknown type")]
|
||||||
|
fn quote(modifier: impl FnOnce(&mut proto::Quote)) -> Result<(), QuoteError> {
|
||||||
|
let mut attachment = proto::Quote::test_data();
|
||||||
|
modifier(&mut attachment);
|
||||||
|
Quote::try_from_with(attachment, &TestContext::default()).map(|_| ())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,8 @@ use crate::backup::chat::text::MessageText;
|
|||||||
use crate::backup::chat::{ChatItemError, Reaction};
|
use crate::backup::chat::{ChatItemError, Reaction};
|
||||||
use crate::backup::file::{FilePointer, MessageAttachment};
|
use crate::backup::file::{FilePointer, MessageAttachment};
|
||||||
use crate::backup::frame::RecipientId;
|
use crate::backup::frame::RecipientId;
|
||||||
use crate::backup::method::Lookup;
|
use crate::backup::method::LookupPair;
|
||||||
|
use crate::backup::recipient::DestinationKind;
|
||||||
use crate::backup::serialize::{SerializeOrder, UnorderedList};
|
use crate::backup::serialize::{SerializeOrder, UnorderedList};
|
||||||
use crate::backup::{TryFromWith, TryIntoWith as _};
|
use crate::backup::{TryFromWith, TryIntoWith as _};
|
||||||
use crate::proto::backup as proto;
|
use crate::proto::backup as proto;
|
||||||
@ -27,8 +28,8 @@ pub struct StandardMessage<Recipient> {
|
|||||||
_limit_construction_to_module: (),
|
_limit_construction_to_module: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::StandardMessage, C>
|
impl<R: Clone, C: LookupPair<RecipientId, DestinationKind, R>>
|
||||||
for StandardMessage<R>
|
TryFromWith<proto::StandardMessage, C> for StandardMessage<R>
|
||||||
{
|
{
|
||||||
type Error = ChatItemError;
|
type Error = ChatItemError;
|
||||||
|
|
||||||
@ -86,8 +87,8 @@ impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::StandardMessage, C>
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::backup::testutil::TestContext;
|
|
||||||
use crate::backup::recipient::FullRecipientData;
|
use crate::backup::recipient::FullRecipientData;
|
||||||
|
use crate::backup::testutil::TestContext;
|
||||||
use crate::backup::time::{Duration, Timestamp};
|
use crate::backup::time::{Duration, Timestamp};
|
||||||
|
|
||||||
impl proto::StandardMessage {
|
impl proto::StandardMessage {
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
use crate::backup::chat::{ChatItemError, Reaction};
|
use crate::backup::chat::{ChatItemError, Reaction};
|
||||||
use crate::backup::frame::RecipientId;
|
use crate::backup::frame::RecipientId;
|
||||||
use crate::backup::method::Lookup;
|
use crate::backup::method::LookupPair;
|
||||||
|
use crate::backup::recipient::DestinationKind;
|
||||||
use crate::backup::serialize::{SerializeOrder, UnorderedList};
|
use crate::backup::serialize::{SerializeOrder, UnorderedList};
|
||||||
use crate::backup::sticker::MessageSticker;
|
use crate::backup::sticker::MessageSticker;
|
||||||
use crate::backup::{TryFromWith, TryIntoWith as _};
|
use crate::backup::{TryFromWith, TryIntoWith as _};
|
||||||
@ -20,7 +21,7 @@ pub struct StickerMessage<Recipient> {
|
|||||||
_limit_construction_to_module: (),
|
_limit_construction_to_module: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::StickerMessage, C>
|
impl<R: Clone, C: LookupPair<RecipientId, DestinationKind, R>> TryFromWith<proto::StickerMessage, C>
|
||||||
for StickerMessage<R>
|
for StickerMessage<R>
|
||||||
{
|
{
|
||||||
type Error = ChatItemError;
|
type Error = ChatItemError;
|
||||||
@ -55,9 +56,9 @@ mod test {
|
|||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::backup::testutil::TestContext;
|
|
||||||
use crate::backup::chat::ReactionError;
|
use crate::backup::chat::ReactionError;
|
||||||
use crate::backup::recipient::FullRecipientData;
|
use crate::backup::recipient::FullRecipientData;
|
||||||
|
use crate::backup::testutil::TestContext;
|
||||||
|
|
||||||
impl proto::StickerMessage {
|
impl proto::StickerMessage {
|
||||||
pub(crate) fn test_data() -> Self {
|
pub(crate) fn test_data() -> Self {
|
||||||
|
@ -6,8 +6,8 @@ use crate::backup::call::{GroupCall, IndividualCall};
|
|||||||
use crate::backup::chat::group::GroupChatUpdate;
|
use crate::backup::chat::group::GroupChatUpdate;
|
||||||
use crate::backup::chat::ChatItemError;
|
use crate::backup::chat::ChatItemError;
|
||||||
use crate::backup::frame::RecipientId;
|
use crate::backup::frame::RecipientId;
|
||||||
use crate::backup::method::Lookup;
|
use crate::backup::method::LookupPair;
|
||||||
use crate::backup::recipient::E164;
|
use crate::backup::recipient::{DestinationKind, E164};
|
||||||
use crate::backup::time::Duration;
|
use crate::backup::time::Duration;
|
||||||
use crate::backup::{TryFromWith, TryIntoWith as _};
|
use crate::backup::{TryFromWith, TryIntoWith as _};
|
||||||
use crate::proto::backup as proto;
|
use crate::proto::backup as proto;
|
||||||
@ -49,8 +49,8 @@ pub enum SimpleChatUpdate {
|
|||||||
MessageRequestAccepted,
|
MessageRequestAccepted,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Lookup<RecipientId, R>, R: Clone> TryFromWith<proto::ChatUpdateMessage, C>
|
impl<C: LookupPair<RecipientId, DestinationKind, R>, R: Clone>
|
||||||
for UpdateMessage<R>
|
TryFromWith<proto::ChatUpdateMessage, C> for UpdateMessage<R>
|
||||||
{
|
{
|
||||||
type Error = ChatItemError;
|
type Error = ChatItemError;
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@ use crate::backup::chat::quote::{Quote, QuoteError};
|
|||||||
use crate::backup::chat::{Reaction, ReactionError};
|
use crate::backup::chat::{Reaction, ReactionError};
|
||||||
use crate::backup::file::{MessageAttachment, MessageAttachmentError};
|
use crate::backup::file::{MessageAttachment, MessageAttachmentError};
|
||||||
use crate::backup::frame::RecipientId;
|
use crate::backup::frame::RecipientId;
|
||||||
use crate::backup::method::Lookup;
|
use crate::backup::method::LookupPair;
|
||||||
|
use crate::backup::recipient::DestinationKind;
|
||||||
use crate::backup::serialize::{SerializeOrder, UnorderedList};
|
use crate::backup::serialize::{SerializeOrder, UnorderedList};
|
||||||
use crate::backup::{TryFromWith, TryIntoWith as _};
|
use crate::backup::{TryFromWith, TryIntoWith as _};
|
||||||
use crate::proto::backup as proto;
|
use crate::proto::backup as proto;
|
||||||
@ -39,8 +40,8 @@ pub enum VoiceMessageError {
|
|||||||
Reaction(#[from] ReactionError),
|
Reaction(#[from] ReactionError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Clone, C: Lookup<RecipientId, R>> TryFromWith<proto::StandardMessage, C>
|
impl<R: Clone, C: LookupPair<RecipientId, DestinationKind, R>>
|
||||||
for VoiceMessage<R>
|
TryFromWith<proto::StandardMessage, C> for VoiceMessage<R>
|
||||||
{
|
{
|
||||||
type Error = VoiceMessageError;
|
type Error = VoiceMessageError;
|
||||||
|
|
||||||
@ -95,8 +96,8 @@ mod test {
|
|||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::backup::testutil::TestContext;
|
|
||||||
use crate::backup::recipient::FullRecipientData;
|
use crate::backup::recipient::FullRecipientData;
|
||||||
|
use crate::backup::testutil::TestContext;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn valid_voice_message() {
|
fn valid_voice_message() {
|
||||||
|
@ -99,6 +99,18 @@ pub enum Destination<M: Method + ReferencedTypes> {
|
|||||||
CallLink(M::Value<CallLink>),
|
CallLink(M::Value<CallLink>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DestinationKind {
|
||||||
|
pub fn is_individual(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
DestinationKind::Contact | DestinationKind::Self_ => true,
|
||||||
|
DestinationKind::Group
|
||||||
|
| DestinationKind::DistributionList
|
||||||
|
| DestinationKind::ReleaseNotes
|
||||||
|
| DestinationKind::CallLink => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsRef<DestinationKind> for DestinationKind {
|
impl AsRef<DestinationKind> for DestinationKind {
|
||||||
fn as_ref(&self) -> &DestinationKind {
|
fn as_ref(&self) -> &DestinationKind {
|
||||||
self
|
self
|
||||||
@ -430,17 +442,17 @@ impl<R: Clone, C: LookupPair<RecipientId, DestinationKind, R>>
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|id| {
|
.map(|id| {
|
||||||
let id = RecipientId(id);
|
let id = RecipientId(id);
|
||||||
let (kind, recipient_reference) = context
|
let (&kind, recipient_reference) = context
|
||||||
.lookup_pair(&id)
|
.lookup_pair(&id)
|
||||||
.ok_or(RecipientError::DistributionListMemberUnknown(id))?;
|
.ok_or(RecipientError::DistributionListMemberUnknown(id))?;
|
||||||
match kind {
|
match kind {
|
||||||
DestinationKind::Contact => Ok(recipient_reference.clone()),
|
DestinationKind::Contact => Ok(recipient_reference.clone()),
|
||||||
kind @ (DestinationKind::Group
|
DestinationKind::Group
|
||||||
| DestinationKind::DistributionList
|
| DestinationKind::DistributionList
|
||||||
| DestinationKind::Self_
|
| DestinationKind::Self_
|
||||||
| DestinationKind::ReleaseNotes
|
| DestinationKind::ReleaseNotes
|
||||||
| DestinationKind::CallLink) => {
|
| DestinationKind::CallLink => {
|
||||||
Err(RecipientError::DistributionListMemberWrongKind(id, *kind))
|
Err(RecipientError::DistributionListMemberWrongKind(id, kind))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -8,6 +8,7 @@ use std::sync::Arc;
|
|||||||
use nonzero_ext::nonzero;
|
use nonzero_ext::nonzero;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
use crate::backup::call::CallLink;
|
||||||
use crate::backup::chat::chat_style::{CustomChatColor, CustomColorId};
|
use crate::backup::chat::chat_style::{CustomChatColor, CustomColorId};
|
||||||
use crate::backup::chat::PinOrder;
|
use crate::backup::chat::PinOrder;
|
||||||
use crate::backup::frame::RecipientId;
|
use crate::backup::frame::RecipientId;
|
||||||
@ -40,11 +41,14 @@ static CONTACT_RECIPIENT: Lazy<FullRecipientData> =
|
|||||||
Lazy::new(|| FullRecipientData::new(Destination::Contact(ContactData::from_proto_test_data())));
|
Lazy::new(|| FullRecipientData::new(Destination::Contact(ContactData::from_proto_test_data())));
|
||||||
static GROUP_RECIPIENT: Lazy<FullRecipientData> =
|
static GROUP_RECIPIENT: Lazy<FullRecipientData> =
|
||||||
Lazy::new(|| FullRecipientData::new(Destination::Group(GroupData::from_proto_test_data())));
|
Lazy::new(|| FullRecipientData::new(Destination::Group(GroupData::from_proto_test_data())));
|
||||||
|
static CALL_LINK_RECIPIENT: Lazy<FullRecipientData> =
|
||||||
|
Lazy::new(|| FullRecipientData::new(Destination::CallLink(CallLink::from_proto_test_data())));
|
||||||
|
|
||||||
impl TestContext {
|
impl TestContext {
|
||||||
pub(super) const CONTACT_ID: RecipientId = RecipientId(123456789);
|
pub(super) const CONTACT_ID: RecipientId = RecipientId(123456789);
|
||||||
pub(super) const SELF_ID: RecipientId = RecipientId(1111111111);
|
pub(super) const SELF_ID: RecipientId = RecipientId(1111111111);
|
||||||
pub(super) const GROUP_ID: RecipientId = RecipientId(7000000);
|
pub(super) const GROUP_ID: RecipientId = RecipientId(7000000);
|
||||||
|
pub(super) const CALL_LINK_ID: RecipientId = RecipientId(0xCA77);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LookupPair<RecipientId, DestinationKind, FullRecipientData> for TestContext {
|
impl LookupPair<RecipientId, DestinationKind, FullRecipientData> for TestContext {
|
||||||
@ -56,17 +60,12 @@ impl LookupPair<RecipientId, DestinationKind, FullRecipientData> for TestContext
|
|||||||
Self::CONTACT_ID => Some((&DestinationKind::Contact, &CONTACT_RECIPIENT)),
|
Self::CONTACT_ID => Some((&DestinationKind::Contact, &CONTACT_RECIPIENT)),
|
||||||
Self::SELF_ID => Some((&DestinationKind::Self_, &SELF_RECIPIENT)),
|
Self::SELF_ID => Some((&DestinationKind::Self_, &SELF_RECIPIENT)),
|
||||||
Self::GROUP_ID => Some((&DestinationKind::Group, &GROUP_RECIPIENT)),
|
Self::GROUP_ID => Some((&DestinationKind::Group, &GROUP_RECIPIENT)),
|
||||||
|
Self::CALL_LINK_ID => Some((&DestinationKind::CallLink, &CALL_LINK_RECIPIENT)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lookup<RecipientId, FullRecipientData> for TestContext {
|
|
||||||
fn lookup<'a>(&'a self, key: &'a RecipientId) -> Option<&'a FullRecipientData> {
|
|
||||||
self.lookup_pair(key).map(|(_kind, data)| data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Lookup<PinOrder, FullRecipientData> for TestContext {
|
impl Lookup<PinOrder, FullRecipientData> for TestContext {
|
||||||
fn lookup(&self, key: &PinOrder) -> Option<&FullRecipientData> {
|
fn lookup(&self, key: &PinOrder) -> Option<&FullRecipientData> {
|
||||||
(*key == Self::DUPLICATE_PINNED_ORDER).then_some(&SELF_RECIPIENT)
|
(*key == Self::DUPLICATE_PINNED_ORDER).then_some(&SELF_RECIPIENT)
|
||||||
|
Loading…
Reference in New Issue
Block a user