use std::fmt;
use grammers_session::types::{PeerAuth, PeerId, PeerInfo, PeerRef};
use grammers_tl_types as tl;
use crate::Client;
#[non_exhaustive]
pub enum Platform {
All,
Android,
Ios,
WindowsPhone,
Other(String),
}
pub struct RestrictionReason {
pub platforms: Vec<Platform>,
pub reason: String,
pub text: String,
}
impl RestrictionReason {
pub fn from_raw(reason: &tl::enums::RestrictionReason) -> Self {
let tl::enums::RestrictionReason::Reason(reason) = reason;
Self {
platforms: reason
.platform
.split('-')
.map(|p| match p {
"all" => Platform::All,
"android" => Platform::Android,
"ios" => Platform::Ios,
"wp" => Platform::WindowsPhone,
o => Platform::Other(o.to_string()),
})
.collect(),
reason: reason.reason.to_string(),
text: reason.text.to_string(),
}
}
}
#[derive(Clone)]
pub struct User {
pub raw: tl::enums::User,
pub(crate) client: Client,
}
impl fmt::Debug for User {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.raw.fmt(f)
}
}
impl User {
pub fn from_raw(client: &Client, user: tl::enums::User) -> Self {
Self {
raw: user,
client: client.clone(),
}
}
pub(crate) fn user(&self) -> Option<&tl::types::User> {
match &self.raw {
tl::enums::User::User(u) => Some(u),
tl::enums::User::Empty(_) => None,
}
}
pub fn status(&self) -> &grammers_tl_types::enums::UserStatus {
self.user()
.and_then(|u| u.status.as_ref())
.unwrap_or(&grammers_tl_types::enums::UserStatus::Empty)
}
pub fn id(&self) -> PeerId {
PeerId::user_unchecked(self.raw.id())
}
pub(crate) fn auth(&self) -> Option<PeerAuth> {
let user = self.user()?;
user.access_hash
.filter(|_| !user.min)
.map(PeerAuth::from_hash)
}
pub async fn to_ref(&self) -> Option<PeerRef> {
let id = self.id();
match self.auth() {
Some(auth) => Some(PeerRef { id, auth }),
None => self.client.0.session.peer_ref(id).await,
}
}
pub fn first_name(&self) -> Option<&str> {
self.user().and_then(|u| u.first_name.as_deref())
}
pub fn last_name(&self) -> Option<&str> {
self.user().and_then(|u| {
u.last_name
.as_deref()
.and_then(|name| if name.is_empty() { None } else { Some(name) })
})
}
pub fn full_name(&self) -> String {
let first_name = self.first_name().unwrap_or_default();
if let Some(last_name) = self.last_name() {
let mut name = String::with_capacity(first_name.len() + 1 + last_name.len());
name.push_str(first_name);
name.push(' ');
name.push_str(last_name);
name
} else {
first_name.to_string()
}
}
pub fn username(&self) -> Option<&str> {
self.user().and_then(|u| u.username.as_deref())
}
pub fn usernames(&self) -> Vec<&str> {
self.user()
.and_then(|u| u.usernames.as_deref())
.map_or(Vec::new(), |usernames| {
usernames
.iter()
.map(|username| match username {
tl::enums::Username::Username(username) => username.username.as_ref(),
})
.collect()
})
}
pub fn phone(&self) -> Option<&str> {
self.user().and_then(|u| u.phone.as_deref())
}
pub fn photo(&self) -> Option<&tl::types::UserProfilePhoto> {
match self.user().and_then(|u| u.photo.as_ref()) {
Some(maybe_photo) => match maybe_photo {
tl::enums::UserProfilePhoto::Empty => None,
tl::enums::UserProfilePhoto::Photo(photo) => Some(photo),
},
None => None,
}
}
pub fn is_self(&self) -> bool {
self.user().map(|u| u.is_self).unwrap_or(false)
}
pub fn contact(&self) -> bool {
self.user().map(|u| u.contact).unwrap_or(false)
}
pub fn mutual_contact(&self) -> bool {
self.user().map(|u| u.mutual_contact).unwrap_or(false)
}
pub fn deleted(&self) -> bool {
self.user().map(|u| u.deleted).unwrap_or(false)
}
pub fn is_bot(&self) -> bool {
self.user().map(|u| u.bot).unwrap_or(false)
}
pub fn bot_privacy(&self) -> bool {
self.user().map(|u| !u.bot_chat_history).unwrap_or(false)
}
pub fn bot_supports_chats(self) -> bool {
self.user().map(|u| u.bot_nochats).unwrap_or(false)
}
pub fn verified(&self) -> bool {
self.user().map(|u| u.verified).unwrap_or(false)
}
pub fn restricted(&self) -> bool {
self.user().map(|u| u.restricted).unwrap_or(false)
}
pub fn bot_inline_geo(&self) -> bool {
self.user().map(|u| u.bot_inline_geo).unwrap_or(false)
}
pub fn support(&self) -> bool {
self.user().map(|u| u.support).unwrap_or(false)
}
pub fn scam(&self) -> bool {
self.user().map(|u| u.scam).unwrap_or(false)
}
pub fn is_premium(&self) -> bool {
self.user().map(|u| u.premium).unwrap_or(false)
}
pub fn fake(&self) -> bool {
self.user().map(|u| u.fake).unwrap_or(false)
}
pub fn restriction_reason(&self) -> Vec<RestrictionReason> {
if let Some(reasons) = self.user().and_then(|u| u.restriction_reason.as_ref()) {
reasons.iter().map(RestrictionReason::from_raw).collect()
} else {
Vec::new()
}
}
pub fn bot_inline_placeholder(&self) -> Option<&str> {
self.user()
.and_then(|u| u.bot_inline_placeholder.as_deref())
}
pub fn lang_code(&self) -> Option<&str> {
self.user().and_then(|u| u.lang_code.as_deref())
}
}
impl From<User> for PeerInfo {
#[inline]
fn from(user: User) -> Self {
<Self as From<&User>>::from(&user)
}
}
impl<'a> From<&'a User> for PeerInfo {
fn from(user: &'a User) -> Self {
<PeerInfo as From<&'a tl::enums::User>>::from(&user.raw)
}
}