diff --git a/doc/api/auth.zh_CN.md b/doc/api/auth.zh_CN.md index db02ab3..fb58d4a 100644 --- a/doc/api/auth.zh_CN.md +++ b/doc/api/auth.zh_CN.md @@ -17,6 +17,10 @@ * 方法: `GET` 或 `POST` * RESTful: `PATCH /api/auth/user` 或 `PATCH /auth/user` * 鉴权: 需要 +## 修改用户名字 +* 路径: `/api/auth/user/change/name`、 `/auth/user/change/name` +* 方法: `GET` 或 `POST` +* 鉴权: 需要 ## 获取Token * 路径: `/api/auth/token/add`、 `/auth/token/add` * 方法: `GET` 或 `POST` diff --git a/src/db/sqlite/db.rs b/src/db/sqlite/db.rs index ad26bd7..04b724b 100644 --- a/src/db/sqlite/db.rs +++ b/src/db/sqlite/db.rs @@ -434,6 +434,10 @@ impl PixivDownloaderSqlite { )?) } + fn _update_user_name(ts: &Transaction, id: u64, name: &str) -> Result { + Ok(ts.execute("UPDATE users SET name = ? WHERE id = ?;", (name, id))?) + } + fn _write_version<'a>(&self, ts: &Transaction<'a>) -> Result<(), SqliteError> { let mut stmt = ts.prepare( "INSERT OR REPLACE INTO version (id, v1, v2, v3, v4) VALUES ('main', ?, ?, ?, ?);", @@ -593,4 +597,15 @@ impl PixivDownloaderDb for PixivDownloaderSqlite { .await?; Ok(self.get_user(id).await?.expect("User not found:")) } + + #[cfg(feature = "server")] + async fn update_user_name(&self, id: u64, name: &str) -> Result { + { + let mut db = self.db.lock().await; + let mut tx = db.transaction()?; + Self::_update_user_name(&mut tx, id, name)?; + tx.commit()?; + } + Ok(self.get_user(id).await?.expect("User not found:")) + } } diff --git a/src/db/traits.rs b/src/db/traits.rs index 2e22e33..35d20c6 100644 --- a/src/db/traits.rs +++ b/src/db/traits.rs @@ -111,4 +111,9 @@ pub trait PixivDownloaderDb { password: &[u8], is_admin: bool, ) -> Result; + #[cfg(feature = "server")] + /// Update a user's name + /// * `id`: The user's ID + /// * `name`: The user's name + async fn update_user_name(&self, id: u64, name: &str) -> Result; } diff --git a/src/ext/try_err.rs b/src/ext/try_err.rs index d126cb4..c65e876 100644 --- a/src/ext/try_err.rs +++ b/src/ext/try_err.rs @@ -75,3 +75,13 @@ where } } } + +#[cfg(feature = "server")] +impl TryErr3 for Option { + fn try_err3 + ?Sized>(self, code: i32, msg: &S) -> Result { + match self { + Some(v) => Ok(v), + None => Err(JSONError::from((code, msg.as_ref().to_string(), None))), + } + } +} diff --git a/src/server/auth/user.rs b/src/server/auth/user.rs index 92b2c0b..b0b0741 100644 --- a/src/server/auth/user.rs +++ b/src/server/auth/user.rs @@ -11,6 +11,8 @@ use openssl::{hash::MessageDigest, pkcs5::pbkdf2_hmac}; pub enum AuthUserAction { /// Add a new user. Add, + /// Change a user's name. + ChangeName, /// Update a existed user. Update, } @@ -153,6 +155,16 @@ impl AuthUserContext { None => return Err((5, gettext("No RSA key found.")).into()), } } + AuthUserAction::ChangeName => { + let name = params.get("name").try_err3(18, "No name specified.")?; + let user = self + .ctx + .db + .update_user_name(user.expect("User not found.").id, name) + .await + .try_err3(-1001, gettext("Failed to operate the database:"))?; + Ok(user.to_json2()) + } AuthUserAction::Update => { if root_user.is_some() { if !user.as_ref().expect("User not found:").is_admin { @@ -296,7 +308,7 @@ pub struct AuthUserRoute { impl AuthUserRoute { pub fn new() -> Self { Self { - regex: Regex::new(r"^(/+api)?/+auth/+user(/+(add|update))?$").unwrap(), + regex: Regex::new(r"^(/+api)?/+auth/+user(/+(add|update|change/+name))?$").unwrap(), } } } @@ -326,7 +338,18 @@ impl MatchRoute for AuthUserRoute { match m { "add" => Some(AuthUserAction::Add), "update" => Some(AuthUserAction::Update), - _ => return None, + _ => { + if m.starts_with("change/") { + let m = m.trim_start_matches("change/"); + let m = m.trim_start_matches("/"); + match m { + "name" => Some(AuthUserAction::ChangeName), + _ => return None, + } + } else { + return None; + } + } } } None => { diff --git a/src/server/unittest/auth.rs b/src/server/unittest/auth.rs index 39f64fc..d532e7b 100644 --- a/src/server/unittest/auth.rs +++ b/src/server/unittest/auth.rs @@ -258,5 +258,26 @@ pub async fn test(ctx: &UnitTestContext) -> Result<[(u64, Vec); 2], PixivDow .unwrap(); let result = JSONResult::from_json(re)?.unwrap_err(); assert_eq!(result.code, 17); + let re = ctx + .request_json2_sign( + "/auth/user/change/name", + &json::object! { + "name": "sdlkasdjklasjd" + }, + &token2, + token2_id, + ) + .await? + .unwrap(); + let result = JSONResult::from_json(re)?.unwrap(); + assert_eq!( + result, + json::object! { + "id": 1, + "name": "sdlkasdjklasjd", + "username": "test1", + "is_admin": false, + } + ); Ok([(token_id, token), (token2_id, token2)]) }