247 lines
6.4 KiB
Rust
247 lines
6.4 KiB
Rust
use std::fmt::Display;
|
|
|
|
use chrono::{DateTime, Utc};
|
|
use serde::{Deserialize, Serialize};
|
|
use sqlx::types::{chrono, JsonValue};
|
|
use sqlx::{Error, PgPool, Postgres, Transaction};
|
|
|
|
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
|
pub enum Role {
|
|
Admin,
|
|
User,
|
|
}
|
|
|
|
impl Role {
|
|
pub fn is_admin(&self) -> bool {
|
|
match self {
|
|
Role::Admin => true,
|
|
Role::User => false,
|
|
}
|
|
}
|
|
|
|
pub fn is_user(&self) -> bool {
|
|
match self {
|
|
Role::Admin => false,
|
|
Role::User => true,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for Role {
|
|
fn default() -> Self {
|
|
Role::User
|
|
}
|
|
}
|
|
|
|
impl Display for Role {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Role::Admin => write!(f, "admin"),
|
|
Role::User => write!(f, "user"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Into<Role> for String {
|
|
fn into(self) -> Role {
|
|
match self.as_str() {
|
|
"admin" => Role::Admin,
|
|
"user" => Role::User,
|
|
_ => Role::User,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
|
pub struct Account {
|
|
pub id: String,
|
|
pub username: String,
|
|
pub display_name: Option<String>,
|
|
pub avatar_url: Option<String>,
|
|
pub lang_tag: String,
|
|
pub location: Option<String>,
|
|
pub timezone: Option<String>,
|
|
pub metadata: JsonValue,
|
|
pub wallet: JsonValue,
|
|
pub email: Option<String>,
|
|
pub password: Option<Vec<u8>>,
|
|
pub role: Role,
|
|
pub facebook_id: Option<String>,
|
|
pub google_id: Option<String>,
|
|
pub gamecenter_id: Option<String>,
|
|
pub steam_id: Option<String>,
|
|
pub custom_id: Option<String>,
|
|
pub apple_id: Option<String>,
|
|
pub facebook_instant_game_id: Option<String>,
|
|
pub weixin_id: Option<String>,
|
|
pub douyin_id: Option<String>,
|
|
pub create_time: DateTime<Utc>,
|
|
pub update_time: Option<DateTime<Utc>>,
|
|
pub verify_time: Option<DateTime<Utc>>,
|
|
pub disable_time: Option<DateTime<Utc>>,
|
|
}
|
|
|
|
impl Account {
|
|
pub async fn find_by_apple_id(
|
|
apple_id: &str,
|
|
db_pool: &PgPool,
|
|
) -> Result<Option<Account>, Error> {
|
|
match sqlx::query_as!(
|
|
Account,
|
|
r#"select * from account where apple_id = $1"#,
|
|
apple_id
|
|
)
|
|
.fetch_one(db_pool)
|
|
.await
|
|
{
|
|
Ok(account) => Ok(Some(account)),
|
|
Err(Error::RowNotFound) => Ok(None),
|
|
Err(e) => {
|
|
tracing::error!("find_by_apple_id error: {:?}", e);
|
|
Err(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn find_by_custom_id(
|
|
custom_id: &str,
|
|
db_pool: &PgPool,
|
|
) -> Result<Option<Account>, Error> {
|
|
match sqlx::query_as!(
|
|
Account,
|
|
r#"select * from account where custom_id = $1"#,
|
|
custom_id
|
|
)
|
|
.fetch_one(db_pool)
|
|
.await
|
|
{
|
|
Ok(account) => Ok(Some(account)),
|
|
Err(Error::RowNotFound) => Ok(None),
|
|
Err(e) => {
|
|
tracing::error!("find_by_custom_id error: {:?}", e);
|
|
Err(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn find_by_facebook_id(
|
|
facebook_id: &str,
|
|
db_pool: &PgPool,
|
|
) -> Result<Option<Account>, Error> {
|
|
match sqlx::query_as!(
|
|
Account,
|
|
r#"select * from account where facebook_id = $1"#,
|
|
facebook_id
|
|
)
|
|
.fetch_one(db_pool)
|
|
.await
|
|
{
|
|
Ok(account) => Ok(Some(account)),
|
|
Err(Error::RowNotFound) => Ok(None),
|
|
Err(e) => {
|
|
tracing::error!("find_by_facebook_id error: {:?}", e);
|
|
Err(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn find_by_google_id(
|
|
google_id: &str,
|
|
db_pool: &PgPool,
|
|
) -> Result<Option<Account>, Error> {
|
|
match sqlx::query_as!(
|
|
Account,
|
|
r#"select * from account where google_id = $1"#,
|
|
google_id
|
|
)
|
|
.fetch_one(db_pool)
|
|
.await
|
|
{
|
|
Ok(account) => Ok(Some(account)),
|
|
Err(Error::RowNotFound) => Ok(None),
|
|
Err(e) => {
|
|
tracing::error!("find_by_google_id error: {:?}", e);
|
|
Err(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn save_google_account(
|
|
&self,
|
|
transaction: &mut Transaction<'_, Postgres>,
|
|
) -> Result<Account, Error> {
|
|
sqlx::query_as!(
|
|
Account,
|
|
r#"
|
|
insert into account
|
|
(username, google_id, email, display_name, avatar_url)
|
|
values
|
|
($1, $2, $3, $4, $5) returning *
|
|
"#,
|
|
self.username,
|
|
self.google_id.as_ref().unwrap(),
|
|
self.email.as_ref().unwrap(),
|
|
self.display_name.as_ref().unwrap(),
|
|
self.avatar_url.as_ref().unwrap()
|
|
)
|
|
.fetch_one(&mut **transaction)
|
|
.await
|
|
}
|
|
|
|
pub async fn find_with_password(
|
|
username: String,
|
|
password: String,
|
|
db_pool: &PgPool,
|
|
) -> Result<Option<Account>, Error> {
|
|
match sqlx::query_as!(
|
|
Account,
|
|
r#"
|
|
select * from account where username = $1 and password = $2
|
|
"#,
|
|
username,
|
|
password.as_bytes().to_vec(),
|
|
)
|
|
.fetch_one(db_pool)
|
|
.await
|
|
{
|
|
Ok(account) => Ok(Some(account)),
|
|
Err(Error::RowNotFound) => Ok(None),
|
|
Err(e) => {
|
|
tracing::error!("find_by_google_id error: {:?}", e);
|
|
Err(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn add_account(
|
|
&self,
|
|
transaction: &mut Transaction<'_, Postgres>,
|
|
) -> Result<Option<Account>, Error> {
|
|
match sqlx::query_as!(
|
|
Account,
|
|
r#"
|
|
insert into account
|
|
(username, password, lang_tag, role, wallet, metadata)
|
|
values
|
|
($1, $2, $3, $4, $5, $6) returning *
|
|
"#,
|
|
self.username,
|
|
self.password,
|
|
self.lang_tag,
|
|
self.role.to_string(),
|
|
self.wallet,
|
|
self.metadata
|
|
)
|
|
.fetch_one(&mut **transaction)
|
|
.await
|
|
{
|
|
Ok(account) => Ok(Some(account)),
|
|
Err(Error::RowNotFound) => Ok(None),
|
|
Err(e) => {
|
|
tracing::error!("add_account error: {:?}", e);
|
|
Err(e)
|
|
}
|
|
}
|
|
}
|
|
}
|