diff --git a/app/db/models/user.py b/app/db/models/user.py index e649e4811..8f9fc0ae5 100644 --- a/app/db/models/user.py +++ b/app/db/models/user.py @@ -81,9 +81,11 @@ class User(Base): user.delete(db, user.id) return True + @classmethod @async_db_update - async def async_delete_by_id(self, db: AsyncSession, user_id: int): - user = await self.async_get_by_id(db, user_id) + async def async_delete_by_id(cls, db: AsyncSession, user_id: int): + """异步按用户 ID 删除用户,供 UserOper 通过类方法调用。""" + user = await cls.async_get_by_id(db, user_id) if user: await user.async_delete(db, user.id) return True @@ -99,9 +101,11 @@ class User(Base): return True return False + @classmethod @async_db_update - async def async_update_otp_by_name(self, db: AsyncSession, name: str, otp: bool, secret: str): - user = await self.async_get_by_name(db, name) + async def async_update_otp_by_name(cls, db: AsyncSession, name: str, otp: bool, secret: str): + """异步按用户名更新 OTP 状态,供 UserOper 通过类方法调用。""" + user = await cls.async_get_by_name(db, name) if user: await user.async_update(db, { 'is_otp': otp, diff --git a/tests/test_db_config_user_queries.py b/tests/test_db_config_user_queries.py index b2a087c07..fb6664f5e 100644 --- a/tests/test_db_config_user_queries.py +++ b/tests/test_db_config_user_queries.py @@ -13,6 +13,7 @@ from app.db.models.passkey import PassKey from app.db.models.systemconfig import SystemConfig from app.db.models.user import User from app.db.models.userconfig import UserConfig +from app.db.oper.user import UserOper @pytest.fixture(autouse=True) @@ -166,16 +167,21 @@ def test_user_async_mutations_match_sync_behaviour(db): """ 异步的删除与 OTP 更新必须与同步路径给出相同的存在性判断。 """ + async_id_user = db.add(User(name="mp-test-async-id", hashed_password="x")) db.add(User(name="mp-test-async-otp", hashed_password="x", is_otp=False)) + oper = UserOper() - assert asyncio.run(User().async_update_otp_by_name( + assert asyncio.run(User.async_update_otp_by_name( name="mp-test-async-otp", otp=True, secret="S2")) is True - assert asyncio.run(User().async_update_otp_by_name( + assert asyncio.run(User.async_update_otp_by_name( name="mp-test-nobody", otp=True, secret="S2")) is False assert asyncio.run(User().async_delete_by_name(name="mp-test-async-otp")) is True assert User.get_by_name(db.session, "mp-test-async-otp") is None + asyncio.run(oper.async_delete(async_id_user.id)) + assert User.get_by_id(db.session, async_id_user.id) is None + # --------------------------------------------------------------------------- # # PassKey