add seaorm in oab

master
veypi 1 year ago
parent 5d71525ce7
commit bd03910ab8

2181
oab/Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -41,3 +41,4 @@ uuid = { version = "1.1", features = ["v3","v4", "fast-rng", "macro-diagnostics"
serde_repr = "0.1.8"
proc = {path="proc"}

@ -9,3 +9,9 @@ run:
@cargo run
init:
@cargo run -- init
sqlx:
@sqlx migrate run
entity:
@sea-orm-cli generate entity --database-url mysql://root:123456@localhost:3306/test -o ./src/models/entity/ --with-serde both --model-extra-derives Default,sqlx::FromRow --serde-skip-hidden-column --date-time-crate chrono

@ -17,12 +17,12 @@ CREATE TABLE IF NOT EXISTS `user`
`email` varchar(255) UNIQUE,
`phone` varchar(255) UNIQUE,
`icon` varchar(255),
`real_code` varchar(32),
`check_code` binary(48),
`_real_code` varchar(32),
`_check_code` binary(48),
`status` int NOT NULL COMMENT '状态0ok1disabled' DEFAULT 0,
`used` int NOT NULL DEFAULT 0,
`space` int DEFAULT 300,
`space` int NOT NULL DEFAULT 300,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@ -124,7 +124,7 @@ CREATE TABLE IF NOT EXISTS `access`
`role_id` varchar(32) NULL DEFAULT NULL,
`user_id` varchar(32) NULL DEFAULT NULL,
`rid` varchar(32) DEFAULT NULL COMMENT '资源子id',
`level` int DEFAULT 0,
`level` int NOT NULL DEFAULT 0,
-- PRIMARY KEY (`app_id`,`name`, `role_id`, `user_id`) USING BTREE,
PRIMARY KEY (`id`),

@ -9,7 +9,10 @@ use actix_web::{delete, get, post, web, Responder};
use proc::access_read;
use serde::{Deserialize, Serialize};
use crate::{models, Error, Result, CONFIG};
use crate::{
models::{self, app},
Error, Result, CONFIG,
};
use chrono::NaiveDateTime;
#[get("/app/{id}")]
@ -17,9 +20,9 @@ use chrono::NaiveDateTime;
pub async fn get(id: web::Path<String>) -> Result<impl Responder> {
let n = id.into_inner();
if !n.is_empty() {
let s = sqlx::query_as::<_, models::App>("select * from app where id = ?")
let s = sqlx::query_as::<_, app::Model>("select * from app where id = ?")
.bind(n)
.fetch_one(CONFIG.db())
.fetch_one(CONFIG.sqlx())
.await?;
Ok(web::Json(s))
} else {
@ -53,7 +56,7 @@ pub async fn list() -> Result<impl Responder> {
let result = sqlx::query_as::<_, App>(
"select app.id,app.created, app.updated, app.icon, app.name, app.des, app.user_count, app.hide,app.join_method, app.role_id, app.redirect, app.status, app_user.status as u_status from app left join app_user on app_user.user_id = ? && app_user.app_id = app.id",
).bind(_auth_token.id)
.fetch_all(CONFIG.db())
.fetch_all(CONFIG.sqlx())
.await?;
Ok(web::Json(result))

@ -10,7 +10,10 @@ use proc::access_read;
use serde::{Deserialize, Serialize};
use tracing::info;
use crate::{models, Error, Result, CONFIG};
use crate::{
models::{self, app_user},
Error, Result, CONFIG,
};
#[get("/app/{aid}/user/{uid}")]
#[access_read("app")]
@ -27,12 +30,12 @@ pub async fn get(params: web::Path<(String, String)>) -> Result<impl Responder>
if uid.is_empty() && aid.is_empty() {
Err(Error::Missing("uid or aid".to_string()))
} else {
let s = sqlx::query_as::<_, models::AppUser>(
let s = sqlx::query_as::<_, app_user::Model>(
"select * from app_user where app_id = ? and user_id = ?",
)
.bind(aid)
.bind(uid)
.fetch_all(CONFIG.db())
.fetch_all(CONFIG.sqlx())
.await?;
Ok(web::Json(s))
}

@ -7,37 +7,27 @@
use std::fmt::Debug;
use crate::{models, Error, Result, CONFIG};
use crate::{
models::{self, access, app, app_user, user, UserPlugin},
AppState, Error, Result, CONFIG,
};
use actix_web::{delete, get, head, http, post, web, HttpResponse, Responder};
use base64;
use proc::access_read;
use rand::Rng;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
use serde::{Deserialize, Serialize};
use tracing::info;
#[get("/user/{id}")]
#[access_read("user", id = "&id.clone()")]
pub async fn get(id: web::Path<String>) -> Result<impl Responder> {
pub async fn get(id: web::Path<String>, data: web::Data<AppState>) -> Result<impl Responder> {
let n = id.into_inner();
let db = &data.db;
if !n.is_empty() {
let s = sqlx::query!(
"select id,updated,created,username,nickname,email,icon,status, used, space from user where id = ?",n
).map(|row| models::User {
id: row.id,
created: row.created,
updated: row.updated,
username: row.username,
nickname: row.nickname,
email: row.email,
status: row.status,
used: row.used,
space: row.space.unwrap_or(0),
icon: row.icon,
..Default::default()
})
.fetch_one(CONFIG.db())
.await?;
Ok(web::Json(s))
let d: Option<models::entity::user::Model> =
models::entity::user::Entity::find_by_id(n).one(db).await?;
Ok(web::Json(d))
} else {
Err(Error::Missing("id".to_string()))
}
@ -49,7 +39,7 @@ pub async fn list() -> Result<impl Responder> {
let result = sqlx::query!(
"select id,updated,created,username,nickname,email,icon,status, used, space from user",
)
.map(|row| models::User {
.map(|row| models::user::Model {
id: row.id,
created: row.created,
updated: row.updated,
@ -58,11 +48,11 @@ pub async fn list() -> Result<impl Responder> {
email: row.email,
status: row.status,
used: row.used,
space: row.space.unwrap_or(0),
space: row.space,
icon: row.icon,
..Default::default()
})
.fetch_all(CONFIG.db())
.fetch_all(CONFIG.sqlx())
.await?;
Ok(web::Json(result))
}
@ -74,16 +64,21 @@ pub struct LoginOpt {
}
#[head("/user/{id}")]
pub async fn login(q: web::Query<LoginOpt>, id: web::Path<String>) -> Result<HttpResponse> {
pub async fn login(
q: web::Query<LoginOpt>,
id: web::Path<String>,
data: web::Data<AppState>,
) -> Result<HttpResponse> {
let db = &data.db;
let id = id.into_inner();
let q = q.into_inner();
let typ = match q.typ {
let filter = match q.typ {
Some(t) => match t.as_str() {
"phone" => "phone",
"email" => "email",
_ => "username",
"phone" => user::Column::Phone.eq(id),
"email" => user::Column::Email.eq(id),
_ => user::Column::Username.eq(id),
},
_ => "username",
_ => user::Column::Username.eq(id),
};
let p = match base64::decode(q.password.as_bytes()) {
Err(_) => return Err(Error::ArgInvalid("password".to_string())),
@ -93,26 +88,27 @@ pub async fn login(q: web::Query<LoginOpt>, id: web::Path<String>) -> Result<Htt
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: Option<user::Model> = models::user::Entity::find().filter(filter).one(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())
let au: Option<app_user::Model> = app_user::Entity::find()
.filter(app_user::Column::AppId.eq(&CONFIG.uuid))
.filter(app_user::Column::UserId.eq(&u.id))
.one(db)
.await?;
// 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.sqlx())
// .await?;
let i: i64 = match au {
Some(au) => match au.status {
Some(au) => match au.status.into() {
models::AUStatus::OK => 0,
models::AUStatus::Deny => {
return Err(Error::BusinessException("apply denied".to_string()))
@ -125,19 +121,18 @@ pub async fn login(q: web::Query<LoginOpt>, id: web::Path<String>) -> Result<Htt
}
},
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 => {
let app_obj: app::Model = app::Entity::find_by_id(CONFIG.uuid.clone())
.one(db)
.await?
.unwrap();
let s = match app_obj.join_method.into() {
models::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,
models::AppJoin::Auto => models::AUStatus::OK,
models::AppJoin::Applying => models::AUStatus::Applying,
};
sqlx::query(
r#"
@ -145,10 +140,10 @@ insert into app_user (app_id,user_id,status)
values ( ?, ?, ? )
"#,
)
.bind(&app.id)
.bind(&app_obj.id)
.bind(&u.id)
.bind(&s)
.execute(CONFIG.db())
.execute(CONFIG.sqlx())
.await?;
match s {
models::AUStatus::OK => 0,
@ -157,12 +152,13 @@ values ( ?, ?, ? )
}
};
if i == 0 {
let result = sqlx::query_as::<_, models::AccessCore>(
// let result: Vec<models::access::Model> = access::Entity::find().all(db).await?;
let result = sqlx::query_as::<_, access::Model>(
"select access.name,access.rid,access.level from access, user_role, role WHERE user_role.user_id = ? && access.role_id=user_role.role_id && role.id=user_role.role_id && role.app_id = ?",
)
.bind(&u.id)
.bind(CONFIG.uuid.clone())
.fetch_all(CONFIG.db())
.fetch_all(CONFIG.sqlx())
.await?;
Ok(HttpResponse::build(http::StatusCode::OK)
.insert_header(("auth_token", u.token(result).to_string()?))
@ -185,15 +181,15 @@ pub async fn register(q: web::Json<RegisterOpt>) -> Result<String> {
let q = q.into_inner();
// let mut tx = dbtx().await;
info!("{:#?}", q);
let u: Option<models::User> =
sqlx::query_as::<_, models::User>("select * from user where username = ?")
let u: Option<models::user::Model> =
sqlx::query_as::<_, models::user::Model>("select * from user where username = ?")
.bind(q.username.clone())
.fetch_optional(CONFIG.db())
.fetch_optional(CONFIG.sqlx())
.await?;
let u: models::User = match u {
let u: models::user::Model = match u {
Some(_) => return Err(Error::ArgDuplicated(format!("username: {}", q.username))),
None => {
let mut u = models::User::default();
let mut u = models::user::Model::default();
u.username = q.username.clone();
u.id = uuid::Uuid::new_v4().to_string().replace("-", "");
let p = match base64::decode(q.password.as_bytes()) {
@ -212,26 +208,26 @@ pub async fn register(q: web::Json<RegisterOpt>) -> Result<String> {
u
}
};
let oa: models::App = sqlx::query_as::<_, models::App>("select * from app where id = ?")
let oa: app::Model = sqlx::query_as::<_, app::Model>("select * from app where id = ?")
.bind(CONFIG.uuid.clone())
.fetch_one(CONFIG.db())
.fetch_one(CONFIG.sqlx())
.await?;
let mut au = models::AppUser::new();
let mut au = app_user::Model::default();
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;
match oa.join_method.into() {
models::AppJoin::Disabled => return Err(Error::AppDisabledRegister),
models::AppJoin::Auto => {
au.status = models::AUStatus::OK as i32;
}
models::app::AppJoin::Applying => au.status = models::app::AUStatus::Applying,
models::AppJoin::Applying => au.status = models::AUStatus::Applying as i32,
}
let mut c = CONFIG.db().begin().await?;
let mut c = CONFIG.sqlx().begin().await?;
// 创建用户
sqlx::query!(
r#"
insert into user (id,username,real_code,check_code,icon)
insert into user (id,username,_real_code,_check_code,icon)
values ( ?, ?, ?, ?, ?)
"#,
u.id,
@ -256,8 +252,8 @@ values ( ?, ?, ?, ?, ?)
.execute(&mut c)
.await?;
if oa.role_id.is_some() {
match au.status {
models::app::AUStatus::OK => {
match au.status.into() {
models::AUStatus::OK => {
sqlx::query!(
r#"
insert into user_role (user_id, role_id)

@ -11,12 +11,16 @@
use std::{
fs::File,
io::{self, Read},
time::Duration,
};
use clap::{Args, Parser, Subcommand};
use lazy_static::lazy_static;
use sea_orm::{ConnectOptions, Database, DatabaseConnection};
use sqlx::{mysql::MySqlPoolOptions, Pool};
use crate::Result;
lazy_static! {
pub static ref CLI: AppCli = AppCli::new();
}
@ -54,6 +58,11 @@ impl AppCli {
}
}
#[derive(Debug, Clone)]
pub struct AppState {
pub db: DatabaseConnection,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct ApplicationConfig {
pub uuid: String,
@ -73,7 +82,7 @@ pub struct ApplicationConfig {
pub jwt_secret: Option<String>,
#[serde(skip)]
pub _pool: Option<Pool<sqlx::MySql>>,
pub sqlx_pool: Option<Pool<sqlx::MySql>>,
}
impl ApplicationConfig {
@ -82,7 +91,7 @@ impl ApplicationConfig {
let mut f = match File::open(CLI.cfg.clone()) {
Ok(f) => f,
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
res._pool = Some(res.connect());
res.connect_sqlx().unwrap();
return res;
}
Err(e) => panic!("{}", e),
@ -98,7 +107,7 @@ impl ApplicationConfig {
} else {
println!("release_mode is enable!")
}
res._pool = Some(res.connect());
res.connect_sqlx().unwrap();
res
}
pub fn defaut() -> Self {
@ -117,17 +126,17 @@ impl ApplicationConfig {
log_pack_compress: None,
log_level: None,
jwt_secret: None,
_pool: None,
sqlx_pool: None,
}
}
pub fn save(&self) {}
pub fn db(&self) -> &sqlx::MySqlPool {
match &self._pool {
pub fn sqlx(&self) -> &sqlx::MySqlPool {
match &self.sqlx_pool {
Some(d) => d,
None => panic!("failed"),
}
}
fn connect(&self) -> Pool<sqlx::MySql> {
fn connect_sqlx(&mut self) -> Result<()> {
let url = format!(
"mysql://{}:{}@{}/{}",
self.db_user, self.db_pass, self.db_url, self.db_name
@ -136,7 +145,24 @@ impl ApplicationConfig {
.max_connections(5)
.connect_lazy(&url)
.unwrap();
p
self.sqlx_pool = Some(p);
Ok(())
}
pub async fn connect(&self) -> Result<DatabaseConnection> {
let url = format!(
"mysql://{}:{}@{}/{}",
self.db_user, self.db_pass, self.db_url, self.db_name
);
let mut opt = ConnectOptions::new(url);
opt.max_connections(100)
.min_connections(1)
.connect_timeout(Duration::from_secs(8))
.acquire_timeout(Duration::from_secs(8))
.idle_timeout(Duration::from_secs(8))
.max_lifetime(Duration::from_secs(8));
let db = Database::connect(opt).await?;
Ok(db)
}
}

@ -10,5 +10,5 @@ mod cfg;
pub mod libs;
pub mod models;
mod result;
pub use cfg::{init_log, ApplicationConfig, Clis, CLI, CONFIG};
pub use cfg::{init_log, AppState, ApplicationConfig, Clis, CLI, CONFIG};
pub use result::{Error, Result};

@ -64,16 +64,27 @@ where
let svc = self.service.clone();
Box::pin(async move {
let value = HeaderValue::from_str("").unwrap();
let token = req.headers().get("auth_token").unwrap_or(&value);
let token = models::Token::from(token.to_str().unwrap_or(""));
match token {
match req.headers().get("auth_token") {
Some(h) => {
match models::Token::from(h.to_str().unwrap_or("")){
Ok(t) => {
req.extensions_mut().insert(t.id.clone());
req.extensions_mut().insert(t);
}
Err(e) => warn!("{}", e),
};
}
}
None => {}
}
// let value = HeaderValue::from_str("").unwrap();
// let token = req.headers().get("auth_token").unwrap_or(&value);
// let token = models::Token::from(token.to_str().unwrap_or(""));
// match token {
// Ok(t) => {
// req.extensions_mut().insert(t.id.clone());
// req.extensions_mut().insert(t);
// }
// };
Ok(svc.call(req).await?)
})
}

@ -9,11 +9,11 @@ use actix_web::{
dev,
http::StatusCode,
middleware::{self, ErrorHandlerResponse, ErrorHandlers},
web::{self, Data},
web::{self},
App, HttpServer,
};
use oab::{api, init_log, libs, models, Clis, Result, CLI, CONFIG};
use oab::{api, init_log, libs, models, AppState, Clis, Result, CLI, CONFIG};
use tracing::{error, info, warn};
#[tokio::main]
@ -32,6 +32,8 @@ async fn main() -> Result<()> {
Ok(())
}
async fn web() -> Result<()> {
let db = CONFIG.connect().await?;
let data = AppState { db };
std::env::set_var("RUST_LOG", "info");
std::env::set_var("RUST_BACKTRACE", "1");
let serv = HttpServer::new(move || {
@ -54,13 +56,13 @@ async fn web() -> Result<()> {
.service(fs::Files::new("/media", CONFIG.media_path.clone()).show_files_listing())
.service(
web::scope("api")
.app_data(web::Data::new(data.clone()))
.wrap(
ErrorHandlers::new()
.handler(StatusCode::INTERNAL_SERVER_ERROR, add_error_header),
)
.wrap(libs::auth::Auth)
.app_data(json_config)
.app_data(Data::new(CONFIG.db()))
.configure(api::routes),
)
});

@ -1,89 +0,0 @@
//
// app.rs
// Copyright (C) 2022 veypi <i@veypi.com>
// 2022-07-09 00:18
// Distributed under terms of the Apache license.
//
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
use serde_repr::*;
#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, sqlx::Type)]
#[repr(i64)]
pub enum AppJoin {
Auto = 0,
Disabled = 1,
Applying = 2,
}
#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
pub struct App {
pub id: String,
pub created: Option<NaiveDateTime>,
pub updated: Option<NaiveDateTime>,
pub delete_flag: bool,
pub name: Option<String>,
pub des: Option<String>,
pub icon: Option<String>,
pub user_count: i64,
pub hide: bool,
pub join_method: AppJoin,
pub role_id: Option<String>,
pub redirect: Option<String>,
pub status: i64,
}
impl App {
pub fn new() -> Self {
Self {
id: "".to_string(),
created: None,
updated: None,
delete_flag: false,
name: None,
des: None,
icon: None,
user_count: 0,
hide: false,
join_method: AppJoin::Auto,
role_id: None,
redirect: None,
status: 0,
}
}
}
#[derive(Debug, Deserialize_repr, Serialize_repr, Clone, sqlx::Type)]
#[repr(i64)]
pub enum AUStatus {
OK = 0,
Disabled = 1,
Applying = 2,
Deny = 3,
}
#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
pub struct AppUser {
pub created: Option<NaiveDateTime>,
pub updated: Option<NaiveDateTime>,
pub app_id: String,
pub user_id: String,
pub status: AUStatus,
}
impl AppUser {
pub fn new() -> Self {
Self {
created: None,
updated: None,
app_id: "".to_string(),
user_id: "".to_string(),
status: AUStatus::OK,
}
}
}

@ -0,0 +1,47 @@
//
// app.rs
// Copyright (C) 2022 veypi <i@veypi.com>
// 2022-07-09 00:18
// Distributed under terms of the Apache license.
//
use serde_repr::*;
#[derive(Debug, Serialize_repr, Deserialize_repr, Clone, sqlx::Type)]
#[repr(i32)]
pub enum AppJoin {
Auto = 0,
Disabled = 1,
Applying = 2,
}
impl From<i32> for AppJoin {
fn from(v: i32) -> Self {
match v {
x if x == AppJoin::Auto as i32 => AppJoin::Auto,
x if x == AppJoin::Disabled as i32 => AppJoin::Disabled,
x if x == AppJoin::Applying as i32 => AppJoin::Applying,
_ => AppJoin::Auto,
}
}
}
#[derive(Debug, Deserialize_repr, Serialize_repr, Clone, sqlx::Type)]
#[repr(i32)]
pub enum AUStatus {
OK = 0,
Disabled = 1,
Applying = 2,
Deny = 3,
}
impl From<i32> for AUStatus {
fn from(v: i32) -> Self {
match v {
x if x == AUStatus::OK as i32 => AUStatus::OK,
x if x == AUStatus::Disabled as i32 => AUStatus::Disabled,
x if x == AUStatus::Applying as i32 => AUStatus::Applying,
x if x == AUStatus::Deny as i32 => AUStatus::Deny,
_ => AUStatus::OK,
}
}
}

@ -0,0 +1,79 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(
Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize, Default, sqlx :: FromRow,
)]
#[sea_orm(table_name = "access")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub created: Option<DateTime>,
pub updated: Option<DateTime>,
pub delete_flag: i8,
pub app_id: String,
pub name: String,
pub role_id: Option<String>,
pub user_id: Option<String>,
pub rid: Option<String>,
pub level: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::resource::Entity",
from = "(Column::AppId, Column::Name)",
to = "(super::resource::Column::AppId, super::resource::Column::Name)",
on_update = "NoAction",
on_delete = "NoAction"
)]
Resource,
#[sea_orm(
belongs_to = "super::role::Entity",
from = "Column::RoleId",
to = "super::role::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
Role,
#[sea_orm(
belongs_to = "super::user::Entity",
from = "Column::UserId",
to = "super::user::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
User,
}
impl Related<super::resource::Entity> for Entity {
fn to() -> RelationDef {
Relation::Resource.def()
}
}
impl Related<super::role::Entity> for Entity {
fn to() -> RelationDef {
Relation::Role.def()
}
}
impl Related<super::user::Entity> for Entity {
fn to() -> RelationDef {
Relation::User.def()
}
}
impl Related<super::app::Entity> for Entity {
fn to() -> RelationDef {
super::resource::Relation::App.def()
}
fn via() -> Option<RelationDef> {
Some(super::resource::Relation::Access.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

@ -0,0 +1,80 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(
Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize, Default, sqlx :: FromRow,
)]
#[sea_orm(table_name = "app")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: String,
pub created: Option<DateTime>,
pub updated: Option<DateTime>,
pub delete_flag: i8,
pub key: String,
pub name: String,
pub icon: Option<String>,
pub des: Option<String>,
pub user_count: i32,
pub hide: i8,
pub join_method: i32,
pub role_id: Option<String>,
pub redirect: Option<String>,
pub status: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::app_user::Entity")]
AppUser,
#[sea_orm(has_many = "super::resource::Entity")]
Resource,
#[sea_orm(
belongs_to = "super::role::Entity",
from = "Column::RoleId",
to = "super::role::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
Role,
}
impl Related<super::app_user::Entity> for Entity {
fn to() -> RelationDef {
Relation::AppUser.def()
}
}
impl Related<super::resource::Entity> for Entity {
fn to() -> RelationDef {
Relation::Resource.def()
}
}
impl Related<super::role::Entity> for Entity {
fn to() -> RelationDef {
Relation::Role.def()
}
}
impl Related<super::access::Entity> for Entity {
fn to() -> RelationDef {
super::resource::Relation::Access.def()
}
fn via() -> Option<RelationDef> {
Some(super::resource::Relation::App.def().rev())
}
}
impl Related<super::user::Entity> for Entity {
fn to() -> RelationDef {
super::app_user::Relation::User.def()
}
fn via() -> Option<RelationDef> {
Some(super::app_user::Relation::App.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

@ -0,0 +1,52 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(
Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize, Default, sqlx :: FromRow,
)]
#[sea_orm(table_name = "app_user")]
pub struct Model {
pub created: Option<DateTime>,
pub updated: Option<DateTime>,
#[sea_orm(primary_key, auto_increment = false)]
pub app_id: String,
#[sea_orm(primary_key, auto_increment = false)]
pub user_id: String,
pub status: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::app::Entity",
from = "Column::AppId",
to = "super::app::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
App,
#[sea_orm(
belongs_to = "super::user::Entity",
from = "Column::UserId",
to = "super::user::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
User,
}
impl Related<super::app::Entity> for Entity {
fn to() -> RelationDef {
Relation::App.def()
}
}
impl Related<super::user::Entity> for Entity {
fn to() -> RelationDef {
Relation::User.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

@ -0,0 +1,11 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
pub mod prelude;
pub mod access;
pub mod app;
pub mod app_user;
pub mod resource;
pub mod role;
pub mod user;
pub mod user_role;

@ -0,0 +1,9 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
pub use super::access::Entity as Access;
pub use super::app::Entity as App;
pub use super::app_user::Entity as AppUser;
pub use super::resource::Entity as Resource;
pub use super::role::Entity as Role;
pub use super::user::Entity as User;
pub use super::user_role::Entity as UserRole;

@ -0,0 +1,47 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(
Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize, Default, sqlx :: FromRow,
)]
#[sea_orm(table_name = "resource")]
pub struct Model {
pub created: Option<DateTime>,
pub updated: Option<DateTime>,
pub delete_flag: i8,
#[sea_orm(primary_key, auto_increment = false)]
pub app_id: String,
#[sea_orm(primary_key, auto_increment = false)]
pub name: String,
pub des: Option<String>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::access::Entity")]
Access,
#[sea_orm(
belongs_to = "super::app::Entity",
from = "Column::AppId",
to = "super::app::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
App,
}
impl Related<super::access::Entity> for Entity {
fn to() -> RelationDef {
Relation::Access.def()
}
}
impl Related<super::app::Entity> for Entity {
fn to() -> RelationDef {
Relation::App.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

@ -0,0 +1,65 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(
Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize, Default, sqlx :: FromRow,
)]
#[sea_orm(table_name = "role")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: String,
pub created: Option<DateTime>,
pub updated: Option<DateTime>,
pub delete_flag: i8,
pub app_id: String,
pub name: String,
pub des: Option<String>,
pub user_count: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::access::Entity")]
Access,
#[sea_orm(
belongs_to = "super::app::Entity",
from = "Column::AppId",
to = "super::app::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
App,
#[sea_orm(has_many = "super::user_role::Entity")]
UserRole,
}
impl Related<super::access::Entity> for Entity {
fn to() -> RelationDef {
Relation::Access.def()
}
}
impl Related<super::app::Entity> for Entity {
fn to() -> RelationDef {
Relation::App.def()
}
}
impl Related<super::user_role::Entity> for Entity {
fn to() -> RelationDef {
Relation::UserRole.def()
}
}
impl Related<super::user::Entity> for Entity {
fn to() -> RelationDef {
super::user_role::Relation::User.def()
}
fn via() -> Option<RelationDef> {
Some(super::user_role::Relation::Role.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

@ -0,0 +1,17 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "status")]
pub enum Status {
#[sea_orm(string_value = "ok")]
Ok,
#[sea_orm(string_value = "disabled")]
Disabled,
#[sea_orm(string_value = "applying")]
Applying,
#[sea_orm(string_value = "deny")]
Deny,
}

@ -0,0 +1,85 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(
Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize, Default, sqlx :: FromRow,
)]
#[sea_orm(table_name = "user")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: String,
pub created: Option<DateTime>,
pub updated: Option<DateTime>,
pub delete_flag: i8,
#[sea_orm(unique)]
pub username: String,
pub nickname: Option<String>,
#[sea_orm(unique)]
pub email: Option<String>,
#[sea_orm(unique)]
pub phone: Option<String>,
pub icon: Option<String>,
#[sea_orm(column_name = "_real_code")]
#[serde(skip)]
pub real_code: Option<String>,
#[sea_orm(
column_name = "_check_code",
column_type = "Binary(BlobSize::Blob(Some(48)))",
nullable
)]
#[serde(skip)]
pub check_code: Option<Vec<u8>>,
pub status: i32,
pub used: i32,
pub space: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::access::Entity")]
Access,
#[sea_orm(has_many = "super::app_user::Entity")]
AppUser,
#[sea_orm(has_many = "super::user_role::Entity")]
UserRole,
}
impl Related<super::access::Entity> for Entity {
fn to() -> RelationDef {
Relation::Access.def()
}
}
impl Related<super::app_user::Entity> for Entity {
fn to() -> RelationDef {
Relation::AppUser.def()
}
}
impl Related<super::user_role::Entity> for Entity {
fn to() -> RelationDef {
Relation::UserRole.def()
}
}
impl Related<super::app::Entity> for Entity {
fn to() -> RelationDef {
super::app_user::Relation::App.def()
}
fn via() -> Option<RelationDef> {
Some(super::app_user::Relation::User.def().rev())
}
}
impl Related<super::role::Entity> for Entity {
fn to() -> RelationDef {
super::user_role::Relation::Role.def()
}
fn via() -> Option<RelationDef> {
Some(super::user_role::Relation::User.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}

@ -0,0 +1,52 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(
Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize, Default, sqlx :: FromRow,
)]
#[sea_orm(table_name = "user_role")]
pub struct Model {
pub created: Option<DateTime>,
pub updated: Option<DateTime>,
#[sea_orm(primary_key, auto_increment = false)]
pub user_id: String,
#[sea_orm(primary_key, auto_increment = false)]
pub role_id: String,
pub status: String,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::role::Entity",
from = "Column::RoleId",
to = "super::role::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
Role,
#[sea_orm(
belongs_to = "super::user::Entity",
from = "Column::UserId",
to = "super::user::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
User,
}
impl Related<super::role::Entity> for Entity {
fn to() -> RelationDef {
Relation::Role.def()
}
}
impl Related<super::user::Entity> for Entity {
fn to() -> RelationDef {
Relation::User.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

@ -5,19 +5,20 @@
// Distributed under terms of the MIT license.
//
pub mod app;
mod app_plugin;
pub mod entity;
mod role;
mod user;
mod user_plugin;
use tracing::info;
pub use app::{AUStatus, App, AppJoin, AppUser};
pub use role::{Access, Resource, Role};
pub use user::{AccessCore, AccessLevel, Token, User};
pub use app_plugin::{AUStatus, AppJoin};
pub use entity::{access, app, app_user, user};
pub use user_plugin::{AccessLevel, Token, UserPlugin};
use crate::CONFIG;
pub async fn init() {
info!("init database");
sqlx::migrate!().run(CONFIG.db()).await.unwrap();
sqlx::migrate!().run(CONFIG.sqlx()).await.unwrap();
}

@ -6,8 +6,6 @@
//
//
use actix_web::ResponseError;
use chrono::{prelude::*, Duration};
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
@ -45,27 +43,15 @@ fn rand_str(l: usize) -> String {
// block
// }
#[derive(Debug, Default, Serialize, Deserialize, sqlx::FromRow)]
pub struct User {
pub id: String,
pub created: Option<NaiveDateTime>,
pub updated: Option<NaiveDateTime>,
pub delete_flag: bool,
pub username: String,
pub nickname: Option<String>,
pub email: Option<String>,
pub phone: Option<String>,
pub icon: Option<String>,
pub real_code: Option<String>,
pub check_code: Option<Vec<u8>>,
pub status: i32,
pub used: i32,
pub space: i32,
pub trait UserPlugin {
fn token(&self, ac: Vec<super::entity::access::Model>) -> Token;
fn check_pass(&self, p: &str) -> Result<()>;
fn update_pass(&mut self, p: &str) -> Result<()>;
}
impl User {
pub fn token(&self, ac: Vec<AccessCore>) -> Token {
// impl User {
impl UserPlugin for super::entity::user::Model {
fn token(&self, ac: Vec<super::entity::access::Model>) -> Token {
let default_ico = "/media/".to_string();
let t = Token {
iss: "onedt".to_string(),
@ -83,13 +69,13 @@ impl User {
};
t
}
pub fn check_pass(&self, p: &str) -> Result<()> {
fn check_pass(&self, p: &str) -> Result<()> {
let p = p.as_bytes();
let mut key_block: GenericArray<u8, U32> = [0xff; 32].into();
key_block[..p.len()].copy_from_slice(p);
Pkcs7::pad(&mut key_block, p.len());
// key 32 Byte
let key = Key::from_slice(&key_block);
let key = Key::from_slice(&key_block.as_slice());
let cipher = Aes256Gcm::new(&key);
// 12 Byte
@ -107,7 +93,7 @@ impl User {
Err(Error::ArgInvalid("password".to_string()))
}
}
pub fn update_pass(&mut self, p: &str) -> Result<()> {
fn update_pass(&mut self, p: &str) -> Result<()> {
if p.len() < 6 || p.len() > 32 {
return Err(Error::ArgInvalid("password".to_string()));
}
@ -116,7 +102,7 @@ impl User {
key_block[..p.len()].copy_from_slice(p);
Pkcs7::pad(&mut key_block, p.len());
// key 32 Byte
let key = Key::from_slice(&key_block);
let key = Key::from_slice(&key_block.as_slice());
let cipher = Aes256Gcm::new(&key);
// 12 Byte
@ -136,40 +122,6 @@ impl User {
}
}
impl actix_web::Responder for User {
type Body = actix_web::body::BoxBody;
fn respond_to(self, _req: &actix_web::HttpRequest) -> actix_web::HttpResponse<Self::Body> {
match serde_json::to_string(&self) {
Ok(body) => match actix_web::HttpResponse::Ok()
.content_type(actix_web::http::header::ContentType::json())
.message_body(body)
{
Ok(res) => res.map_into_boxed_body(),
Err(err) => Error::from(err).error_response(),
},
Err(_err) => Error::SerdeError.error_response(),
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone, sqlx::FromRow)]
pub struct Access {
pub created: Option<NaiveDateTime>,
pub updated: Option<NaiveDateTime>,
pub user_id: String,
pub domain: String,
pub did: Option<String>,
pub l: AccessLevel,
}
#[derive(Debug, Serialize, Deserialize, Clone, sqlx::FromRow)]
pub struct AccessCore {
pub name: String,
pub rid: Option<String>,
pub level: AccessLevel,
}
#[derive(
MyDisplay,
Debug,
@ -192,6 +144,20 @@ pub enum AccessLevel {
ALL = 5,
}
impl From<i32> for AccessLevel {
fn from(v: i32) -> Self {
match v {
x if x == AccessLevel::No as i32 => AccessLevel::No,
x if x == AccessLevel::Read as i32 => AccessLevel::Read,
x if x == AccessLevel::Create as i32 => AccessLevel::Create,
x if x == AccessLevel::Update as i32 => AccessLevel::Update,
x if x == AccessLevel::Delete as i32 => AccessLevel::Delete,
x if x == AccessLevel::ALL as i32 => AccessLevel::ALL,
_ => AccessLevel::No,
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Token {
pub iss: String, // Optional. token 发行者
@ -201,7 +167,7 @@ pub struct Token {
pub id: String, // 用户id
pub nickname: String,
pub ico: String,
pub access: Option<Vec<AccessCore>>,
pub access: Option<Vec<super::access::Model>>,
}
impl Token {
@ -235,6 +201,7 @@ impl Token {
fn check(&self, domain: &str, did: &str, l: AccessLevel) -> bool {
info!("{:#?}|{:#?}|{}|", self.access, domain, did);
let l = l as i32;
match &self.access {
Some(ac) => {
for ele in ac {

@ -81,7 +81,7 @@ pub enum Error {
InternalServerError,
// business
#[error("无效的 Session ID")]
#[error("invalid 的 Session ID")]
InvalidSessionId,
#[error("invalid verify code")]
InvalidVerifyCode,
@ -151,6 +151,12 @@ impl From<jsonwebtoken::errors::Error> for Error {
Error::BusinessException(format!("{:?}", e))
}
}
impl From<sea_orm::DbErr> for Error {
fn from(e: sea_orm::DbErr) -> Self {
Error::BusinessException(format!("{:?}", e))
}
}
impl From<aes_gcm::Error> for Error {
fn from(e: aes_gcm::Error) -> Self {
Error::BusinessException(format!("{:?}", e))
@ -172,7 +178,7 @@ impl actix_web::Responder for Error {
impl error::ResponseError for Error {
fn error_response(&self) -> HttpResponse {
info!("{}", self.to_string());
info!("{}", self);
HttpResponse::build(self.status_code())
.insert_header(ContentType::html())
.insert_header(("error", self.to_string()))

Loading…
Cancel
Save