use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Value;
use crate::utils::error::Error;
fn to_md5(input: &str) -> String {
let hash = md5::compute(input);
format!("{:x}", hash)
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct LoginData {
#[serde(rename = "nameOrEmail")]
pub username: String,
#[serde(rename = "userPassword")]
pub password: String,
#[serde(rename = "mfaCode")]
pub mfa_code: Option<String>,
}
impl LoginData {
pub fn new(username: &str, password: &str, mfa_code: Option<String>) -> Self {
LoginData {
username: username.to_string(),
password: to_md5(password),
mfa_code,
}
}
pub fn from_value(value: &Value) -> Result<Self, Error> {
serde_json::from_value(value.clone())
.map_err(|e| Error::Parse(format!("Failed to parse LoginData: {}", e)))
}
pub fn to_value(&self) -> Result<Value, Error> {
serde_json::to_value(self)
.map_err(|e| Error::Parse(format!("Failed to serialize LoginData: {}", e)))
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[allow(non_snake_case)]
#[derive(Default)]
pub struct PreRegisterInfo {
#[serde(rename = "userName")]
pub username: String,
#[serde(rename = "userPhone")]
pub phone: String,
pub invitecode: Option<String>,
pub captcha: String,
}
impl PreRegisterInfo {
pub fn from_value(data: &Value) -> Result<Self, Error> {
serde_json::from_value(data.clone())
.map_err(|e| Error::Parse(format!("Failed to parse PreRegisterInfo: {}", e)))
}
pub fn to_value(&self) -> Result<Value, Error> {
serde_json::to_value(self)
.map_err(|e| Error::Parse(format!("Failed to serialize PreRegisterInfo: {}", e)))
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[allow(non_snake_case)]
pub struct RegisterInfo {
#[serde(rename = "userAppRole")]
pub role: String,
#[serde(rename = "userPassword", serialize_with = "serialize_md5")]
pub passwd: String,
#[serde(rename = "userId")]
pub user_id: String,
pub r: Option<String>,
}
impl RegisterInfo {
pub fn from_value(data: &Value) -> Result<Self, Error> {
serde_json::from_value(data.clone())
.map_err(|e| Error::Parse(format!("Failed to parse RegisterInfo: {}", e)))
}
}
impl Default for RegisterInfo {
fn default() -> Self {
Self {
role: "0".to_string(),
passwd: String::new(),
user_id: String::new(),
r: None,
}
}
}
fn serialize_md5<S>(passwd: &str, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let hash = md5::compute(passwd.as_bytes());
serializer.serialize_str(&format!("{:x}", hash))
}
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct FileInfo {
pub filename: String,
pub url: String,
}
impl FileInfo {
pub fn from_value(data: &Value) -> Result<Self, Error> {
serde_json::from_value(data.clone())
.map_err(|e| Error::Parse(format!("Failed to parse FileInfo: {}", e)))
}
}
impl std::fmt::Display for FileInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"FileInfo{{filename={}, url={}}}",
self.filename, self.url
)
}
}
#[derive(Clone, Debug, Default)]
pub struct UploadResult {
pub errs: Vec<String>,
pub success: Vec<FileInfo>,
}
impl UploadResult {
pub fn from_value(data: &Value) -> Result<Self, Error> {
let errs = data["errFiles"]
.as_array()
.unwrap_or(&vec![])
.iter()
.filter_map(|v| v.as_str().map(|s| s.to_string()))
.collect();
let success = if let Some(succ_map) = data["succMap"].as_object() {
succ_map
.iter()
.map(|(filename, url)| FileInfo {
filename: filename.clone(),
url: url.as_str().unwrap_or("").to_string(),
})
.collect()
} else {
vec![]
};
Ok(UploadResult { errs, success })
}
}
impl Serialize for UploadResult {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(2))?;
map.serialize_entry("errFiles", &self.errs)?;
let succ_map: std::collections::HashMap<String, String> = self
.success
.iter()
.map(|f| (f.filename.clone(), f.url.clone()))
.collect();
map.serialize_entry("succMap", &succ_map)?;
map.end()
}
}
impl<'de> Deserialize<'de> for UploadResult {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct UploadResultHelper {
#[serde(rename = "errFiles")]
errs: Vec<String>,
#[serde(rename = "succMap")]
succ_map: std::collections::HashMap<String, String>,
}
let helper = UploadResultHelper::deserialize(deserializer)?;
let success = helper
.succ_map
.into_iter()
.map(|(filename, url)| FileInfo { filename, url })
.collect();
Ok(UploadResult {
errs: helper.errs,
success,
})
}
}
impl std::fmt::Display for UploadResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let errs_str = self.errs.join(",");
write!(
f,
"UploadResult{{ errFiles={}, succFiles={:?} }}",
errs_str, self.success
)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[allow(non_snake_case)]
#[derive(Default)]
pub struct UserLite {
#[serde(rename = "userNickname")]
pub user_nickname: String,
#[serde(rename = "userName")]
pub user_name: String,
}
impl UserLite {
pub fn from_value(data: &Value) -> Result<Self, Error> {
serde_json::from_value(data.clone())
.map_err(|e| Error::Parse(format!("Failed to parse UserLite: {}", e)))
}
}
impl std::fmt::Display for UserLite {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"UserLite{{userNickname: {}, userName: {}}}",
self.user_nickname, self.user_name
)
}
}
use chrono::{DateTime, Utc};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[allow(non_snake_case)]
#[derive(Default)]
pub struct UserVipInfo {
pub joint_vip: bool,
pub color: String,
pub underline: bool,
pub metal: bool,
pub auto_checkin: u32,
pub bold: bool,
pub o_id: String,
pub state: bool,
pub user_id: String,
pub lv_code: String,
pub expires_at: u64,
pub created_at: u64,
pub updated_at: u64,
}
impl UserVipInfo {
pub fn is_vip(&self) -> bool {
self.state
}
pub fn expires_date(&self) -> DateTime<Utc> {
DateTime::from_timestamp_millis(self.expires_at as i64).unwrap_or_default()
}
pub fn created_date(&self) -> DateTime<Utc> {
DateTime::from_timestamp_millis(self.created_at as i64).unwrap_or_default()
}
pub fn updated_date(&self) -> DateTime<Utc> {
DateTime::from_timestamp_millis(self.updated_at as i64).unwrap_or_default()
}
pub fn vip_name(&self) -> String {
self.lv_code
.replace("_YEAR", "(包年)")
.replace("_MONTH", "(包月)")
}
pub fn from_value(data: &Value) -> Result<Self, Error> {
let joint_vip = data["jointVip"].as_bool().unwrap_or(false);
let color = data["color"].as_str().unwrap_or("").to_string();
let underline = data["underline"].as_bool().unwrap_or(false);
let metal = data["metal"].as_bool().unwrap_or(false);
let auto_checkin = data["autoCheckin"].as_u64().unwrap_or(0) as u32;
let bold = data["bold"].as_bool().unwrap_or(false);
let o_id = data["oId"].as_str().unwrap_or("").to_string();
let state = data["state"].as_i64().unwrap_or(0) == 1;
let user_id = data["userId"].as_str().unwrap_or("").to_string();
let lv_code = data["lvCode"].as_str().unwrap_or("").to_string();
let expires_at = data["expiresAt"].as_u64().unwrap_or(0);
let created_at = data["createdAt"].as_u64().unwrap_or(0);
let updated_at = data["updatedAt"].as_u64().unwrap_or(0);
Ok(UserVipInfo {
joint_vip,
color,
underline,
metal,
auto_checkin,
bold,
o_id,
state,
user_id,
lv_code,
expires_at,
created_at,
updated_at,
})
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ReportDataType {
Article,
Comment,
User,
Chatroom,
}
impl From<u8> for ReportDataType {
fn from(value: u8) -> Self {
match value {
0 => Self::Article,
1 => Self::Comment,
2 => Self::User,
_ => Self::Chatroom,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ReportType {
Advertise,
Porn,
Violate,
Infringement,
Attacks,
Impersonate,
AdvertisingAccount,
LeakPrivacy,
Other,
}
impl From<u8> for ReportType {
fn from(value: u8) -> Self {
match value {
0 => Self::Advertise,
1 => Self::Porn,
2 => Self::Violate,
3 => Self::Infringement,
4 => Self::Attacks,
5 => Self::Impersonate,
6 => Self::AdvertisingAccount,
7 => Self::LeakPrivacy,
_ => Self::Other,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[allow(non_snake_case)]
pub struct Report {
#[serde(rename = "reportDataId")]
pub report_data_id: String,
#[serde(rename = "reportDataType")]
pub report_data_type: ReportDataType,
#[serde(rename = "reportType")]
pub report_type: ReportType,
#[serde(rename = "reportMemo")]
pub report_memo: String,
}
impl Report {
pub fn from_value(data: &Value) -> Result<Self, Error> {
let report_data_id = data["reportDataId"].as_str().unwrap_or("").to_string();
let report_data_type =
ReportDataType::from(data["reportDataType"].as_u64().unwrap_or(3) as u8);
let report_type = ReportType::from(data["reportType"].as_u64().unwrap_or(0) as u8);
let report_memo = data["reportMemo"].as_str().unwrap_or("").to_string();
Ok(Report {
report_data_id,
report_data_type,
report_type,
report_memo,
})
}
}
impl Default for Report {
fn default() -> Self {
Self {
report_data_id: String::new(),
report_data_type: ReportDataType::Chatroom,
report_type: ReportType::Advertise,
report_memo: String::new(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[allow(non_snake_case)]
#[derive(Default)]
pub struct Log {
pub key1: String,
pub key2: String,
pub data: String,
#[serde(rename = "public")]
pub is_public: bool,
pub key3: String,
pub o_id: String,
#[serde(rename = "type")]
pub type_: String,
}
impl Log {
pub fn from_value(data: &Value) -> Result<Self, Error> {
serde_json::from_value(data.clone())
.map_err(|e| Error::Parse(format!("Failed to parse Log: {}", e)))
}
}