// // user.rs // Copyright (C) 2022 veypi // 2022-07-09 03:10 // Distributed under terms of the Apache license. // use std::fmt::Debug; use crate::{models, Error, Result, CONFIG}; use actix_web::{delete, get, head, http, post, web, HttpResponse, Responder}; use base64; use serde::{Deserialize, Serialize}; use tracing::info; #[get("/user/{id}")] pub async fn get(id: web::Path) -> Result { let n = id.into_inner(); if !n.is_empty() { let s = sqlx::query_as::<_, models::User>("select *& from user where id = ?") .bind(n) .fetch_one(CONFIG.db()) .await?; info!("{:#?}", s); Ok(s) } else { Err(Error::Missing("id".to_string())) } } #[get("/user/")] pub async fn list() -> Result { let result = sqlx::query_as::<_, models::User>("select * from user") .fetch_all(CONFIG.db()) .await?; Ok(web::Json(result)) } #[derive(Debug, Deserialize, Serialize)] pub struct LoginOpt { typ: Option, password: String, } #[head("/user/{id}")] pub async fn login(q: web::Query, id: web::Path) -> Result { let id = id.into_inner(); let q = q.into_inner(); let typ = match q.typ { Some(t) => match t.as_str() { "phone" => "phone", "email" => "email", _ => "username", }, _ => "username", }; let p = match base64::decode(q.password.as_bytes()) { Err(_) => return Err(Error::ArgInvalid("password".to_string())), Ok(p) => p, }; let p = match std::str::from_utf8(&p) { Ok(p) => p, Err(_) => return Err(Error::ArgInvalid("password".to_string())), }; let sql = format!("select * from user where {} = ?", typ); let u = sqlx::query_as::<_, models::User>(&sql) .bind(id) .fetch_optional(CONFIG.db()) .await?; let u = match u { Some(u) => u, None => return Err(Error::NotFound("user".to_string())), }; u.check_pass(p)?; let au = sqlx::query_as::<_, models::AppUser>( "select * from app_user where app_id = ? and user_id = ?", ) .bind(&CONFIG.uuid) .bind(&u.id) .fetch_optional(CONFIG.db()) .await?; let i: i64 = match au { Some(au) => match au.status { models::AUStatus::OK => 0, models::AUStatus::Deny => { return Err(Error::BusinessException("apply denied".to_string())) } models::AUStatus::Disabled => { return Err(Error::BusinessException("login disabled".to_string())) } models::AUStatus::Applying => { return Err(Error::BusinessException("applying".to_string())) } }, None => { let app = sqlx::query_as::<_, models::App>("select * from app where id = ?") .bind(CONFIG.uuid.clone()) .fetch_one(CONFIG.db()) .await?; info!("{:#?}", u); let s = match app.join_method { models::app::AppJoin::Disabled => { return Err(Error::BusinessException( "this app diabled login".to_string(), )) } models::app::AppJoin::Auto => models::AUStatus::OK, models::app::AppJoin::Applying => models::AUStatus::Applying, }; sqlx::query( r#" insert into app_user (app_id,user_id,status) values ( ?, ?, ? ) "#, ) .bind(&app.id) .bind(&u.id) .bind(&s) .execute(CONFIG.db()) .await?; match s { models::AUStatus::OK => 0, _ => 1, } } }; if i == 0 { Ok(HttpResponse::build(http::StatusCode::OK) .insert_header(("auth_token", u.token().to_string()?)) .body("".to_string())) } else { Ok(HttpResponse::build(http::StatusCode::OK) .insert_header(("data", "applying")) .body("".to_string())) } } #[derive(Debug, Deserialize, Serialize)] pub struct RegisterOpt { username: String, password: String, } #[post("/user/")] pub async fn register(q: web::Json) -> Result { let q = q.into_inner(); // let mut tx = dbtx().await; println!("{:#?}", q); let u: Option = sqlx::query_as::<_, models::User>("select * from user where username = ?") .bind(q.username.clone()) .fetch_optional(CONFIG.db()) .await?; let u: models::User = match u { Some(_) => return Err(Error::ArgDuplicated(format!("username: {}", q.username))), None => { let mut u = models::User::default(); u.username = q.username.clone(); let p = match base64::decode(q.password.as_bytes()) { Err(_) => return Err(Error::ArgInvalid("password".to_string())), Ok(p) => p, }; let p = match std::str::from_utf8(&p) { Ok(p) => p, Err(_) => return Err(Error::ArgInvalid("password".to_string())), }; info!("{}", p); u.update_pass(&p)?; u } }; let oa: models::App = sqlx::query_as::<_, models::App>("select * from app where id = ?") .bind(CONFIG.uuid.clone()) .fetch_one(CONFIG.db()) .await?; let mut au = models::AppUser::new(); au.app_id = oa.id; au.user_id = u.id.clone(); match oa.join_method { models::app::AppJoin::Disabled => return Err(Error::AppDisabledRegister), models::app::AppJoin::Auto => au.status = models::app::AUStatus::OK, models::app::AppJoin::Applying => au.status = models::app::AUStatus::Applying, } let mut c = CONFIG.db().begin().await?; sqlx::query!( r#" insert into user (id,username,real_code,check_code) values ( ?, ?, ?, ?) "#, u.id, u.username, u.real_code, u.check_code, ) .execute(&mut c) .await?; sqlx::query!( r#" insert into app_user ( app_id, user_id, status) values (?, ?, ? ) "#, au.app_id, au.user_id, au.status, ) .execute(&mut c) .await?; c.commit().await?; Ok("ok".to_string()) } #[delete("/user/")] pub async fn delete() -> impl Responder { "" }