server: move domain types to a separate file
This commit is contained in:
committed by
nitnelave
parent
e89b1538af
commit
09a0522e2d
@@ -1,223 +1,13 @@
|
||||
use super::error::*;
|
||||
use super::{
|
||||
error::Result,
|
||||
types::{
|
||||
Group, GroupDetails, GroupId, JpegPhoto, User, UserAndGroups, UserColumn, UserId, Uuid,
|
||||
},
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub use super::model::{GroupColumn, UserColumn};
|
||||
|
||||
#[derive(PartialEq, Hash, Eq, Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[serde(try_from = "&str")]
|
||||
pub struct Uuid(String);
|
||||
|
||||
impl Uuid {
|
||||
pub fn from_name_and_date(name: &str, creation_date: &chrono::DateTime<chrono::Utc>) -> Self {
|
||||
Uuid(
|
||||
uuid::Uuid::new_v3(
|
||||
&uuid::Uuid::NAMESPACE_X500,
|
||||
&[name.as_bytes(), creation_date.to_rfc3339().as_bytes()].concat(),
|
||||
)
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn into_string(self) -> String {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::convert::TryFrom<&'a str> for Uuid {
|
||||
type Error = anyhow::Error;
|
||||
fn try_from(s: &'a str) -> anyhow::Result<Self> {
|
||||
Ok(Uuid(uuid::Uuid::parse_str(s)?.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::string::ToString for Uuid {
|
||||
fn to_string(&self) -> String {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl sea_orm::TryGetable for Uuid {
|
||||
fn try_get(
|
||||
res: &sea_orm::QueryResult,
|
||||
pre: &str,
|
||||
col: &str,
|
||||
) -> std::result::Result<Self, sea_orm::TryGetError> {
|
||||
Ok(Uuid(String::try_get(res, pre, col)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_export]
|
||||
macro_rules! uuid {
|
||||
($s:literal) => {
|
||||
<$crate::domain::handler::Uuid as std::convert::TryFrom<_>>::try_from($s).unwrap()
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[serde(from = "String")]
|
||||
pub struct UserId(String);
|
||||
|
||||
impl UserId {
|
||||
pub fn new(user_id: &str) -> Self {
|
||||
Self(user_id.to_lowercase())
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
|
||||
pub fn into_string(self) -> String {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for UserId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for UserId {
|
||||
fn from(s: String) -> Self {
|
||||
Self::new(&s)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct JpegPhoto(#[serde(with = "serde_bytes")] Vec<u8>);
|
||||
|
||||
impl JpegPhoto {
|
||||
pub fn null() -> Self {
|
||||
Self(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JpegPhoto> for sea_orm::Value {
|
||||
fn from(photo: JpegPhoto) -> Self {
|
||||
photo.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JpegPhoto> for sea_orm::Value {
|
||||
fn from(photo: &JpegPhoto) -> Self {
|
||||
photo.0.as_slice().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for JpegPhoto {
|
||||
type Error = anyhow::Error;
|
||||
fn try_from(bytes: &[u8]) -> anyhow::Result<Self> {
|
||||
if bytes.is_empty() {
|
||||
return Ok(JpegPhoto::null());
|
||||
}
|
||||
// Confirm that it's a valid Jpeg, then store only the bytes.
|
||||
image::io::Reader::with_format(std::io::Cursor::new(bytes), image::ImageFormat::Jpeg)
|
||||
.decode()?;
|
||||
Ok(JpegPhoto(bytes.to_vec()))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<u8>> for JpegPhoto {
|
||||
type Error = anyhow::Error;
|
||||
fn try_from(bytes: Vec<u8>) -> anyhow::Result<Self> {
|
||||
if bytes.is_empty() {
|
||||
return Ok(JpegPhoto::null());
|
||||
}
|
||||
// Confirm that it's a valid Jpeg, then store only the bytes.
|
||||
image::io::Reader::with_format(
|
||||
std::io::Cursor::new(bytes.as_slice()),
|
||||
image::ImageFormat::Jpeg,
|
||||
)
|
||||
.decode()?;
|
||||
Ok(JpegPhoto(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for JpegPhoto {
|
||||
type Error = anyhow::Error;
|
||||
fn try_from(string: String) -> anyhow::Result<Self> {
|
||||
// The String format is in base64.
|
||||
Self::try_from(base64::decode(string.as_str())?)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&JpegPhoto> for String {
|
||||
fn from(val: &JpegPhoto) -> Self {
|
||||
base64::encode(&val.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl JpegPhoto {
|
||||
pub fn into_bytes(self) -> Vec<u8> {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn for_tests() -> Self {
|
||||
use image::{ImageOutputFormat, Rgb, RgbImage};
|
||||
let img = RgbImage::from_fn(32, 32, |x, y| {
|
||||
if (x + y) % 2 == 0 {
|
||||
Rgb([0, 0, 0])
|
||||
} else {
|
||||
Rgb([255, 255, 255])
|
||||
}
|
||||
});
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
img.write_to(
|
||||
&mut std::io::Cursor::new(&mut bytes),
|
||||
ImageOutputFormat::Jpeg(0),
|
||||
)
|
||||
.unwrap();
|
||||
Self(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize, sea_orm::FromQueryResult)]
|
||||
pub struct User {
|
||||
pub user_id: UserId,
|
||||
pub email: String,
|
||||
pub display_name: Option<String>,
|
||||
pub first_name: Option<String>,
|
||||
pub last_name: Option<String>,
|
||||
pub avatar: Option<JpegPhoto>,
|
||||
pub creation_date: chrono::DateTime<chrono::Utc>,
|
||||
pub uuid: Uuid,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Default for User {
|
||||
fn default() -> Self {
|
||||
use chrono::TimeZone;
|
||||
let epoch = chrono::Utc.timestamp_opt(0, 0).unwrap();
|
||||
User {
|
||||
user_id: UserId::default(),
|
||||
email: String::new(),
|
||||
display_name: None,
|
||||
first_name: None,
|
||||
last_name: None,
|
||||
avatar: None,
|
||||
creation_date: epoch,
|
||||
uuid: Uuid::from_name_and_date("", &epoch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||
pub struct Group {
|
||||
pub id: GroupId,
|
||||
pub display_name: String,
|
||||
pub creation_date: chrono::DateTime<chrono::Utc>,
|
||||
pub uuid: Uuid,
|
||||
pub users: Vec<UserId>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct BindRequest {
|
||||
pub name: UserId,
|
||||
@@ -282,23 +72,6 @@ pub trait LoginHandler: Clone + Send {
|
||||
async fn bind(&self, request: BindRequest) -> Result<()>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct GroupId(pub i32);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, sea_orm::FromQueryResult)]
|
||||
pub struct GroupDetails {
|
||||
pub group_id: GroupId,
|
||||
pub display_name: String,
|
||||
pub creation_date: chrono::DateTime<chrono::Utc>,
|
||||
pub uuid: Uuid,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct UserAndGroups {
|
||||
pub user: User,
|
||||
pub groups: Option<Vec<GroupDetails>>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait GroupBackendHandler {
|
||||
async fn list_groups(&self, filters: Option<GroupRequestFilter>) -> Result<Vec<Group>>;
|
||||
|
||||
Reference in New Issue
Block a user