diff --git a/Makefile b/Makefile index f602015..8d584ce 100644 --- a/Makefile +++ b/Makefile @@ -29,3 +29,8 @@ build: syncDB: @scp -P 19529 oa.db root@alco.host:/root/ + +buildweb: + @cd oaweb && yarn build + @rm -rf ./oab/dist/* + @mv ./oaweb/dist/spa/* ./oab/dist/ diff --git a/oab/Cargo.lock b/oab/Cargo.lock index 2a5e975..23a65ac 100644 --- a/oab/Cargo.lock +++ b/oab/Cargo.lock @@ -1914,8 +1914,10 @@ dependencies = [ "include_dir", "jsonwebtoken", "lazy_static", + "mime_guess", "proc", "rand", + "rust-embed", "sea-orm", "serde", "serde-big-array", @@ -2445,6 +2447,40 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rust-embed" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e7d90385b59f0a6bf3d3b757f3ca4ece2048265d70db20a2016043d4509a40" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3d8c6fd84090ae348e63a84336b112b5c3918b3bf0493a581f7bd8ee623c29" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn 2.0.37", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873feff8cb7bf86fdf0a71bb21c95159f4e4a37dd7a4bd1855a940909b583ada" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "rust_decimal" version = "1.32.0" @@ -2538,6 +2574,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -3637,6 +3682,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/oab/Cargo.toml b/oab/Cargo.toml index 775ce77..39399af 100644 --- a/oab/Cargo.toml +++ b/oab/Cargo.toml @@ -53,4 +53,6 @@ http = "0.2.9" http-auth-basic = "0.3.3" actix-multipart = "0.6.1" actix-cors = "0.6.4" +rust-embed = "8.0.0" +mime_guess = "2.0.4" diff --git a/oab/dist/index.html b/oab/dist/index.html new file mode 100644 index 0000000..0b5d476 --- /dev/null +++ b/oab/dist/index.html @@ -0,0 +1,3 @@ +OA + +
\ No newline at end of file diff --git a/oab/proc/src/curd.rs b/oab/proc/src/crud.rs similarity index 100% rename from oab/proc/src/curd.rs rename to oab/proc/src/crud.rs diff --git a/oab/proc/src/lib.rs b/oab/proc/src/lib.rs index b15ee27..409de2e 100644 --- a/oab/proc/src/lib.rs +++ b/oab/proc/src/lib.rs @@ -9,9 +9,9 @@ use proc_macro::TokenStream; use quote::{quote, ToTokens}; use syn::{parse_macro_input, AttributeArgs, ItemFn}; mod access; -mod curd; +mod crud; use access::AccessWrap; -use curd::CrudWrap; +use crud::CrudWrap; #[proc_macro_attribute] pub fn have_access(args: TokenStream, input: TokenStream) -> TokenStream { diff --git a/oab/src/api/access.rs b/oab/src/api/access.rs index 1cbd951..85fe373 100644 --- a/oab/src/api/access.rs +++ b/oab/src/api/access.rs @@ -6,109 +6,108 @@ // // // -use actix_web::{web, Responder}; -use proc::crud_update; -use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, TransactionTrait}; +use actix_web::{delete, get, patch, post, web, Responder}; +use proc::{access_create, access_delete, access_read, crud_update}; +use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter}; use serde::{Deserialize, Serialize}; +use tracing::info; -use crate::{models::app, AppState, Error, Result}; +use crate::{ + models::{self}, + AppState, Error, Result, +}; -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct UpdateOpt { - pub name: Option, - pub icon: Option, - pub des: Option, - pub join_method: Option, - pub role_id: Option, - pub redirect: Option, - pub status: Option, +#[derive(Debug, Deserialize, Serialize)] +pub struct Options { + name: Option, + role_id: Option, + user_id: Option, + rid: Option, + level: Option, } -impl UpdateOpt { - // #[crud_update( - // app, - // id = "Id", - // name, - // icon, - // des, - // join_method, - // role_id, - // redirect, - // status - // )] - pub async fn update( - id: web::Path, - stat: web::Data, - data: web::Json, - ) -> Result { - let data = data.into_inner(); - let id = id.into_inner(); - let obj = app::Entity::find_by_id(&id).one(stat.db()).await?; - let mut obj: app::ActiveModel = match obj { - Some(o) => o.into(), - None => return Err(Error::NotFound(id)), - }; - if let Some(name) = data.name { - obj.name = sea_orm::Set(name) - }; - let obj = obj.update(stat.db()).await?; - Ok(web::Json(obj)) - } + +#[get("/app/{aid}/access/")] +#[access_read("app")] +pub async fn list( + aid: web::Path, + stat: web::Data, + query: web::Query, +) -> Result { + let aid = aid.into_inner(); + let mut q = models::access::Entity::find().filter(models::access::Column::AppId.eq(aid)); + let query = query.into_inner(); + if let Some(rid) = query.role_id { + q = q.filter(models::access::Column::RoleId.eq(rid)); + }; + if let Some(v) = query.name { + q = q.filter(models::access::Column::Name.eq(v)); + }; + if let Some(v) = query.user_id { + q = q.filter(models::access::Column::UserId.eq(v)); + }; + let aus = q.all(stat.db()).await?; + Ok(web::Json(aus)) } -pub async fn update( - id: web::Path, +#[derive(Debug, Deserialize, Serialize)] +pub struct CreateOptions { + name: String, + level: i32, + role_id: Option, + user_id: Option, + rid: Option, +} +#[post("/app/{aid}/access/")] +#[access_create("app")] +pub async fn creat( + aid: web::Path, stat: web::Data, - data: web::Json, + query: web::Json, ) -> Result { - let _id = &id.clone(); - let _data = data.clone(); - let _db = &stat.db().clone(); - let f = || async move { - let data = data.into_inner(); - let id = id.into_inner(); - let obj = app::Entity::find_by_id(&id).one(stat.db()).await?; - let mut obj: app::ActiveModel = match obj { - Some(o) => o.into(), - None => return Err(Error::NotFound(id)), - }; - if let Some(name) = data.name { - obj.name = sea_orm::Set(name) - }; - let obj = obj.update(stat.db()).await?; - Ok(web::Json(obj)) + let aid = aid.into_inner(); + let query = query.into_inner(); + let obj = models::access::ActiveModel { + app_id: sea_orm::ActiveValue::Set(aid), + name: sea_orm::ActiveValue::Set(query.name), + level: sea_orm::ActiveValue::Set(query.level), + role_id: sea_orm::ActiveValue::Set(query.role_id), + user_id: sea_orm::ActiveValue::Set(query.user_id), + rid: sea_orm::ActiveValue::Set(query.rid), + ..Default::default() }; - let res = f().await; - match res { - Err(e) => Err(e), - Ok(res) => { - let obj = crate::models::app::Entity::find_by_id(_id).one(_db).await?; - let mut obj: crate::models::app::ActiveModel = match obj { - Some(o) => o.into(), - None => return Err(Error::NotFound(_id.to_owned())), - }; - if let Some(name) = _data.name { - obj.name = sea_orm::Set(name.into()) - }; - if let Some(icon) = _data.icon { - obj.icon = sea_orm::Set(icon.into()) - }; - if let Some(des) = _data.des { - obj.des = sea_orm::Set(des.into()) - }; - if let Some(join_method) = _data.join_method { - obj.join_method = sea_orm::Set(join_method.into()) - }; - if let Some(role_id) = _data.role_id { - obj.role_id = sea_orm::Set(role_id.into()) - }; - if let Some(redirect) = _data.redirect { - obj.redirect = sea_orm::Set(redirect.into()) - }; - if let Some(status) = _data.status { - obj.status = sea_orm::Set(status.into()) - }; - let obj = obj.update(_db).await?; - Ok(actix_web::web::Json(obj)) - } - } + let obj: models::access::Model = obj.insert(stat.db()).await?; + Ok(web::Json(obj)) +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct UpdateOpt { + pub level: Option, + pub rid: Option, +} + +#[patch("/app/{aid}/access/{id}")] +#[access_delete("app")] +#[crud_update(access, AppId = "_id", Id = "_id", level, rid)] +pub async fn update( + id: web::Path<(String, String)>, + data: web::Json, + stat: web::Data, +) -> Result { + Ok("") +} + +#[delete("/app/{aid}/access/{id}")] +#[access_delete("app")] +pub async fn delete( + params: web::Path<(String, String)>, + stat: web::Data, +) -> Result { + let (aid, rid) = params.into_inner(); + let res = models::access::Entity::delete_many() + .filter(models::access::Column::AppId.eq(aid)) + .filter(models::access::Column::Id.eq(rid)) + .exec(stat.db()) + .await?; + info!("{:#?}", res); + Ok("ok") } diff --git a/oab/src/api/app.rs b/oab/src/api/app.rs index 873346d..b2144c4 100644 --- a/oab/src/api/app.rs +++ b/oab/src/api/app.rs @@ -88,6 +88,7 @@ pub struct UpdateOpt { pub join_method: Option, pub role_id: Option, pub redirect: Option, + pub host: Option, pub status: Option, } @@ -102,6 +103,7 @@ pub struct UpdateOpt { join_method, role_id, redirect, + host, status )] pub async fn update( diff --git a/oab/src/api/mod.rs b/oab/src/api/mod.rs index 8d742a4..25eedf7 100644 --- a/oab/src/api/mod.rs +++ b/oab/src/api/mod.rs @@ -21,6 +21,7 @@ pub fn routes(cfg: &mut web::ServiceConfig) { .service(user::list) .service(user::register) .service(user::login) + .service(user::update) .service(user::delete); cfg.service(app::get) .service(app::list) @@ -32,4 +33,19 @@ pub fn routes(cfg: &mut web::ServiceConfig) { cfg.service(appuser::get) .service(appuser::add) .service(appuser::update); + + cfg.service(access::list) + .service(access::creat) + .service(access::update) + .service(access::delete); + cfg.service(resource::list) + .service(resource::create) + .service(resource::update) + .service(resource::delete); + cfg.service(role::list) + .service(role::create) + .service(role::update) + .service(role::delete) + .service(role::add) + .service(role::drop); } diff --git a/oab/src/api/resource.rs b/oab/src/api/resource.rs index 7dcce20..cccad92 100644 --- a/oab/src/api/resource.rs +++ b/oab/src/api/resource.rs @@ -4,3 +4,85 @@ // 2022-07-09 03:09 // Distributed under terms of the Apache license. // +use actix_web::{delete, get, patch, post, web, Responder}; +use proc::{access_create, access_delete, access_read, crud_update}; +use sea_orm::{ + ActiveModelTrait, ColumnTrait, EntityTrait, LoaderTrait, QueryFilter, TransactionTrait, +}; +use serde::{Deserialize, Serialize}; +use tracing::info; + +use crate::{ + models::{self}, + AppState, Error, Result, +}; + +#[get("/app/{aid}/resource/")] +#[access_read("app")] +pub async fn list(aid: web::Path, stat: web::Data) -> Result { + let n = aid.into_inner(); + if !n.is_empty() { + let s = models::resource::Entity::find() + .filter(models::resource::Column::AppId.eq(n)) + .all(stat.db()) + .await?; + Ok(web::Json(s)) + } else { + Err(Error::Missing("id".to_string())) + } +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct CreateOpt { + name: String, + des: Option, +} +#[post("/app/{aid}/resource/")] +#[access_create("app")] +pub async fn create( + aid: web::Path, + stat: web::Data, + data: web::Json, +) -> Result { + let data = data.into_inner(); + let obj = models::resource::ActiveModel { + name: sea_orm::ActiveValue::Set(data.name), + des: sea_orm::ActiveValue::Set(data.des), + app_id: sea_orm::ActiveValue::Set(aid.into_inner()), + ..Default::default() + }; + let obj = obj.insert(stat.db()).await?; + Ok(web::Json(obj)) +} + +#[delete("/app/{aid}/resource/{rid}")] +#[access_delete("app")] +pub async fn delete( + params: web::Path<(String, String)>, + stat: web::Data, +) -> Result { + let (aid, rid) = params.into_inner(); + let res = models::resource::Entity::delete_many() + .filter(models::resource::Column::AppId.eq(aid)) + .filter(models::resource::Column::Name.eq(rid)) + .exec(stat.db()) + .await?; + info!("{:#?}", res); + Ok("ok") +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct UpdateOpt { + pub des: Option, +} + +#[patch("/app/{aid}/resource/{rid}")] +#[access_delete("app")] +#[crud_update(resource, AppId = "_id", Name = "_id", des)] +pub async fn update( + id: web::Path<(String, String)>, + data: web::Json, + stat: web::Data, +) -> Result { + Ok("") +} diff --git a/oab/src/api/role.rs b/oab/src/api/role.rs index edb1fad..981ac29 100644 --- a/oab/src/api/role.rs +++ b/oab/src/api/role.rs @@ -4,3 +4,141 @@ // 2022-07-09 03:10 // Distributed under terms of the Apache license. // +// +use actix_web::{delete, get, patch, post, web, Responder}; +use proc::{access_create, access_delete, access_read, access_update, crud_update}; +use sea_orm::{ + ActiveModelTrait, ColumnTrait, ConnectionTrait, EntityTrait, LoaderTrait, QueryFilter, + TransactionTrait, +}; +use serde::{Deserialize, Serialize}; +use tracing::info; + +use crate::{ + libs, + models::{self}, + AppState, Error, Result, +}; + +#[get("/app/{aid}/role/")] +#[access_read("app")] +pub async fn list(aid: web::Path, stat: web::Data) -> Result { + let n = aid.into_inner(); + if !n.is_empty() { + let s = models::role::Entity::find() + .filter(models::role::Column::AppId.eq(n)) + .all(stat.db()) + .await?; + Ok(web::Json(s)) + } else { + Err(Error::Missing("id".to_string())) + } +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct CreateOpt { + name: String, + des: Option, +} +#[post("/app/{aid}/role/")] +#[access_create("app")] +pub async fn create( + aid: web::Path, + stat: web::Data, + data: web::Json, +) -> Result { + let data = data.into_inner(); + let id = uuid::Uuid::new_v4().to_string().replace("-", ""); + let obj = models::role::ActiveModel { + name: sea_orm::ActiveValue::Set(data.name), + id: sea_orm::ActiveValue::Set(id), + des: sea_orm::ActiveValue::Set(data.des), + app_id: sea_orm::ActiveValue::Set(aid.into_inner()), + ..Default::default() + }; + let obj = obj.insert(stat.db()).await?; + Ok(web::Json(obj)) +} + +#[delete("/app/{aid}/role/{rid}")] +#[access_delete("app", id = "&id.clone().0")] +pub async fn delete( + id: web::Path<(String, String)>, + stat: web::Data, +) -> Result { + let (aid, rid) = id.into_inner(); + let res = models::role::Entity::delete_many() + .filter(models::role::Column::AppId.eq(aid)) + .filter(models::role::Column::Id.eq(rid)) + .exec(stat.db()) + .await?; + info!("{:#?}", res); + Ok("ok") +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct UpdateOpt { + pub des: Option, +} + +#[patch("/app/{aid}/role/{rid}")] +#[access_update("app", id = "&id.clone().0")] +#[crud_update(role, AppId = "_id", Id = "_id", des)] +pub async fn update( + id: web::Path<(String, String)>, + data: web::Json, + stat: web::Data, +) -> Result { + Ok("") +} + +#[get("/app/{aid}/role/{rid}/user/{uid}")] +#[access_delete("app", id = "&id.clone().0")] +pub async fn add( + id: web::Path<(String, String, String)>, + stat: web::Data, +) -> Result { + let (_, rid, uid) = id.into_inner(); + let s = models::user_role::ActiveModel { + user_id: sea_orm::ActiveValue::Set(uid), + role_id: sea_orm::ActiveValue::Set(rid.clone()), + ..Default::default() + }; + let s = s.insert(stat.db()).await?; + let sql = format!( + "update role set user_count = user_count + 1 where id = '{}'", + rid, + ); + stat.db() + .execute(sea_orm::Statement::from_string( + sea_orm::DatabaseBackend::MySql, + sql, + )) + .await?; + Ok(web::Json(s)) +} + +#[delete("/app/{aid}/role/{rid}/user/{uid}")] +#[access_delete("app", id = "&id.clone().0")] +pub async fn drop( + id: web::Path<(String, String, String)>, + stat: web::Data, +) -> Result { + let (_, rid, uid) = id.into_inner(); + models::user_role::Entity::delete_many() + .filter(models::user_role::Column::RoleId.eq(rid.clone())) + .filter(models::user_role::Column::UserId.eq(uid)) + .exec(stat.db()) + .await?; + let sql = format!( + "update role set user_count = user_count - 1 where id = '{}'", + rid, + ); + stat.db() + .execute(sea_orm::Statement::from_string( + sea_orm::DatabaseBackend::MySql, + sql, + )) + .await?; + Ok("ok") +} diff --git a/oab/src/api/user.rs b/oab/src/api/user.rs index 8ea8154..ed8ec1d 100644 --- a/oab/src/api/user.rs +++ b/oab/src/api/user.rs @@ -12,10 +12,10 @@ use crate::{ models::{self, app_user, user, AUStatus, UserPlugin}, AppState, Error, Result, }; -use actix_web::{delete, get, head, http, post, web, HttpResponse, Responder}; +use actix_web::{delete, get, head, http, patch, post, web, HttpResponse, Responder}; use base64; use chrono::{DateTime, Local, NaiveDateTime}; -use proc::access_read; +use proc::{access_read, access_update, crud_update}; use rand::Rng; use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, TransactionTrait}; use serde::{Deserialize, Serialize}; @@ -35,10 +35,46 @@ pub async fn get(id: web::Path, stat: web::Data) -> Result, + role_id: Option, + app_id: Option, +} + #[get("/user/")] #[access_read("user")] -pub async fn list(stat: web::Data) -> Result { - let res: Vec = user::Entity::find().all(stat.db()).await?; +pub async fn list( + stat: web::Data, + query: web::Query, +) -> Result { + let query = query.into_inner(); + let res = if let Some(v) = query.name { + user::Entity::find() + .filter(user::Column::Username.contains(v)) + .all(stat.db()) + .await? + } else if let Some(v) = query.role_id { + models::user_role::Entity::find() + .filter(models::user_role::Column::RoleId.eq(v)) + .find_also_related(user::Entity) + .all(stat.db()) + .await? + .into_iter() + .filter_map(|(_, u)| return u) + .collect() + } else if let Some(v) = query.app_id { + models::app_user::Entity::find() + .filter(models::app_user::Column::AppId.eq(v)) + .find_also_related(user::Entity) + .all(stat.db()) + .await? + .into_iter() + .filter_map(|(_, u)| return u) + .collect() + } else { + user::Entity::find().all(stat.db()).await? + }; Ok(web::Json(res)) } @@ -175,6 +211,26 @@ pub async fn register( Ok(web::Json(u)) } +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct UpdateOpt { + pub username: Option, + pub icon: Option, + pub nickname: Option, + pub email: Option, + pub phone: Option, +} + +#[patch("/user/{id}")] +#[access_update("user")] +#[crud_update(user, Id = "_id", username, icon, nickname, email, phone)] +pub async fn update( + id: web::Path, + stat: web::Data, + data: web::Json, +) -> Result { + Ok("") +} + #[delete("/user/")] pub async fn delete() -> impl Responder { "" diff --git a/oab/src/api/userapp.rs b/oab/src/api/userapp.rs deleted file mode 100644 index f1dd499..0000000 --- a/oab/src/api/userapp.rs +++ /dev/null @@ -1,69 +0,0 @@ -// -// userapp.rs -// Copyright (C) 2023 veypi -// 2023-10-09 03:12 -// Distributed under terms of the MIT license. -// - -use actix_web::{get, post, web, Responder}; -use proc::access_read; -use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, TransactionTrait}; - -use crate::{ - libs, - models::{app, app_user}, - AppState, Error, Result, -}; - -// 获取 app -#[get("/user/{uid}/user/{aid}")] -#[access_read("app")] -pub async fn get( - params: web::Path<(String, String)>, - stat: web::Data, -) -> Result { - let (mut aid, mut uid) = params.into_inner(); - let mut q = app_user::Entity::find(); - if uid == "-" { - uid = "".to_string(); - } else { - q = q.filter(app_user::Column::UserId.eq(uid.clone())); - } - if aid == "-" { - aid = "".to_string(); - } else { - q = q.filter(app_user::Column::AppId.eq(aid.clone())); - } - if uid.is_empty() && aid.is_empty() { - Err(Error::Missing("uid or aid".to_string())) - } else { - let s: Vec<(app_user::Model, Option)> = - q.find_also_related(app::Entity).all(stat.db()).await?; - let res: Vec = s - .into_iter() - .filter_map(|(l, a)| match a { - Some(a) => Some(app::Model { - status: l.status, - ..a - }), - None => None, - }) - .collect(); - // let s: Vec = q.all(stat.db()).await?; - Ok(web::Json(res)) - } -} - -// 关联app -#[post("/user/{uid}/app/{aid}")] -#[access_read("app")] -pub async fn add( - params: web::Path<(String, String)>, - stat: web::Data, -) -> Result { - let (aid, uid) = params.into_inner(); - let db = stat.db().begin().await?; - let res = libs::user::connect_to_app(uid, aid, &db, None).await?; - db.commit().await?; - Ok(web::Json(res)) -} diff --git a/oab/src/libs/user.rs b/oab/src/libs/user.rs index 33898e5..08e3930 100644 --- a/oab/src/libs/user.rs +++ b/oab/src/libs/user.rs @@ -60,14 +60,23 @@ pub async fn after_connected_to_app( obj: app::Model, db: &DatabaseTransaction, ) -> Result<()> { - if obj.role_id.is_some() { + if let Some(role_id) = obj.role_id { user_role::ActiveModel { user_id: sea_orm::ActiveValue::Set(uid.clone()), - role_id: sea_orm::ActiveValue::Set(obj.role_id.unwrap().clone()), + role_id: sea_orm::ActiveValue::Set(role_id.clone()), ..Default::default() } .insert(db) .await?; + let sql = format!( + "update role set user_count = user_count + 1 where id = '{}'", + role_id, + ); + db.execute(sea_orm::Statement::from_string( + sea_orm::DatabaseBackend::MySql, + sql, + )) + .await?; }; let sql = format!( "update app set user_count = user_count + 1 where id = '{}'", diff --git a/oab/src/main.rs b/oab/src/main.rs index d72502d..cef3870 100644 --- a/oab/src/main.rs +++ b/oab/src/main.rs @@ -11,9 +11,11 @@ use actix_web::{ http::StatusCode, middleware::{self, ErrorHandlerResponse, ErrorHandlers}, web::{self}, - App, HttpServer, + App, HttpResponse, HttpServer, Responder, }; use futures_util::future::FutureExt; +use mime_guess::from_path; +use rust_embed::RustEmbed; use http::{HeaderName, HeaderValue}; use oab::{api, init_log, libs, models, AppState, Clis, Result, CLI}; @@ -100,6 +102,7 @@ async fn web(data: AppState) -> Result<()> { .app_data(web::Data::new(dav.clone())) .service(web::resource("/{tail:.*}").to(libs::fs::dav_handler)), ) + .service(index) }); info!("listen to {}", url); serv.bind(url)?.run().await?; @@ -113,3 +116,21 @@ fn add_error_header( Ok(ErrorHandlerResponse::Response(res.map_into_left_body())) } + +#[derive(RustEmbed)] +#[folder = "dist/"] +struct Asset; + +#[actix_web::get("/{_:.*}")] +async fn index(p: web::Path) -> impl Responder { + info!("{}", p); + let p = &p.into_inner(); + match Asset::get(p) { + Some(content) => HttpResponse::Ok() + .content_type(from_path(p).first_or_octet_stream().as_ref()) + .body(content.data.into_owned()), + None => HttpResponse::Ok() + .content_type(from_path("index.html").first_or_octet_stream().as_ref()) + .body(Asset::get("index.html").unwrap().data.into_owned()), + } +} diff --git a/oab/src/models/mod.rs b/oab/src/models/mod.rs index 32101b7..1df22a8 100644 --- a/oab/src/models/mod.rs +++ b/oab/src/models/mod.rs @@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize}; use tracing::info; pub use app_plugin::{AUStatus, AppJoin}; -pub use entity::{access, app, app_user, role, user, user_role}; +pub use entity::{access, app, app_user, resource, role, user, user_role}; pub use user_plugin::{rand_str, AccessCore, AccessLevel, Token, UserPlugin}; use crate::AppState; diff --git a/oaweb/public/doc/markdown.md b/oaweb/public/doc/markdown.md index 4b14f3a..90093b1 100644 --- a/oaweb/public/doc/markdown.md +++ b/oaweb/public/doc/markdown.md @@ -1,8 +1,6 @@ +[[toc]] # 例子 # Markdown { 简明手册 | jiǎn míng shǒu cè } - -[[toc]] - # 基本语法 --- diff --git a/oaweb/quasar.config.js b/oaweb/quasar.config.js index d3d726d..d5170bc 100644 --- a/oaweb/quasar.config.js +++ b/oaweb/quasar.config.js @@ -76,7 +76,7 @@ module.exports = configure(function(/* ctx */) { // rebuildCache: true, // rebuilds Vite/linter/etc cache on startup - // publicPath: '/', + publicPath: '/', // analyze: true, // env: {}, // rawDefine: {} diff --git a/oaweb/src/boot/api/access.ts b/oaweb/src/boot/api/access.ts new file mode 100644 index 0000000..ab0a777 --- /dev/null +++ b/oaweb/src/boot/api/access.ts @@ -0,0 +1,30 @@ +/* + * access.ts + * Copyright (C) 2023 veypi + * 2023-10-12 19:32 + * Distributed under terms of the MIT license. + */ + + +import ajax from './axios' + +export default (app_id: string) => { + return { + local: `./app/${app_id}/access/`, + create(name: string, props?: { name?: string, level?: number, role_id?: string, user_id?: string, rid?: string }) { + return ajax.post(this.local, Object.assign({ name, level: 0 }, props)) + }, + get(id: string) { + return ajax.get(this.local + id) + }, + list(props?: { name?: string, role_id?: string, user_id?: string }) { + return ajax.get(this.local, props) + }, + update(uuid: string, props: any) { + return ajax.patch(this.local + uuid, props) + }, + del(id: string) { + return ajax.delete(this.local + id) + }, + } +} diff --git a/oaweb/src/boot/api/index.ts b/oaweb/src/boot/api/index.ts index 215d0a5..4158b3c 100644 --- a/oaweb/src/boot/api/index.ts +++ b/oaweb/src/boot/api/index.ts @@ -6,16 +6,21 @@ */ import app from "./app"; +import role from "./role"; import token from "./token"; import user from "./user"; - +import resource from "./resource"; +import access from './access'; const api = { - user: user, - app: app, - token: token + user, + app, + token, + role, + resource, + access, } diff --git a/oaweb/src/boot/api/resource.ts b/oaweb/src/boot/api/resource.ts new file mode 100644 index 0000000..39c00fd --- /dev/null +++ b/oaweb/src/boot/api/resource.ts @@ -0,0 +1,30 @@ +/* + * resource.ts + * Copyright (C) 2023 veypi + * 2023-10-12 18:03 + * Distributed under terms of the MIT license. + */ + + +import ajax from './axios' + +export default (app_id: string) => { + return { + local: `./app/${app_id}/resource/`, + create(name: string, props?: { des?: string }) { + return ajax.post(this.local, Object.assign({ name }, props)) + }, + get(id: string) { + return ajax.get(this.local + id) + }, + list() { + return ajax.get(this.local) + }, + update(uuid: string, props: any) { + return ajax.patch(this.local + uuid, props) + }, + del(id: string) { + return ajax.delete(this.local + id) + }, + } +} diff --git a/oaweb/src/boot/api/role.ts b/oaweb/src/boot/api/role.ts new file mode 100644 index 0000000..583ab10 --- /dev/null +++ b/oaweb/src/boot/api/role.ts @@ -0,0 +1,36 @@ +/* + * role.ts + * Copyright (C) 2023 veypi + * 2023-10-12 15:40 + * Distributed under terms of the MIT license. + */ + + +import ajax from './axios' + +export default (app_id: string) => { + return { + local: `./app/${app_id}/role/`, + create(name: string, props?: { des?: string }) { + return ajax.post(this.local, Object.assign({ name }, props)) + }, + get(id: string) { + return ajax.get(this.local + id) + }, + list() { + return ajax.get(this.local) + }, + update(uuid: string, props: any) { + return ajax.patch(this.local + uuid, props) + }, + del(id: string) { + return ajax.delete(this.local + id) + }, + add(id: string, uid: string) { + return ajax.get(this.local + `${id}/user/${uid}`) + }, + drop(id: string, uid: string) { + return ajax.delete(this.local + `${id}/user/${uid}`) + } + } +} diff --git a/oaweb/src/boot/api/user.ts b/oaweb/src/boot/api/user.ts index bfbb63f..7a679b3 100644 --- a/oaweb/src/boot/api/user.ts +++ b/oaweb/src/boot/api/user.ts @@ -31,10 +31,10 @@ export default { get(id: number) { return ajax.get(this.local + id) }, - list() { - return ajax.get(this.local) + list(props?: { name?: string, role_id?: string, app_id?: string }) { + return ajax.get(this.local, props) }, - update(id: number, props: any) { + update(id: string, props: any) { return ajax.patch(this.local + id, props) }, } diff --git a/oaweb/src/components/crud.vue b/oaweb/src/components/crud.vue index a039c59..88cc8e1 100644 --- a/oaweb/src/components/crud.vue +++ b/oaweb/src/components/crud.vue @@ -9,7 +9,8 @@
@@ -20,17 +21,19 @@
+ cstyle.width[k.name], cstyle.v, cstyle.kv[k.name])">
@@ -42,7 +45,7 @@ diff --git a/oaweb/src/pages/AppCfg.vue b/oaweb/src/pages/AppCfg.vue index e5a6cd6..52c32e5 100644 --- a/oaweb/src/pages/AppCfg.vue +++ b/oaweb/src/pages/AppCfg.vue @@ -7,7 +7,7 @@