use super::{Filter, FilterResult};
use crate::{types::User as UserType, Request};
use std::{borrow::Cow, convert::Infallible};
#[derive(Debug, Clone)]
pub struct User {
usernames: Vec<Cow<'static, str>>,
first_names: Vec<Cow<'static, str>>,
last_names: Vec<Cow<'static, str>>,
language_codes: Vec<Cow<'static, str>>,
ids: Vec<i64>,
}
impl User {
pub fn new<T, I1, C, I2, S, I3, E, I4, I5>(
usernames: I1,
first_names: I2,
last_names: I3,
language_codes: I4,
ids: I5,
) -> Self
where
T: Into<Cow<'static, str>>,
I1: IntoIterator<Item = T>,
C: Into<Cow<'static, str>>,
I2: IntoIterator<Item = C>,
S: Into<Cow<'static, str>>,
I3: IntoIterator<Item = S>,
E: Into<Cow<'static, str>>,
I4: IntoIterator<Item = E>,
I5: IntoIterator<Item = i64>,
{
Self {
usernames: usernames.into_iter().map(Into::into).collect(),
first_names: first_names.into_iter().map(Into::into).collect(),
last_names: last_names.into_iter().map(Into::into).collect(),
language_codes: language_codes.into_iter().map(Into::into).collect(),
ids: ids.into_iter().collect(),
}
}
#[inline]
#[must_use]
pub fn username(val: impl Into<Cow<'static, str>>) -> Self {
Self::builder().username(val).build()
}
#[inline]
#[must_use]
pub fn usernames<T, I>(val: I) -> Self
where
T: Into<Cow<'static, str>>,
I: IntoIterator<Item = T>,
{
Self::builder().usernames(val).build()
}
#[inline]
#[must_use]
pub fn first_name(val: impl Into<Cow<'static, str>>) -> Self {
Self::builder().first_name(val).build()
}
#[inline]
#[must_use]
pub fn first_names<T, I>(val: I) -> Self
where
T: Into<Cow<'static, str>>,
I: IntoIterator<Item = T>,
{
Self::builder().first_names(val).build()
}
#[inline]
#[must_use]
pub fn last_name(val: impl Into<Cow<'static, str>>) -> Self {
Self::builder().last_name(val).build()
}
#[inline]
#[must_use]
pub fn last_names<T, I>(val: I) -> Self
where
T: Into<Cow<'static, str>>,
I: IntoIterator<Item = T>,
{
Self::builder().last_names(val).build()
}
#[inline]
#[must_use]
pub fn language_code(val: impl Into<Cow<'static, str>>) -> Self {
Self::builder().language_code(val).build()
}
#[inline]
#[must_use]
pub fn language_codes<T, I>(val: I) -> Self
where
T: Into<Cow<'static, str>>,
I: IntoIterator<Item = T>,
{
Self::builder().language_codes(val).build()
}
#[inline]
#[must_use]
pub fn id(val: i64) -> Self {
Self::builder().id(val).build()
}
#[inline]
#[must_use]
pub fn ids(val: impl IntoIterator<Item = i64>) -> Self {
Self::builder().ids(val).build()
}
#[inline]
#[must_use]
pub fn builder() -> Builder {
Builder::default()
}
}
#[derive(Debug, Default, Clone)]
pub struct Builder {
usernames: Vec<Cow<'static, str>>,
first_names: Vec<Cow<'static, str>>,
last_names: Vec<Cow<'static, str>>,
language_codes: Vec<Cow<'static, str>>,
ids: Vec<i64>,
}
impl Builder {
#[must_use]
pub fn username(self, val: impl Into<Cow<'static, str>>) -> Self {
Self {
usernames: self.usernames.into_iter().chain(Some(val.into())).collect(),
..self
}
}
#[must_use]
pub fn usernames<T, I>(self, val: I) -> Self
where
T: Into<Cow<'static, str>>,
I: IntoIterator<Item = T>,
{
Self {
usernames: self
.usernames
.into_iter()
.chain(val.into_iter().map(Into::into))
.collect(),
..self
}
}
#[must_use]
pub fn first_name(self, val: impl Into<Cow<'static, str>>) -> Self {
Self {
first_names: self
.first_names
.into_iter()
.chain(Some(val.into()))
.collect(),
..self
}
}
#[must_use]
pub fn first_names<T, I>(self, val: I) -> Self
where
T: Into<Cow<'static, str>>,
I: IntoIterator<Item = T>,
{
Self {
first_names: self
.first_names
.into_iter()
.chain(val.into_iter().map(Into::into))
.collect(),
..self
}
}
#[must_use]
pub fn last_name(self, val: impl Into<Cow<'static, str>>) -> Self {
Self {
last_names: self
.last_names
.into_iter()
.chain(Some(val.into()))
.collect(),
..self
}
}
#[must_use]
pub fn last_names<T, I>(self, val: I) -> Self
where
T: Into<Cow<'static, str>>,
I: IntoIterator<Item = T>,
{
Self {
last_names: self
.last_names
.into_iter()
.chain(val.into_iter().map(Into::into))
.collect(),
..self
}
}
#[must_use]
pub fn language_code(self, val: impl Into<Cow<'static, str>>) -> Self {
Self {
language_codes: self
.language_codes
.into_iter()
.chain(Some(val.into()))
.collect(),
..self
}
}
#[must_use]
pub fn language_codes<T, I>(self, val: I) -> Self
where
T: Into<Cow<'static, str>>,
I: IntoIterator<Item = T>,
{
Self {
language_codes: self
.language_codes
.into_iter()
.chain(val.into_iter().map(Into::into))
.collect(),
..self
}
}
#[must_use]
pub fn id(self, val: i64) -> Self {
Self {
ids: self.ids.into_iter().chain(Some(val)).collect(),
..self
}
}
#[must_use]
pub fn ids(self, val: impl IntoIterator<Item = i64>) -> Self {
Self {
ids: self.ids.into_iter().chain(val).collect(),
..self
}
}
#[inline]
#[must_use]
pub fn build(self) -> User {
User::new(
self.usernames,
self.first_names,
self.last_names,
self.language_codes,
self.ids,
)
}
}
impl User {
#[must_use]
pub fn validate_username(&self, username: &str) -> bool {
self.usernames
.iter()
.any(|allowed_username| allowed_username.as_ref() == username)
}
#[must_use]
pub fn validate_first_name(&self, first_name: &str) -> bool {
self.first_names
.iter()
.any(|allowed_first_name| allowed_first_name.as_ref() == first_name)
}
#[must_use]
pub fn validate_last_name(&self, last_name: &str) -> bool {
self.last_names
.iter()
.any(|allowed_last_name| allowed_last_name.as_ref() == last_name)
}
#[must_use]
pub fn validate_language_code(&self, language_code: &str) -> bool {
self.language_codes
.iter()
.any(|allowed_language_code| allowed_language_code.as_ref() == language_code)
}
#[must_use]
pub fn validate_id(&self, id: i64) -> bool {
self.ids.contains(&id)
}
#[must_use]
pub fn validate(&self, user: &UserType) -> bool {
user.username
.as_deref()
.is_some_and(|username| self.validate_username(username))
|| self.validate_id(user.id)
|| self.validate_first_name(&user.first_name)
|| user
.last_name
.as_deref()
.is_some_and(|last_name| self.validate_last_name(last_name))
|| user
.language_code
.as_deref()
.is_some_and(|language_code| self.validate_language_code(language_code))
}
}
impl<Client> Filter<Client> for User
where
Client: Send + Sync + 'static,
{
type Error = Infallible;
async fn check(&mut self, request: &mut Request<Client>) -> FilterResult<Self::Error> {
Ok(match request.update.from() {
Some(user) => self.validate(user),
None => false,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_username() {
let user = User::username("test");
assert!(user.validate_username("test"));
assert!(!user.validate_username("test2"));
let user = User::usernames(["test", "test2"]);
assert!(user.validate_username("test"));
assert!(user.validate_username("test2"));
}
#[test]
fn test_validate_first_name() {
let user = User::first_name("test");
assert!(user.validate_first_name("test"));
assert!(!user.validate_first_name("test2"));
let user = User::first_names(["test", "test2"]);
assert!(user.validate_first_name("test"));
assert!(user.validate_first_name("test2"));
}
#[test]
fn test_validate_last_name() {
let user = User::last_name("test");
assert!(user.validate_last_name("test"));
assert!(!user.validate_last_name("test2"));
let user = User::last_names(["test", "test2"]);
assert!(user.validate_last_name("test"));
assert!(user.validate_last_name("test2"));
}
#[test]
fn test_validate_language_code() {
let user = User::language_code("test");
assert!(user.validate_language_code("test"));
assert!(!user.validate_language_code("test2"));
let user = User::language_codes(["test", "test2"]);
assert!(user.validate_language_code("test"));
assert!(user.validate_language_code("test2"));
}
#[test]
fn test_validate_id() {
let user = User::id(1);
assert!(user.validate_id(1));
assert!(!user.validate_id(2));
let user = User::ids([1, 2]);
assert!(user.validate_id(1));
assert!(user.validate_id(2));
}
}