From 664bf9c922db00fb3d367eafd091a803df3a93d0 Mon Sep 17 00:00:00 2001 From: veypi Date: Thu, 5 Oct 2023 15:30:40 +0800 Subject: [PATCH] update --- oab/Cargo.lock | 232 +- oab/Cargo.toml | 5 + oab/src/api/app.rs | 9 +- oab/src/api/mod.rs | 17 +- oab/src/api/upload.rs | 92 + oab/src/api/user.rs | 4 +- oab/src/cfg.rs | 8 +- oab/src/libs/fs.rs | 121 ++ oab/src/libs/mod.rs | 1 + oab/src/libs/user.rs | 21 +- oab/src/main.rs | 8 +- oab/src/models/entity/access.rs | 1 - oab/src/models/entity/app.rs | 1 - oab/src/models/entity/resource.rs | 1 - oab/src/models/entity/role.rs | 1 - oab/src/models/entity/user.rs | 1 - oab/src/result.rs | 1 + oaweb/package.json | 2 + oaweb/quasar.config.js | 3 +- oaweb/src/App.vue | 16 + oaweb/src/components/EssentialLink.vue | 26 +- oaweb/src/components/app.vue | 5 +- oaweb/src/components/menu.vue | 30 + oaweb/src/components/uploader/uploader.vue | 89 +- oaweb/src/layouts/AppLayout.vue | 53 + oaweb/src/layouts/MainLayout.vue | 80 +- oaweb/src/libs/util.ts | 135 +- oaweb/src/models/index.ts | 8 + oaweb/src/oaer/package.json | 28 + oaweb/src/oaer/postcss.config.js | 6 + oaweb/src/oaer/src/api/ajax.ts | 86 + oaweb/src/oaer/src/api/app.ts | 31 + oaweb/src/oaer/src/api/index.ts | 18 + oaweb/src/oaer/src/api/interface.ts | 65 + oaweb/src/oaer/src/api/setting.ts | 22 + oaweb/src/oaer/src/api/user.ts | 33 + oaweb/src/oaer/src/assets/icon.js | 1 + oaweb/src/oaer/src/components/app.vue | 36 + oaweb/src/oaer/src/components/file.vue | 47 + oaweb/src/oaer/src/components/user.vue | 7 + oaweb/src/oaer/src/evt/index.ts | 12 + oaweb/src/oaer/src/frame.vue | 91 + oaweb/src/oaer/src/index.ts | 24 + oaweb/src/oaer/src/libs/webdav/auth/basic.ts | 7 + oaweb/src/oaer/src/libs/webdav/auth/digest.ts | 82 + oaweb/src/oaer/src/libs/webdav/auth/index.ts | 36 + oaweb/src/oaer/src/libs/webdav/auth/oauth.ts | 5 + .../src/libs/webdav/compat/arrayBuffer.ts | 10 + .../src/oaer/src/libs/webdav/compat/buffer.ts | 8 + .../oaer/src/libs/webdav/compat/patcher.ts | 10 + oaweb/src/oaer/src/libs/webdav/factory.ts | 114 + oaweb/src/oaer/src/libs/webdav/index.ts | 5 + .../src/libs/webdav/operations/copyFile.ts | 26 + .../libs/webdav/operations/createDirectory.ts | 81 + .../libs/webdav/operations/createStream.ts | 109 + .../libs/webdav/operations/customRequest.ts | 19 + .../src/libs/webdav/operations/deleteFile.ts | 22 + .../webdav/operations/directoryContents.ts | 78 + .../oaer/src/libs/webdav/operations/exists.ts | 18 + .../libs/webdav/operations/getFileContents.ts | 102 + .../src/libs/webdav/operations/getQuota.ts | 30 + .../oaer/src/libs/webdav/operations/lock.ts | 79 + .../src/libs/webdav/operations/moveFile.ts | 26 + .../libs/webdav/operations/putFileContents.ts | 94 + .../oaer/src/libs/webdav/operations/stat.ts | 32 + oaweb/src/oaer/src/libs/webdav/request.ts | 108 + oaweb/src/oaer/src/libs/webdav/response.ts | 46 + .../src/oaer/src/libs/webdav/tools/crypto.ts | 16 + oaweb/src/oaer/src/libs/webdav/tools/dav.ts | 171 ++ .../src/oaer/src/libs/webdav/tools/encode.ts | 24 + .../src/oaer/src/libs/webdav/tools/headers.ts | 18 + oaweb/src/oaer/src/libs/webdav/tools/merge.ts | 62 + oaweb/src/oaer/src/libs/webdav/tools/path.ts | 36 + oaweb/src/oaer/src/libs/webdav/tools/quota.ts | 22 + oaweb/src/oaer/src/libs/webdav/tools/size.ts | 22 + oaweb/src/oaer/src/libs/webdav/tools/url.ts | 32 + oaweb/src/oaer/src/libs/webdav/tools/xml.ts | 55 + oaweb/src/oaer/src/libs/webdav/types.ts | 288 +++ oaweb/src/oaer/src/main.vue | 121 ++ oaweb/src/oaer/src/models/index.ts | 126 ++ oaweb/src/oaer/src/theme/index.ts | 72 + oaweb/src/oaer/tailwind.config.js | 11 + oaweb/src/oaer/tsconfig.json | 15 + oaweb/src/oaer/vite.config.ts | 7 + oaweb/src/oaer/yarn.lock | 1904 +++++++++++++++++ oaweb/src/pages/404.vue | 37 + oaweb/src/pages/AppHome.vue | 23 + oaweb/src/pages/IndexPage.vue | 39 +- oaweb/src/router/routes.ts | 30 +- oaweb/src/stores/app.ts | 5 + oaweb/src/stores/menu.ts | 47 + oaweb/yarn.lock | 14 +- 92 files changed, 5600 insertions(+), 222 deletions(-) create mode 100644 oab/src/api/upload.rs create mode 100644 oab/src/libs/fs.rs create mode 100644 oaweb/src/components/menu.vue create mode 100644 oaweb/src/layouts/AppLayout.vue create mode 100644 oaweb/src/oaer/package.json create mode 100644 oaweb/src/oaer/postcss.config.js create mode 100644 oaweb/src/oaer/src/api/ajax.ts create mode 100644 oaweb/src/oaer/src/api/app.ts create mode 100644 oaweb/src/oaer/src/api/index.ts create mode 100644 oaweb/src/oaer/src/api/interface.ts create mode 100644 oaweb/src/oaer/src/api/setting.ts create mode 100644 oaweb/src/oaer/src/api/user.ts create mode 100644 oaweb/src/oaer/src/assets/icon.js create mode 100644 oaweb/src/oaer/src/components/app.vue create mode 100644 oaweb/src/oaer/src/components/file.vue create mode 100644 oaweb/src/oaer/src/components/user.vue create mode 100644 oaweb/src/oaer/src/evt/index.ts create mode 100644 oaweb/src/oaer/src/frame.vue create mode 100644 oaweb/src/oaer/src/index.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/auth/basic.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/auth/digest.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/auth/index.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/auth/oauth.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/compat/arrayBuffer.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/compat/buffer.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/compat/patcher.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/factory.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/index.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/copyFile.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/createDirectory.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/createStream.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/customRequest.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/deleteFile.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/directoryContents.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/exists.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/getFileContents.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/getQuota.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/lock.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/moveFile.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/putFileContents.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/operations/stat.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/request.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/response.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/tools/crypto.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/tools/dav.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/tools/encode.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/tools/headers.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/tools/merge.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/tools/path.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/tools/quota.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/tools/size.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/tools/url.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/tools/xml.ts create mode 100644 oaweb/src/oaer/src/libs/webdav/types.ts create mode 100644 oaweb/src/oaer/src/main.vue create mode 100644 oaweb/src/oaer/src/models/index.ts create mode 100644 oaweb/src/oaer/src/theme/index.ts create mode 100644 oaweb/src/oaer/tailwind.config.js create mode 100644 oaweb/src/oaer/tsconfig.json create mode 100644 oaweb/src/oaer/vite.config.ts create mode 100644 oaweb/src/oaer/yarn.lock create mode 100644 oaweb/src/pages/404.vue create mode 100644 oaweb/src/pages/AppHome.vue create mode 100644 oaweb/src/stores/menu.ts diff --git a/oab/Cargo.lock b/oab/Cargo.lock index 36824bf..5a070d2 100644 --- a/oab/Cargo.lock +++ b/oab/Cargo.lock @@ -91,6 +91,44 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "actix-multipart" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b960e2aea75f49c8f069108063d12a48d329fc8b60b786dfc7552a9d5918d2d" +dependencies = [ + "actix-multipart-derive", + "actix-utils", + "actix-web", + "bytes", + "derive_more", + "futures-core", + "futures-util", + "httparse", + "local-waker", + "log", + "memchr", + "mime", + "serde", + "serde_json", + "serde_plain", + "tempfile", + "tokio", +] + +[[package]] +name = "actix-multipart-derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a0a77f836d869f700e5b47ac7c3c8b9c8bc82e4aec861954c6198abee3ebd4d" +dependencies = [ + "darling", + "parse-size", + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "actix-router" version = "0.5.1" @@ -822,6 +860,73 @@ dependencies = [ "cipher", ] +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.37", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "dav-server" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c1b3c57ea8b45dc1303de4653b12e3a2742ff023a469083716feea98abfdbe" +dependencies = [ + "actix-web", + "bytes", + "futures-channel", + "futures-util", + "headers", + "htmlescape", + "http", + "http-body", + "lazy_static", + "libc", + "log", + "lru", + "mime_guess", + "parking_lot 0.12.1", + "percent-encoding", + "pin-project", + "pin-utils", + "regex", + "time", + "tokio", + "url", + "uuid", + "xml-rs", + "xmltree", +] + [[package]] name = "der" version = "0.5.1" @@ -927,9 +1032,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480" dependencies = [ "errno-dragonfly", "libc", @@ -1238,6 +1343,30 @@ dependencies = [ "hashbrown 0.14.1", ] +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.4", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + [[package]] name = "heck" version = "0.4.1" @@ -1295,6 +1424,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "htmlescape" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" + [[package]] name = "http" version = "0.2.9" @@ -1306,6 +1441,26 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-auth-basic" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e17aacf7f4a2428def798e2ff4f4f883c0987bdaf47dd5c8bc027bc9f1ebc" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + [[package]] name = "http-range" version = "0.1.5" @@ -1347,6 +1502,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.4.0" @@ -1549,6 +1710,15 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "lru" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" +dependencies = [ + "hashbrown 0.14.1", +] + [[package]] name = "md-5" version = "0.10.6" @@ -1561,9 +1731,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.3" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "mime" @@ -1713,14 +1883,18 @@ name = "oab" version = "0.1.0" dependencies = [ "actix-files", + "actix-multipart", "actix-web", "aes-gcm", "base64 0.13.1", "block-padding", "chrono", "clap", + "dav-server", "futures-util", "generic-array", + "http", + "http-auth-basic", "include_dir", "jsonwebtoken", "lazy_static", @@ -1854,6 +2028,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "parse-size" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae" + [[package]] name = "paste" version = "1.0.14" @@ -1893,6 +2073,26 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2488,6 +2688,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_plain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" +dependencies = [ + "serde", +] + [[package]] name = "serde_repr" version = "0.1.16" @@ -3631,6 +3840,21 @@ dependencies = [ "tap", ] +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" + +[[package]] +name = "xmltree" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" +dependencies = [ + "xml-rs", +] + [[package]] name = "zeroize" version = "1.6.0" diff --git a/oab/Cargo.toml b/oab/Cargo.toml index 4703044..b57f209 100644 --- a/oab/Cargo.toml +++ b/oab/Cargo.toml @@ -41,4 +41,9 @@ uuid = { version = "1.1", features = ["v3","v4", "fast-rng", "macro-diagnostics" serde_repr = "0.1.8" proc = {path="proc"} +# dav-server = {version = "0.5.7", features = ["default","actix-compat"], path = "../../../test/dav-server-rs/" } +dav-server = {version = "0.5.7", features = ["default","actix-compat"]} +http = "0.2.9" +http-auth-basic = "0.3.3" +actix-multipart = "0.6.1" diff --git a/oab/src/api/app.rs b/oab/src/api/app.rs index 010d558..9b4923e 100644 --- a/oab/src/api/app.rs +++ b/oab/src/api/app.rs @@ -12,6 +12,7 @@ use serde::{Deserialize, Serialize}; use tracing::info; use crate::{ + libs, models::{self, access, app, app_user, rand_str, AUStatus, AccessLevel, Token}, AppState, Error, Result, }; @@ -101,13 +102,7 @@ pub async fn create( ..Default::default() }; let ac: access::Model = ac.insert(&db).await?; - let au = app_user::ActiveModel { - app_id: sea_orm::ActiveValue::Set(obj.id.clone()), - user_id: sea_orm::ActiveValue::Set(t.id.clone()), - status: sea_orm::ActiveValue::Set(AUStatus::OK as i32), - ..Default::default() - }; - let au: app_user::Model = au.insert(&db).await?; + libs::user::connect_to_app(t.id.clone(), obj.id.clone(), &db, Some(obj.clone())).await?; db.commit().await?; Ok(web::Json(obj)) } diff --git a/oab/src/api/mod.rs b/oab/src/api/mod.rs index 756ad74..49f3289 100644 --- a/oab/src/api/mod.rs +++ b/oab/src/api/mod.rs @@ -11,21 +11,12 @@ mod app; mod appuser; mod resource; mod role; +mod upload; mod user; -use crate::{Error, Result}; -use actix_web::{get, web}; - -#[get("/hello/{name}")] -async fn greet(name: web::Path) -> Result { - let n = name.into_inner(); - if n > 0 { - Ok(format!("Hello {n}!")) - } else { - Err(Error::Unknown) - } -} +use actix_web::web; pub fn routes(cfg: &mut web::ServiceConfig) { + cfg.service(upload::save_files); cfg.service(user::get) .service(user::list) .service(user::register) @@ -37,6 +28,4 @@ pub fn routes(cfg: &mut web::ServiceConfig) { .service(app::del); cfg.service(appuser::get); - - cfg.service(greet); } diff --git a/oab/src/api/upload.rs b/oab/src/api/upload.rs new file mode 100644 index 0000000..c3324c1 --- /dev/null +++ b/oab/src/api/upload.rs @@ -0,0 +1,92 @@ +// +// upload.rs +// Copyright (C) 2023 veypi +// 2023-10-03 21:50 +// Distributed under terms of the MIT license. +// +// + +use actix_multipart::form::{tempfile::TempFile, MultipartForm}; +use actix_web::{post, web, Responder}; +use proc::access_read; +use tracing::{info, warn}; + +use crate::{AppState, Error, Result}; + +#[derive(Debug, MultipartForm)] +struct UploadForm { + files: Vec, +} + +#[post("/upload/")] +#[access_read("app")] +async fn save_files( + MultipartForm(form): MultipartForm, + stat: web::Data, +) -> Result { + let l = form.files.len(); + let mut res: Vec = Vec::new(); + info!("!|||||||||||_{}_|", l); + for f in form.files { + info!("saving to {:#?}", f); + let fname = f.file_name.unwrap(); + let path = format!("{}tmp/{}", stat.media_path, fname); + info!("saving to {path}"); + match f.file.persist(path) { + Ok(t) => { + info!("{:#?}", t); + res.push(format!("/media/tmp/{}", fname)) + } + Err(e) => { + warn!("{}", e); + return Err(Error::InternalServerError); + } + }; + } + + Ok(web::Json(res)) +} + +// #[actix_web::main] +// async fn main() -> std::io::Result<()> { +// HttpServer::new(|| { +// App::new() +// .wrap(middleware::Logger::default()) +// .app_data(TempFileConfig::default().directory("./tmp")) +// .service( +// web::resource("/") +// .route(web::get().to(index)) +// .route(web::post().to(save_files)), +// ) +// }) +// .bind(("127.0.0.1", 8080))? +// .workers(2) +// .run() +// .await +// } + +// /// Example of the old manual way of processing multipart forms. +// #[allow(unused)] +// async fn save_file_manual(mut payload: Multipart) -> Result { +// // iterate over multipart stream +// while let Some(mut field) = payload.try_next().await? { +// // A multipart/form-data stream has to contain `content_disposition` +// let content_disposition = field.content_disposition(); + +// let filename = content_disposition +// .get_filename() +// .map_or_else(|| Uuid::new_v4().to_string(), sanitize_filename::sanitize); +// let filepath = format!("./tmp/{filename}"); + +// // File::create is blocking operation, use threadpool +// let mut f = web::block(|| std::fs::File::create(filepath)).await??; + +// // Field in turn is stream of *Bytes* object +// while let Some(chunk) = field.try_next().await? { +// // filesystem operations are blocking, we have to use threadpool +// f = web::block(move || f.write_all(&chunk).map(|_| f)).await??; +// } +// } + +// Ok(HttpResponse::Ok().into()) +// } diff --git a/oab/src/api/user.rs b/oab/src/api/user.rs index 76359c1..4eab3ed 100644 --- a/oab/src/api/user.rs +++ b/oab/src/api/user.rs @@ -95,7 +95,7 @@ pub async fn login( // 未绑定应用时进行绑定操作 let aid = stat.uuid.clone(); let db = stat.db().begin().await?; - let s = libs::user::connect_to_app(u.clone(), aid, &db).await?; + let s = libs::user::connect_to_app(u.id.clone(), aid, &db, None).await?; db.commit().await?; s } @@ -165,7 +165,7 @@ pub async fn register( let u = u.insert(&db).await?; // 关联应用 - libs::user::connect_to_app(u.clone(), stat.uuid.clone(), &db).await?; + libs::user::connect_to_app(u.id.clone(), stat.uuid.clone(), &db, None).await?; db.commit().await?; diff --git a/oab/src/cfg.rs b/oab/src/cfg.rs index 7b3120d..591aa16 100644 --- a/oab/src/cfg.rs +++ b/oab/src/cfg.rs @@ -18,6 +18,7 @@ use clap::{Args, Parser, Subcommand}; use lazy_static::lazy_static; use sea_orm::{ConnectOptions, Database, DatabaseConnection}; use sqlx::{mysql::MySqlPoolOptions, Pool}; +use tracing::Level; use crate::Result; @@ -76,6 +77,7 @@ pub struct AppState { pub db_pass: String, pub db_name: String, pub log_dir: Option, + pub fs_root: String, /// "100MB" 日志分割尺寸-单位KB,MB,GB pub log_temp_size: Option, pub log_pack_compress: Option, @@ -119,7 +121,6 @@ impl AppState { key: "AMpjwQHwVjGsb1WC4WG6".to_string(), debug: true, server_url: "127.0.0.1:4001".to_string(), - media_path: "/Users/veypi/test/media/".to_string(), db_url: "localhost:3306".to_string(), db_user: "root".to_string(), db_pass: "123456".to_string(), @@ -127,6 +128,8 @@ impl AppState { log_dir: None, log_temp_size: None, log_pack_compress: None, + media_path: "/Users/veypi/test/media/".to_string(), + fs_root: "/Users/veypi/test/media/".to_string(), log_level: None, jwt_secret: None, _sqlx: None, @@ -192,5 +195,8 @@ pub fn init_log() { tracing_subscriber::fmt() .with_line_number(true) .with_timer(FormatTime {}) + .with_max_level(Level::DEBUG) + .with_target(false) + .with_file(true) .init(); } diff --git a/oab/src/libs/fs.rs b/oab/src/libs/fs.rs new file mode 100644 index 0000000..c879892 --- /dev/null +++ b/oab/src/libs/fs.rs @@ -0,0 +1,121 @@ +// +// fs.rs +// Copyright (C) 2023 veypi +// 2023-10-02 22:51 +// Distributed under terms of the MIT license. +// +// + +use std::{fs, path::Path}; + +use actix_web::web; + +use dav_server::{ + actix::{DavRequest, DavResponse}, + body::Body, + fakels::FakeLs, + localfs::LocalFs, + DavConfig, DavHandler, +}; + +use http::Response; +use http_auth_basic::Credentials; +use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; +use tracing::{info, warn}; + +use crate::{ + models::{self, UserPlugin}, + AppState, Error, Result, +}; + +pub fn core() -> DavHandler { + DavHandler::builder() + .locksystem(FakeLs::new()) + .strip_prefix("/file/") + .build_handler() +} + +pub async fn dav_handler( + req: DavRequest, + davhandler: web::Data, + stat: web::Data, +) -> DavResponse { + let root = stat.fs_root.clone(); + match handle_file(req, stat).await { + Ok((p, req)) => { + let p = Path::new(&root).join(p); + if !p.exists() { + match fs::create_dir_all(p.clone()) { + Ok(_) => {} + Err(e) => { + warn!("{}", e); + } + } + } + info!("mount {}", p.to_str().unwrap()); + let config = DavConfig::new().filesystem(LocalFs::new(p, false, false, true)); + davhandler.handle_with(config, req.request).await.into() + } + Err(e) => { + warn!("handle file failed: {}", e); + Response::builder() + .status(401) + .header("WWW-Authenticate", "Basic realm=\"file\"") + .body(Body::from("please auth".to_string())) + .unwrap() + .into() + } + } +} + +async fn handle_file(req: DavRequest, stat: web::Data) -> Result<(String, DavRequest)> { + let p = req.request.uri(); + let headers = req.request.headers(); + let m = req.request.method(); + // handle_authorization(req.request.headers()); + info!("access {} to {}", m, p); + let auth_token = headers.get("auth_token"); + let authorization = headers.get("authorization"); + let app_id = match headers.get("app_id") { + Some(i) => i.to_str().unwrap_or(""), + None => "", + }; + match auth_token { + Some(t) => match models::Token::from(t.to_str().unwrap_or("")) { + Ok(t) => { + if t.is_valid() { + if app_id != "" { + // 只有秘钥才能访问app数据 + if t.can_read("app", app_id) { + return Ok((format!("app/{}/", app_id), req)); + } + } else { + return Ok((format!("user/{}/", t.id), req)); + } + } + } + Err(_) => {} + }, + None => {} + } + match authorization { + Some(au) => { + let credentials = + Credentials::from_header(au.to_str().unwrap_or("").to_string()).unwrap(); + info!("{}|{}", credentials.user_id, credentials.password); + match models::user::Entity::find() + .filter(models::user::Column::Username.eq(credentials.user_id)) + .one(stat.db()) + .await? + { + Some(u) => { + u.check_pass(&credentials.password)?; + return Ok((format!("user/{}/", u.id), req)); + } + None => {} + } + } + None => {} + } + Err(Error::NotAuthed) +} diff --git a/oab/src/libs/mod.rs b/oab/src/libs/mod.rs index adc0c35..abdb53a 100644 --- a/oab/src/libs/mod.rs +++ b/oab/src/libs/mod.rs @@ -7,6 +7,7 @@ pub mod auth; pub mod user; +pub mod fs; use std::future::{ready, Ready}; diff --git a/oab/src/libs/user.rs b/oab/src/libs/user.rs index 5bf00cb..509268c 100644 --- a/oab/src/libs/user.rs +++ b/oab/src/libs/user.rs @@ -6,21 +6,24 @@ // use crate::{ - models::{self, app, app_user, user, user_role}, + models::{self, app, app_user, user_role}, Error, Result, }; use sea_orm::{ActiveModelTrait, ConnectionTrait, DatabaseTransaction, EntityTrait}; // 尝试绑定应用 pub async fn connect_to_app( - u: user::Model, + uid: String, aid: String, db: &DatabaseTransaction, + app_obj: Option, ) -> Result { - let app_obj: Option = app::Entity::find_by_id(&aid).one(db).await?; let app_obj = match app_obj { Some(o) => o, - None => return Err(Error::NotFound(aid.clone())), + None => match app::Entity::find_by_id(&aid).one(db).await? { + Some(o) => o, + None => return Err(Error::NotFound(aid.clone())), + }, }; let m = match app_obj.join_method.into() { models::AppJoin::Disabled => return Err(Error::AppDisabledRegister), @@ -29,26 +32,26 @@ pub async fn connect_to_app( }; let au = app_user::ActiveModel { app_id: sea_orm::ActiveValue::Set(aid.clone()), - user_id: sea_orm::ActiveValue::Set(u.id.clone()), + user_id: sea_orm::ActiveValue::Set(uid.clone()), status: sea_orm::ActiveValue::Set(m.clone() as i32), ..Default::default() }; let au = au.insert(db).await?; if m == models::AUStatus::OK { - after_connected_to_app(u, app_obj, db).await?; + after_connected_to_app(uid, app_obj, db).await?; } Ok(au) } // 成功绑定应用后操作 pub async fn after_connected_to_app( - u: user::Model, + uid: String, obj: app::Model, db: &DatabaseTransaction, ) -> Result<()> { if obj.role_id.is_some() { user_role::ActiveModel { - user_id: sea_orm::ActiveValue::Set(u.id.clone()), + user_id: sea_orm::ActiveValue::Set(uid.clone()), role_id: sea_orm::ActiveValue::Set(obj.role_id.unwrap().clone()), ..Default::default() } @@ -56,7 +59,7 @@ pub async fn after_connected_to_app( .await?; }; let sql = format!( - "update app set user_count = user_count + 1 where app_id = {}", + "update app set user_count = user_count + 1 where id = '{}'", obj.id ); db.execute(sea_orm::Statement::from_string( diff --git a/oab/src/main.rs b/oab/src/main.rs index cac2a08..8f7d5f5 100644 --- a/oab/src/main.rs +++ b/oab/src/main.rs @@ -38,6 +38,7 @@ async fn main() -> Result<()> { } async fn web(data: AppState) -> Result<()> { let url = data.server_url.clone(); + let dav = libs::fs::core(); let serv = HttpServer::new(move || { let logger = middleware::Logger::default(); let json_config = web::JsonConfig::default() @@ -55,10 +56,10 @@ async fn web(data: AppState) -> Result<()> { let app = App::new(); app.wrap(logger) .wrap(middleware::Compress::default()) + .app_data(web::Data::new(data.clone())) .service(fs::Files::new("/media", data.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), @@ -67,6 +68,11 @@ async fn web(data: AppState) -> Result<()> { .app_data(json_config) .configure(api::routes), ) + .service( + web::scope("file") + .app_data(web::Data::new(dav.clone())) + .service(web::resource("/{tail:.*}").to(libs::fs::dav_handler)), + ) }); info!("listen to {}", url); serv.bind(url)?.run().await?; diff --git a/oab/src/models/entity/access.rs b/oab/src/models/entity/access.rs index a730945..c8e7a60 100644 --- a/oab/src/models/entity/access.rs +++ b/oab/src/models/entity/access.rs @@ -12,7 +12,6 @@ pub struct Model { pub id: i32, pub created: Option, pub updated: Option, - pub delete_flag: i8, pub app_id: String, pub name: String, pub role_id: Option, diff --git a/oab/src/models/entity/app.rs b/oab/src/models/entity/app.rs index 1ad31a2..3dfc281 100644 --- a/oab/src/models/entity/app.rs +++ b/oab/src/models/entity/app.rs @@ -12,7 +12,6 @@ pub struct Model { pub id: String, pub created: Option, pub updated: Option, - pub delete_flag: i8, pub key: String, pub name: String, pub icon: Option, diff --git a/oab/src/models/entity/resource.rs b/oab/src/models/entity/resource.rs index bfd4575..bc8e6dd 100644 --- a/oab/src/models/entity/resource.rs +++ b/oab/src/models/entity/resource.rs @@ -10,7 +10,6 @@ use serde::{Deserialize, Serialize}; pub struct Model { pub created: Option, pub updated: Option, - pub delete_flag: i8, #[sea_orm(primary_key, auto_increment = false)] pub app_id: String, #[sea_orm(primary_key, auto_increment = false)] diff --git a/oab/src/models/entity/role.rs b/oab/src/models/entity/role.rs index ee150ec..d451509 100644 --- a/oab/src/models/entity/role.rs +++ b/oab/src/models/entity/role.rs @@ -12,7 +12,6 @@ pub struct Model { pub id: String, pub created: Option, pub updated: Option, - pub delete_flag: i8, pub app_id: String, pub name: String, pub des: Option, diff --git a/oab/src/models/entity/user.rs b/oab/src/models/entity/user.rs index 833c7b0..f31248c 100644 --- a/oab/src/models/entity/user.rs +++ b/oab/src/models/entity/user.rs @@ -12,7 +12,6 @@ pub struct Model { pub id: String, pub created: Option, pub updated: Option, - pub delete_flag: i8, #[sea_orm(unique)] pub username: String, pub nickname: Option, diff --git a/oab/src/result.rs b/oab/src/result.rs index d7fb833..7e1f8e7 100644 --- a/oab/src/result.rs +++ b/oab/src/result.rs @@ -168,6 +168,7 @@ impl From> for Error { } } + impl actix_web::Responder for Error { type Body = actix_web::body::BoxBody; fn respond_to(self, _req: &actix_web::HttpRequest) -> HttpResponse { diff --git a/oaweb/package.json b/oaweb/package.json index 810850e..fde7882 100644 --- a/oaweb/package.json +++ b/oaweb/package.json @@ -15,8 +15,10 @@ "dependencies": { "@quasar/extras": "^1.16.4", "@veypi/msg": "^0.1.0", + "@veypi/one-icon": "2", "axios": "^1.2.1", "js-base64": "^3.7.5", + "mitt": "^3.0.1", "pinia": "^2.0.11", "quasar": "^2.6.0", "vue": "^3.0.0", diff --git a/oaweb/quasar.config.js b/oaweb/quasar.config.js index b7a2d28..011106f 100644 --- a/oaweb/quasar.config.js +++ b/oaweb/quasar.config.js @@ -145,7 +145,8 @@ module.exports = configure(function(/* ctx */) { // Quasar plugins plugins: [ - 'LoadingBar' + 'LoadingBar', + 'AppFullscreen', ] }, diff --git a/oaweb/src/App.vue b/oaweb/src/App.vue index d689f51..a21417d 100644 --- a/oaweb/src/App.vue +++ b/oaweb/src/App.vue @@ -30,3 +30,19 @@ onBeforeMount(() => { }) + + diff --git a/oaweb/src/components/EssentialLink.vue b/oaweb/src/components/EssentialLink.vue index 13205c2..c2658be 100644 --- a/oaweb/src/components/EssentialLink.vue +++ b/oaweb/src/components/EssentialLink.vue @@ -1,34 +1,22 @@ diff --git a/oaweb/src/components/app.vue b/oaweb/src/components/app.vue index 1dc7e37..35e00ed 100644 --- a/oaweb/src/components/app.vue +++ b/oaweb/src/components/app.vue @@ -2,7 +2,8 @@
- + +
@@ -36,7 +37,7 @@ let props = withDefaults(defineProps<{ function Go() { switch (props.core.au.status) { case AUStatus.OK: - router.push({ name: "app.main", params: { uuid: props.core.UUID } }); + router.push({ name: "app.home", params: { id: props.core.id } }); return; case AUStatus.Applying: msg.Info("请等待管理员审批进入"); diff --git a/oaweb/src/components/menu.vue b/oaweb/src/components/menu.vue new file mode 100644 index 0000000..2528e43 --- /dev/null +++ b/oaweb/src/components/menu.vue @@ -0,0 +1,30 @@ + + + + + + + diff --git a/oaweb/src/components/uploader/uploader.vue b/oaweb/src/components/uploader/uploader.vue index 27e0796..9a51918 100644 --- a/oaweb/src/components/uploader/uploader.vue +++ b/oaweb/src/components/uploader/uploader.vue @@ -1,56 +1,87 @@ diff --git a/oaweb/src/layouts/AppLayout.vue b/oaweb/src/layouts/AppLayout.vue new file mode 100644 index 0000000..c56c647 --- /dev/null +++ b/oaweb/src/layouts/AppLayout.vue @@ -0,0 +1,53 @@ + + + + + + + diff --git a/oaweb/src/layouts/MainLayout.vue b/oaweb/src/layouts/MainLayout.vue index d61f00d..fd0d56d 100644 --- a/oaweb/src/layouts/MainLayout.vue +++ b/oaweb/src/layouts/MainLayout.vue @@ -1,38 +1,42 @@