diff --git a/doc/api/auth.zh_CN.md b/doc/api/auth.zh_CN.md index 817f9f8..b6443de 100644 --- a/doc/api/auth.zh_CN.md +++ b/doc/api/auth.zh_CN.md @@ -30,6 +30,11 @@ * 方法: `GET` 或 `POST` * RESTful: `DELETE /api/auth/user` 或 `DELETE /auth/user` * 鉴权: 需要(仅管理员) +## 获取用户信息 +* 路径: `/api/auth/user/info`、 `/auth/user/info` +* 方法: `GET` 或 `POST` +* RESTful: `GET /api/auth/user` 或 `GET /auth/user` +* 鉴权: 需要(其他用户信息仅管理员) ## 获取Token * 路径: `/api/auth/token/add`、 `/auth/token/add` * 方法: `GET` 或 `POST` diff --git a/src/db/user.rs b/src/db/user.rs index 8b03898..423095f 100644 --- a/src/db/user.rs +++ b/src/db/user.rs @@ -2,6 +2,7 @@ use bytes::BytesMut; use crate::ext::json::ToJson2; +#[derive(Clone)] /// A user in the database pub struct User { /// The user ID diff --git a/src/server/auth/user.rs b/src/server/auth/user.rs index b36698f..69dd57a 100644 --- a/src/server/auth/user.rs +++ b/src/server/auth/user.rs @@ -17,6 +17,8 @@ pub enum AuthUserAction { ChangePassword, /// Delete a user. Delete, + /// Get a user's information. + GetInfo, /// Update a existed user. Update, } @@ -251,6 +253,29 @@ impl AuthUserContext { .try_err3(-1001, gettext("Failed to operate the database:"))?; Ok(json::JsonValue::Boolean(re)) } + AuthUserAction::GetInfo => { + let id = params.get_u64("id").try_err3( + 13, + &gettext("Failed to parse :").replace("", "user id"), + )?; + let username = params.get("username"); + let nuser = if let Some(id) = id { + self.ctx.db.get_user(id).await + } else if let Some(username) = username { + self.ctx.db.get_user_by_username(username).await + } else { + Ok(user.clone()) + } + .try_err3(-1001, gettext("Failed to operate the database:"))? + .try_err3(15, gettext("User not found."))?; + let user = user.as_ref().expect("User not found:"); + if root_user.is_some() && nuser.id != user.id { + if !user.is_admin { + return Err((9, gettext("Admin privileges required.")).into()); + } + } + Ok(nuser.to_json2()) + } AuthUserAction::Update => { if root_user.is_some() { if !user.as_ref().expect("User not found:").is_admin { @@ -369,6 +394,7 @@ impl ResponseJsonFor for AuthUserContext { PUT, PATCH, DELETE, + GET, ); builder } else { @@ -397,7 +423,7 @@ impl AuthUserRoute { pub fn new() -> Self { Self { regex: Regex::new( - r"^(/+api)?/+auth/+user(/+(add|update|delete|change/+(name|password)))?$", + r"^(/+api)?/+auth/+user(/+(add|update|delete|info|change/+(name|password)))?$", ) .unwrap(), } @@ -429,6 +455,7 @@ impl MatchRoute for AuthUserRoute { match m { "add" => Some(AuthUserAction::Add), "delete" => Some(AuthUserAction::Delete), + "info" => Some(AuthUserAction::GetInfo), "update" => Some(AuthUserAction::Update), _ => { if m.starts_with("change/") { @@ -453,6 +480,8 @@ impl MatchRoute for AuthUserRoute { Some(AuthUserAction::Update) } else if m == Method::DELETE { Some(AuthUserAction::Delete) + } else if m == Method::GET { + Some(AuthUserAction::GetInfo) } else { None } diff --git a/src/server/unittest/auth.rs b/src/server/unittest/auth.rs index ac94a6f..98b8bff 100644 --- a/src/server/unittest/auth.rs +++ b/src/server/unittest/auth.rs @@ -363,5 +363,68 @@ pub async fn test(ctx: &UnitTestContext) -> Result<[(u64, Vec); 2], PixivDow "is_admin": false, } ); + let re = ctx + .request_json2_sign("/auth/user/info", &json::object! {}, &token2, token2_id) + .await? + .unwrap(); + let result = JSONResult::from_json(re)?.unwrap(); + assert_eq!( + result, + json::object! { + "id": 1, + "name": "sadiuqwed", + "username": "test1", + "is_admin": false, + } + ); + let re = ctx + .request_json2_sign( + "/auth/user/info", + &json::object! { "id": 1 }, + &token2, + token2_id, + ) + .await? + .unwrap(); + let result = JSONResult::from_json(re)?.unwrap(); + assert_eq!( + result, + json::object! { + "id": 1, + "name": "sadiuqwed", + "username": "test1", + "is_admin": false, + } + ); + let re = ctx + .request_json2_sign( + "/auth/user/info", + &json::object! {"username": "test"}, + &token2, + token2_id, + ) + .await? + .unwrap(); + let result = JSONResult::from_json(re)?.unwrap_err(); + assert_eq!(result.code, 9); + let re = ctx + .request_json2_sign( + "/auth/user/info", + &json::object! {"username": "test1"}, + &token, + token_id, + ) + .await? + .unwrap(); + let result = JSONResult::from_json(re)?.unwrap(); + assert_eq!( + result, + json::object! { + "id": 1, + "name": "sadiuqwed", + "username": "test1", + "is_admin": false, + } + ); Ok([(token_id, token), (token2_id, token2)]) }