From ea7977b124a9900f16e44b8cd0e3bd6c4170b6c0 Mon Sep 17 00:00:00 2001 From: Fankai Liu Date: Sat, 21 Oct 2023 14:10:48 +0800 Subject: [PATCH] better web site --- src/template/src/main_template.hbs | 10 ++ src/template/src/middleware/jwt.rs | 1 + src/template/src/routers/mod.hbs | 114 ++++++++++++++++++---- src/template/src/routers/user.hbs | 113 ++++++++++++++------- src/template/src/services/user.hbs | 14 +-- src/template/templates/login.hbs | 87 ++++++++++++++++- src/template/templates/user_list.hbs | 84 ---------------- src/template/templates/user_list_page.hbs | 91 ++++++++++++++++- src/utils/create_project.rs | 2 +- src/utils/get_selection.rs | 6 +- 10 files changed, 362 insertions(+), 160 deletions(-) diff --git a/src/template/src/main_template.hbs b/src/template/src/main_template.hbs index a262acf..fa997b0 100644 --- a/src/template/src/main_template.hbs +++ b/src/template/src/main_template.hbs @@ -45,6 +45,11 @@ async fn main() { "swagger-ui: https://{}/swagger-ui", &CFG.server.address.replace("0.0.0.0", "127.0.0.1") ); + {{#if is_web_site}} + {{#if need_db_conn}} + println!("login page: https://{}/login", &CFG.server.address.replace("0.0.0.0", "127.0.0.1")); + {{/if}} + {{/if}} let config = RustlsConfig::new( Keycert::new() .cert(CERT_KEY.cert.clone()) @@ -68,6 +73,11 @@ async fn main() { "swagger-ui: http://{}/swagger-ui", &CFG.server.address.replace("0.0.0.0", "127.0.0.1") ); + {{#if is_web_site}} + {{#if need_db_conn}} + println!("login page: http://{}/login", &CFG.server.address.replace("0.0.0.0", "127.0.0.1")); + {{/if}} + {{/if}} let acceptor = TcpListener::new(&CFG.server.address).bind().await; let server = Server::new(acceptor).serve_with_graceful_shutdown( service, diff --git a/src/template/src/middleware/jwt.rs b/src/template/src/middleware/jwt.rs index b7088c4..cac61b0 100644 --- a/src/template/src/middleware/jwt.rs +++ b/src/template/src/middleware/jwt.rs @@ -13,6 +13,7 @@ pub struct JwtClaims { exp: i64, } +#[allow(dead_code)] pub fn jwt_hoop() -> JwtAuth { let auth_handler: JwtAuth = JwtAuth::new(ConstDecoder::from_secret( CFG.jwt.jwt_secret.to_owned().as_bytes(), diff --git a/src/template/src/routers/mod.hbs b/src/template/src/routers/mod.hbs index 39f1739..39b1a1c 100644 --- a/src/template/src/routers/mod.hbs +++ b/src/template/src/routers/mod.hbs @@ -1,33 +1,22 @@ {{#if need_db_conn}} + {{#if is_web_site}} use crate::middleware::jwt::jwt_hoop; -{{/if}} use salvo::{ prelude::{CatchPanic, Logger, OpenApi, SwaggerUi}, Router, }; + use self::{ demo::hello, -{{#if need_db_conn}} -{{#if is_web_site}} user::{ - delete_user,login_page, post_add_user, post_login, post_update_user, + delete_user, get_users, login_page, post_add_user, post_login, put_update_user, user_list_page, }, -{{else}} - user::{ - delete_user, get_users, post_add_user, post_login, post_update_user, - }, -{{/if}} -{{/if}} }; pub mod demo; -{{#if need_db_conn}} pub mod user; -{{/if}} pub fn router() -> Router { - {{#if is_web_site}} - {{#if need_db_conn}} let mut no_auth_routers = vec![ Router::with_path("login").get(login_page), Router::with_path("/api/login").post(post_login), @@ -35,12 +24,14 @@ pub fn router() -> Router { let mut need_auth_routers = vec![ Router::with_path("users") + .get(user_list_page), + Router::with_path("/api/users").get(get_users) .post(post_add_user) - .get(user_list_page), - Router::with_path("/api/users") - .get(get_users) - .put(post_update_user) - .push(Router::with_path("").delete(delete_user)), + .push( + Router::with_path("") + .put(put_update_user) + .delete(delete_user), + ), ]; let router = Router::new() .hoop(Logger::new()) @@ -52,10 +43,91 @@ pub fn router() -> Router { .append(&mut need_auth_routers) .hoop(jwt_hoop()), ); + let doc = OpenApi::new("salvo web api", "0.0.1").merge_router(&router); + router + .push(doc.into_router("/api-doc/openapi.json")) + .push(SwaggerUi::new("/api-doc/openapi.json").into_router("swagger-ui")) +} + {{else}} +use crate::middleware::jwt::jwt_hoop; +use salvo::{ + prelude::{CatchPanic, Logger, OpenApi, SwaggerUi}, + Router, +}; + +use self::{ + demo::hello, + user::{ + delete_user, get_users, post_add_user, post_login, put_update_user, + }, +}; +pub mod demo; +pub mod user; + +pub fn router() -> Router { + let mut no_auth_routers = vec![ + Router::with_path("/api/login").post(post_login), + ]; + + let mut need_auth_routers = vec![ + Router::with_path("/api/users").get(get_users) + .post(post_add_user) + .push( + Router::with_path("") + .put(put_update_user) + .delete(delete_user), + ), + ]; + let router = Router::new() + .hoop(Logger::new()) + .hoop(CatchPanic::new()) + .get(hello) + .append(&mut no_auth_routers) + .push( + Router::new() + .append(&mut need_auth_routers) + .hoop(jwt_hoop()), + ); + let doc = OpenApi::new("salvo web api", "0.0.1").merge_router(&router); + router + .push(doc.into_router("/api-doc/openapi.json")) + .push(SwaggerUi::new("/api-doc/openapi.json").into_router("swagger-ui")) +} {{/if}} - {{/if}} +{{else}} + {{#if is_web_site}} +use salvo::{ + prelude::{CatchPanic, Logger, OpenApi, SwaggerUi}, + Router, +}; +use self::demo::hello; +pub mod demo; +pub fn router() -> Router { + let router = Router::new() + .hoop(Logger::new()) + .hoop(CatchPanic::new()) + .get(hello); let doc = OpenApi::new("salvo web api", "0.0.1").merge_router(&router); router .push(doc.into_router("/api-doc/openapi.json")) .push(SwaggerUi::new("/api-doc/openapi.json").into_router("swagger-ui")) -} \ No newline at end of file +} + {{else}} +use salvo::{ + prelude::{CatchPanic, Logger, OpenApi, SwaggerUi}, + Router, +}; +use self::demo::hello; +pub mod demo; +pub fn router() -> Router { + let router = Router::new() + .hoop(Logger::new()) + .hoop(CatchPanic::new()) + .get(hello); + let doc = OpenApi::new("salvo web api", "0.0.1").merge_router(&router); + router + .push(doc.into_router("/api-doc/openapi.json")) + .push(SwaggerUi::new("/api-doc/openapi.json").into_router("swagger-ui")) +} + {{/if}} +{{/if}} \ No newline at end of file diff --git a/src/template/src/routers/user.hbs b/src/template/src/routers/user.hbs index d4d4ef1..4144290 100644 --- a/src/template/src/routers/user.hbs +++ b/src/template/src/routers/user.hbs @@ -1,9 +1,25 @@ {{#if is_web_site}} +use crate::{ + app_error::AppResult, + app_response::{ErrRes, Res}, + dtos::user::{UserAddRequest, UserLoginRequest, UserLoginResponse, UserUpdateRequest}, + middleware::jwt::decode_token, + services::user, +}; +use askama::Template; +use salvo::{ + endpoint, + http::cookie::Cookie, + oapi::extract::{JsonBody, PathParam}, + writing::{Redirect, Text}, + Request, Response, +}; + #[derive(Template)] #[template(path = "login.html")] struct LoginTemplate {} -#[endpoint] +#[endpoint( tags("comm"),)] pub async fn login_page(res: &mut Response) -> AppResult<()> { let cookies = res.cookies(); let cookie = cookies.get("jwt_token"); @@ -19,8 +35,23 @@ pub async fn login_page(res: &mut Response) -> AppResult<()> { res.render(Text::Html(hello_tmpl.render().unwrap())); Ok(()) } +#[endpoint( tags("comm"),)] +pub async fn post_login(req: JsonBody, res: &mut Response) { + let result: AppResult = user::login(req.0).await; + match result { + Ok(data) => { + let jwt_token = data.token.clone(); + let cookie = Cookie::build("jwt_token", jwt_token) + .path("/") + .http_only(true) + .finish(); + res.add_cookie(cookie); + } + Err(e) => ErrRes::with_err(&e.to_string()).into_response(res), + } +} -#[endpoint] +#[endpoint( tags("users"))] pub async fn post_add_user(req: JsonBody, res: &mut Response) { let result = user::add_user(req.0).await; match result { @@ -29,7 +60,10 @@ pub async fn post_add_user(req: JsonBody, res: &mut Response) { } } -#[endpoint] +#[endpoint( tags("users"), +parameters( + ("id", description = "user id"), +))] pub async fn put_update_user(req: &mut Request, res: &mut Response) { let req: UserUpdateRequest = req.extract().await.unwrap(); let result = user::update_user(req).await; @@ -39,7 +73,7 @@ pub async fn put_update_user(req: &mut Request, res: &mut Response) { } } -#[endpoint] +#[endpoint( tags("users"),)] pub async fn delete_user(id: PathParam, res: &mut Response) { let result = user::delete_user(id.0).await; match result { @@ -48,7 +82,7 @@ pub async fn delete_user(id: PathParam, res: &mut Response) { } } -#[endpoint] +#[endpoint( tags("users"),)] pub async fn get_users(res: &mut Response) { let result = user::users().await; match result { @@ -57,22 +91,6 @@ pub async fn get_users(res: &mut Response) { } } -#[endpoint] -pub async fn post_login(req: JsonBody, res: &mut Response) { - let result: Result = - user::login(req.0).await; - match result { - Ok(data) => { - let jwt_token = data.token.clone(); - let cookie = Cookie::build("jwt_token", jwt_token) - .path("/") - .http_only(true) - .finish(); - res.add_cookie(cookie); - } - Err(e) => ErrRes::with_err(&e.to_string()).into_response(res), - } -} #[derive(Template)] #[template(path = "user_list_page.html")] pub struct UserListPageTemplate {} @@ -97,19 +115,36 @@ pub async fn user_list_page(req: &mut Request, res: &mut Response) -> AppResult< Ok(()) } {{else}} -use salvo::{ - endpoint, - oapi::extract::{FormBody, JsonBody}, - Response, -}; use crate::{ + app_error::AppResult, app_response::{ErrRes, Res}, - dtos::user::{ - UserAddRequest, UserDeleteRequest, UserLoginRequest, UserUpdateRequest, - }, + dtos::user::{UserAddRequest, UserLoginRequest, UserLoginResponse, UserUpdateRequest}, services::user, }; -#[endpoint] +use salvo::{ + endpoint, + http::cookie::Cookie, + oapi::extract::{JsonBody, PathParam}, + Request, Response, +}; + +#[endpoint( tags("comm"),)] +pub async fn post_login(req: JsonBody, res: &mut Response) { + let result: AppResult = user::login(req.0).await; + match result { + Ok(data) => { + let jwt_token = data.token.clone(); + let cookie = Cookie::build("jwt_token", jwt_token) + .path("/") + .http_only(true) + .finish(); + res.add_cookie(cookie); + } + Err(e) => ErrRes::with_err(&e.to_string()).into_response(res), + } +} + +#[endpoint( tags("users"))] pub async fn post_add_user(req: JsonBody, res: &mut Response) { let result = user::add_user(req.0).await; match result { @@ -118,25 +153,29 @@ pub async fn post_add_user(req: JsonBody, res: &mut Response) { } } -#[endpoint] -pub async fn post_update_user(req: JsonBody, res: &mut Response) { - let result = user::update_user(req.0).await; +#[endpoint( tags("users"), +parameters( + ("id", description = "user id"), +))] +pub async fn put_update_user(req: &mut Request, res: &mut Response) { + let req: UserUpdateRequest = req.extract().await.unwrap(); + let result = user::update_user(req).await; match result { Ok(data) => Res::with_data(data).into_response(res), Err(e) => ErrRes::with_err(&e.to_string()).into_response(res), } } -#[endpoint] -pub async fn delete_user(req: JsonBody, res: &mut Response) { - let result = user::delete_user(req.0).await; +#[endpoint( tags("users"),)] +pub async fn delete_user(id: PathParam, res: &mut Response) { + let result = user::delete_user(id.0).await; match result { Ok(_) => Res::with_data(()).into_response(res), Err(e) => ErrRes::with_err(&e.to_string()).into_response(res), } } -#[endpoint] +#[endpoint( tags("users"),)] pub async fn get_users(res: &mut Response) { let result = user::users().await; match result { diff --git a/src/template/src/services/user.hbs b/src/template/src/services/user.hbs index 9ef7eff..c8f9e22 100644 --- a/src/template/src/services/user.hbs +++ b/src/template/src/services/user.hbs @@ -3,7 +3,7 @@ use crate::{ app_error::AppResult, db::DB, dtos::user::{ - UserAddRequest, UserDeleteRequest, UserLoginRequest, UserLoginResponse, UserResponse, + UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, UserUpdateRequest, }, middleware::jwt::get_token, @@ -16,7 +16,7 @@ use crate::{ app_error::AppResult, db::DB, dtos::user::{ - UserAddRequest, UserDeleteRequest, UserLoginRequest, UserLoginResponse, UserResponse, + UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, UserUpdateRequest, }, middleware::jwt::get_token, @@ -103,14 +103,14 @@ pub async fn update_user(req: UserUpdateRequest) -> AppResult { }) } -pub async fn delete_user(req: UserDeleteRequest) -> AppResult<()> { +pub async fn delete_user(id: String) -> AppResult<()> { let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?; sqlx::query!( r#" DELETE FROM users WHERE id = $1 "#, - req.id, + id, ) .execute(db) .await?; @@ -196,9 +196,9 @@ pub async fn update_user(req: UserUpdateRequest) -> AppResult { }) } -pub async fn delete_user(req: UserDeleteRequest) -> AppResult<()> { - let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?; - User::delete_by_id(req.id, ).exec(db).await?; +pub async fn delete_user(id: String) -> AppResult<()> { + let db = DB.get().ok_or(anyhow::anyhow!("数据库连接失败"))?; + User::delete_by_id(id).exec(db).await?; Ok(()) } diff --git a/src/template/templates/login.hbs b/src/template/templates/login.hbs index 30e67cb..cfe249d 100644 --- a/src/template/templates/login.hbs +++ b/src/template/templates/login.hbs @@ -92,7 +92,7 @@ userList: "", async submit() { try { - const response = await fetch("/login", { + const response = await fetch("/api/login", { method: "POST", headers: { "Content-Type": "application/json", @@ -107,13 +107,13 @@ throw new Error(`${data.msg}`); } this.isLoggedIn = true; - const userListResponse = await fetch("/user", { + const userListResponse = await fetch("/users", { headers: { "X-Fragment-Header": "true", }, }); this.userList = await userListResponse.text(); - //history.pushState(null, '', '/user'); + history.pushState(null, '', '/users'); } catch (error) { Swal.fire({ title: "Error!", @@ -125,5 +125,86 @@ }, }; } + function userForm() { + return { + users: [], + fetchData() { + fetch("/api/users") + .then((response) => { + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.json(); + }) + .then((data) => { + this.users = data.data; + }) + .catch((error) => { + console.error( + "There has been a problem with your fetch operation:", + error + ); + }); + }, + addUser() { + Swal.fire({ + title: "Add User", + showCancelButton: true, + html: ` + + + `, + preConfirm: () => { + return fetch("/api/users", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + username: document.getElementById("swal-input1").value, + password: document.getElementById("swal-input2").value, + }), + }) + .then((response) => { + if (!response.ok) { + throw new Error(response.statusText); + } + this.fetchData(); + return; + }) + .catch((error) => { + Swal.showValidationMessage(`Request failed: ${error}`); + }); + }, + allowOutsideClick: () => !Swal.isLoading(), + }); + }, + deleteUser(id) { + Swal.fire({ + title: "Are you sure?", + text: "You won't be able to revert this!", + icon: "warning", + showCancelButton: true, + confirmButtonText: "Yes, delete it!", + preConfirm: () => { + return fetch(`/api/users/${id}`, { + method: "DELETE", + }) + .then((response) => { + if (!response.ok) { + throw new Error(response.statusText); + } + this.fetchData(); + return; + }) + .catch((error) => { + Swal.showValidationMessage(`Request failed: ${error}`); + }); + }, + allowOutsideClick: () => !Swal.isLoading(), + }).then((result) => {}); + }, + }; + } diff --git a/src/template/templates/user_list.hbs b/src/template/templates/user_list.hbs index 69d9a20..55ce689 100644 --- a/src/template/templates/user_list.hbs +++ b/src/template/templates/user_list.hbs @@ -60,87 +60,3 @@ - - diff --git a/src/template/templates/user_list_page.hbs b/src/template/templates/user_list_page.hbs index 7958716..df98780 100644 --- a/src/template/templates/user_list_page.hbs +++ b/src/template/templates/user_list_page.hbs @@ -6,8 +6,91 @@ salvo - {% include "user_list.html" %} - - - + {% include "user_list.html" %} + + + + diff --git a/src/utils/create_project.rs b/src/utils/create_project.rs index 6695414..ef2ee71 100644 --- a/src/utils/create_project.rs +++ b/src/utils/create_project.rs @@ -83,7 +83,7 @@ fn write_project_file( "jsonwebtoken": "8.3.0", "once_cell": "1.18.0", "salvo": { - "version": "*", + "version": "0.57", "features": ["anyhow", "logging", "cors", "oapi", "jwt-auth", "rustls", "catch-panic","cookie"] }, "serde": "1.0.188", diff --git a/src/utils/get_selection.rs b/src/utils/get_selection.rs index 49796d5..1a305a6 100644 --- a/src/utils/get_selection.rs +++ b/src/utils/get_selection.rs @@ -18,8 +18,8 @@ pub fn get_user_selected() -> Result> { ..ColorfulTheme::default() }; let selections = &[ - t!("salvo_web_api"), t!("salvo_web_site"), + t!("salvo_web_api"), // "custom", ]; let selection = Select::with_theme(&theme) @@ -28,8 +28,8 @@ pub fn get_user_selected() -> Result> { .items(&selections[..]) .interact()?; let template_type = match selection { - 0 => TemplateType::SalvoWebApi, - 1 => TemplateType::SalvoWebSite, + 0 => TemplateType::SalvoWebSite, + 1 => TemplateType::SalvoWebApi, _ => anyhow::bail!("Invalid selection"), }; let db_conn_types = &[