system_view.py 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502
  1. # 在 views/system_view.py 中
  2. import sys
  3. import os
  4. import uuid
  5. import traceback
  6. import json
  7. import secrets
  8. import logging
  9. # 添加src目录到Python路径
  10. sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..'))
  11. sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../..'))
  12. """
  13. 系统管理视图路由
  14. 包含:用户管理、角色管理、菜单管理、权限管理、系统日志、仪表盘、应用管理
  15. """
  16. from fastapi import APIRouter, Depends, HTTPException, Request, Response
  17. from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
  18. from sqlalchemy.ext.asyncio import AsyncSession
  19. from typing import Optional
  20. from datetime import datetime, timezone
  21. from app.services.jwt_token import verify_token
  22. from app.services.auth_service import AuthService
  23. from app.utils.auth_decorator import get_current_user_with_sliding_expiration
  24. from app.schemas.base import ApiResponse
  25. from app.utils.security import hash_password, verify_password
  26. from app.services.system_service import SystemService
  27. from app.services.system_service_ext import SystemServiceExt
  28. from app.utils.auth_dependency import get_current_user_with_refresh
  29. # 获取logger
  30. logger = logging.getLogger(__name__)
  31. router = APIRouter(prefix="/system", tags=["系统管理"])
  32. security = HTTPBearer()
  33. @router.get("/dashboard")
  34. async def get_dashboard(
  35. request: Request,
  36. credentials: dict = Depends(get_current_user_with_refresh)
  37. ):
  38. """获取仪表盘数据(支持滑动过期)"""
  39. try:
  40. # 使用AuthService验证令牌并获取用户信息(支持滑动过期)
  41. auth_service = AuthService(db)
  42. user, new_token = await auth_service.get_current_user(credentials.credentials)
  43. if not user:
  44. return ApiResponse(
  45. code=401,
  46. message="无效的访问令牌",
  47. timestamp=datetime.now(timezone.utc).isoformat()
  48. ).model_dump()
  49. # 获取仪表盘数据
  50. dashboard_data = {
  51. "total_users": 0,
  52. "total_apps": 0,
  53. "today_logins": 0,
  54. "system_status": "正常",
  55. "current_user": {
  56. "id": user.id,
  57. "username": user.username,
  58. "email": user.email
  59. }
  60. }
  61. response_data = ApiResponse(
  62. code=0,
  63. message="获取仪表盘数据成功",
  64. data=dashboard_data,
  65. timestamp=datetime.now(timezone.utc).isoformat()
  66. ).model_dump()
  67. # 如果token被刷新,添加提示信息
  68. if new_token:
  69. response_data["token_refreshed"] = True
  70. response_data["new_token"] = new_token
  71. logger.info(f"仪表盘API - Token已刷新,用户: {user.username}")
  72. return response_data
  73. except Exception as e:
  74. logger.error(f"获取仪表盘数据错误: {e}")
  75. return ApiResponse(
  76. code=500,
  77. message=f"获取仪表盘数据失败: {str(e)}",
  78. timestamp=datetime.now(timezone.utc).isoformat()
  79. ).model_dump()
  80. @router.get("/info")
  81. async def get_system_info_with_sliding_token(
  82. user_info: dict = Depends(get_current_user_with_sliding_expiration)
  83. ):
  84. """获取系统信息(使用滑动过期依赖注入)"""
  85. try:
  86. user = user_info["user"]
  87. new_token = user_info["new_token"]
  88. # 获取系统信息
  89. system_info = {
  90. "system_name": "LQ后台管理系统",
  91. "version": "1.0.0",
  92. "current_time": datetime.now(timezone.utc).isoformat(),
  93. "current_user": {
  94. "id": user.id,
  95. "username": user.username,
  96. "email": user.email,
  97. "is_superuser": user.is_superuser
  98. }
  99. }
  100. response_data = ApiResponse(
  101. code=0,
  102. message="获取系统信息成功",
  103. data=system_info,
  104. timestamp=datetime.now(timezone.utc).isoformat()
  105. ).model_dump()
  106. # 如果token被刷新,添加提示信息
  107. if new_token:
  108. response_data["token_refreshed"] = True
  109. response_data["new_token"] = new_token
  110. logger.info(f"系统信息API - Token已刷新,用户: {user.username}")
  111. return response_data
  112. except Exception as e:
  113. logger.error(f"获取系统信息错误: {e}")
  114. return ApiResponse(
  115. code=500,
  116. message=f"获取系统信息失败: {str(e)}",
  117. timestamp=datetime.now(timezone.utc).isoformat()
  118. ).model_dump()
  119. @router.get("/logs")
  120. async def get_logs(
  121. page: int = 1,
  122. page_size: int = 20,
  123. log_type: str = "",
  124. credentials: dict = Depends(get_current_user_with_refresh)
  125. ):
  126. """获取系统日志"""
  127. return {
  128. "code": 0,
  129. "message": "获取系统日志成功",
  130. "data": {
  131. "items": [],
  132. "total": 0,
  133. "page": page,
  134. "page_size": page_size
  135. },
  136. "timestamp": datetime.now(timezone.utc).isoformat()
  137. }
  138. @router.get("/users/profile")
  139. async def get_user_profile( request: Request,
  140. credentials: dict = Depends(get_current_user_with_refresh)
  141. ):
  142. """获取用户资料"""
  143. try:
  144. # 验证令牌
  145. # 验证令牌
  146. payload = credentials
  147. if not payload:
  148. return ApiResponse(
  149. code=200002,
  150. message="无效的访问令牌",
  151. timestamp=datetime.now(timezone.utc).isoformat()
  152. ).model_dump()
  153. user_id = payload.get("sub")
  154. if not user_id:
  155. return ApiResponse(
  156. code=200002,
  157. message="无效的访问令牌",
  158. timestamp=datetime.now(timezone.utc).isoformat()
  159. ).model_dump()
  160. # 调用 service 层
  161. system_service = SystemService()
  162. user_info = await system_service.get_user_profile(user_id)
  163. if not user_info:
  164. return ApiResponse(
  165. code=200001,
  166. message="用户不存在",
  167. timestamp=datetime.now(timezone.utc).isoformat()
  168. ).model_dump()
  169. return ApiResponse(
  170. code=0,
  171. message="获取用户资料成功",
  172. data=user_info,
  173. timestamp=datetime.now(timezone.utc).isoformat()
  174. ).model_dump()
  175. except Exception as e:
  176. logger.exception("获取用户资料错误")
  177. return ApiResponse(
  178. code=500001,
  179. message="服务器内部错误",
  180. timestamp=datetime.now(timezone.utc).isoformat()
  181. ).model_dump()
  182. @router.put("/users/profile")
  183. async def update_user_profile(
  184. request: Request,
  185. profile_data: dict,
  186. credentials: dict = Depends(get_current_user_with_refresh)
  187. ):
  188. """更新用户资料"""
  189. try:
  190. # 验证令牌
  191. payload = credentials
  192. if not payload:
  193. return ApiResponse(
  194. code=200002,
  195. message="无效的访问令牌",
  196. timestamp=datetime.now(timezone.utc).isoformat()
  197. ).model_dump()
  198. user_id = payload.get("sub")
  199. # 调用 service 层
  200. system_service = SystemService()
  201. success, message = await system_service.update_user_profile(user_id, profile_data)
  202. if success:
  203. return ApiResponse(
  204. code=0,
  205. message=message,
  206. timestamp=datetime.now(timezone.utc).isoformat()
  207. ).model_dump()
  208. else:
  209. return ApiResponse(
  210. code=500001,
  211. message=message,
  212. timestamp=datetime.now(timezone.utc).isoformat()
  213. ).model_dump()
  214. except Exception as e:
  215. logger.exception("更新用户资料错误")
  216. return ApiResponse(
  217. code=500001,
  218. message="服务器内部错误",
  219. timestamp=datetime.now(timezone.utc).isoformat()
  220. ).model_dump()
  221. @router.put("/users/password")
  222. async def change_user_password(
  223. request: Request,
  224. password_data: dict,
  225. credentials: dict = Depends(get_current_user_with_refresh)
  226. ):
  227. """修改用户密码"""
  228. try:
  229. # 验证令牌
  230. payload = credentials
  231. if not payload:
  232. return ApiResponse(
  233. code=200002,
  234. message="无效的访问令牌",
  235. timestamp=datetime.now(timezone.utc).isoformat()
  236. ).model_dump()
  237. user_id = payload.get("sub")
  238. old_password = password_data.get('old_password')
  239. new_password = password_data.get('new_password')
  240. if not old_password or not new_password:
  241. return ApiResponse(
  242. code=100001,
  243. message="缺少必要参数",
  244. timestamp=datetime.now(timezone.utc).isoformat()
  245. ).model_dump()
  246. # 调用 service 层
  247. system_service = SystemService()
  248. success, message = await system_service.change_user_password(user_id, old_password, new_password)
  249. if success:
  250. return ApiResponse(
  251. code=0,
  252. message=message,
  253. timestamp=datetime.now(timezone.utc).isoformat()
  254. ).model_dump()
  255. else:
  256. return ApiResponse(
  257. code=200001,
  258. message=message,
  259. timestamp=datetime.now(timezone.utc).isoformat()
  260. ).model_dump()
  261. except Exception as e:
  262. logger.exception("修改密码错误")
  263. return ApiResponse(
  264. code=500001,
  265. message="服务器内部错误",
  266. timestamp=datetime.now(timezone.utc).isoformat()
  267. ).model_dump()
  268. def hash_password_simple(password):
  269. """密码哈希 - 使用bcrypt"""
  270. from app.utils.security import hash_password
  271. return hash_password(password)
  272. def verify_password_simple(plain_password: str, hashed_password: str) -> bool:
  273. """
  274. 验证密码
  275. 支持两种格式:
  276. 1. sha256$salt$hash - 自定义格式
  277. 2. bcrypt格式 - 使用bcrypt验证
  278. """
  279. import hashlib
  280. try:
  281. # 检查是否是自定义sha256格式
  282. if hashed_password.startswith("sha256$"):
  283. parts = hashed_password.split("$")
  284. if len(parts) == 3:
  285. _, salt, stored_hash = parts
  286. # 使用相同的盐值计算哈希
  287. computed_hash = hashlib.sha256((plain_password + salt).encode()).hexdigest()
  288. return computed_hash == stored_hash
  289. # 尝试bcrypt验证
  290. try:
  291. from passlib.context import CryptContext
  292. pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
  293. return pwd_context.verify(plain_password, hashed_password)
  294. except ImportError:
  295. # 如果没有passlib,尝试使用bcrypt
  296. try:
  297. import bcrypt
  298. return bcrypt.checkpw(plain_password.encode('utf-8'), hashed_password.encode('utf-8'))
  299. except ImportError:
  300. pass
  301. return False
  302. except Exception as e:
  303. logger.exception("密码验证错误")
  304. return False
  305. # RBAC权限管理API
  306. @router.get("/user/menus")
  307. async def api_get_user_menus(
  308. request: Request,
  309. credentials: dict = Depends(get_current_user_with_refresh)
  310. ):
  311. """获取用户菜单"""
  312. try:
  313. payload = credentials
  314. if not payload:
  315. return ApiResponse(
  316. code=401,
  317. message="无效的访问令牌",
  318. timestamp=datetime.now(timezone.utc).isoformat()
  319. ).model_dump()
  320. user_id = payload.get("sub")
  321. # 调用 service 层
  322. system_service = SystemService()
  323. menu_tree = await system_service.get_user_menus(user_id)
  324. return ApiResponse(
  325. code=0,
  326. message="获取用户菜单成功",
  327. data=menu_tree,
  328. timestamp=datetime.now(timezone.utc).isoformat()
  329. ).model_dump()
  330. except Exception as e:
  331. logger.exception("获取用户菜单错误")
  332. return ApiResponse(
  333. code=500,
  334. message="服务器内部错误",
  335. timestamp=datetime.now(timezone.utc).isoformat()
  336. ).model_dump()
  337. @router.get("/admin/menus")
  338. async def api_get_all_menus(
  339. request: Request,
  340. credentials: dict = Depends(get_current_user_with_refresh),
  341. page: int = 1,
  342. page_size: int = 1000, # 增大默认页面大小,确保返回所有菜单
  343. keyword: Optional[str] = None,
  344. ):
  345. """获取所有菜单(管理员)"""
  346. try:
  347. #payload = verify_token(credentials.credentials)
  348. payload = credentials
  349. logger.info(f"credentials={credentials}")
  350. if not payload:
  351. return ApiResponse(
  352. code=401,
  353. message="无效的访问令牌",
  354. timestamp=datetime.now(timezone.utc).isoformat()
  355. ).model_dump()
  356. # 调用 service 层
  357. system_service = SystemService()
  358. menus, total = await system_service.get_all_menus(page, page_size, keyword)
  359. return ApiResponse(
  360. code=0,
  361. message="获取菜单列表成功",
  362. data={
  363. "items": menus,
  364. "total": total,
  365. "page": page,
  366. "page_size": page_size
  367. },
  368. timestamp=datetime.now(timezone.utc).isoformat()
  369. ).model_dump()
  370. except Exception as e:
  371. logger.exception("获取菜单列表错误")
  372. return ApiResponse(
  373. code=500,
  374. message="服务器内部错误",
  375. timestamp=datetime.now(timezone.utc).isoformat()
  376. ).model_dump()
  377. @router.get("/admin/roles")
  378. async def api_get_all_roles(
  379. request: Request,
  380. credentials: dict = Depends(get_current_user_with_refresh),
  381. page: int = 1,
  382. page_size: int = 20,
  383. keyword: Optional[str] = None,
  384. ):
  385. """获取所有角色"""
  386. try:
  387. #payload = verify_token(credentials.credentials)
  388. payload = credentials
  389. logger.info(f"credentials={credentials}")
  390. if not payload:
  391. return ApiResponse(
  392. code=401,
  393. message="无效的访问令牌",
  394. timestamp=datetime.now(timezone.utc).isoformat()
  395. ).model_dump()
  396. # 调用 service 层
  397. system_service = SystemService()
  398. roles, total = await system_service.get_all_roles(page , page_size , keyword)
  399. return ApiResponse(
  400. code=0,
  401. message="获取角色列表成功",
  402. data={
  403. "items": roles,
  404. "total": total,
  405. "page": page,
  406. "page_size": page_size
  407. },
  408. timestamp=datetime.now(timezone.utc).isoformat()
  409. ).model_dump()
  410. except Exception as e:
  411. logger.exception("获取角色列表错误")
  412. return ApiResponse(
  413. code=500,
  414. message="服务器内部错误",
  415. timestamp=datetime.now(timezone.utc).isoformat()
  416. ).model_dump()
  417. @router.get("/user/permissions")
  418. async def api_get_user_permissions(credentials: dict = Depends(get_current_user_with_refresh)):
  419. """获取用户权限"""
  420. try:
  421. payload = credentials
  422. if not payload:
  423. return ApiResponse(
  424. code=401,
  425. message="无效的访问令牌",
  426. timestamp=datetime.now(timezone.utc).isoformat()
  427. ).model_dump()
  428. user_id = payload.get("sub")
  429. # 调用 service 层
  430. system_service = SystemService()
  431. permissions = await system_service.get_user_permissions(user_id)
  432. return ApiResponse(
  433. code=0,
  434. message="获取用户权限成功",
  435. data=permissions,
  436. timestamp=datetime.now(timezone.utc).isoformat()
  437. ).model_dump()
  438. except Exception as e:
  439. logger.exception("获取用户权限错误")
  440. return ApiResponse(
  441. code=500,
  442. message="服务器内部错误",
  443. timestamp=datetime.now(timezone.utc).isoformat()
  444. ).model_dump()
  445. # 用户管理API
  446. @router.get("/admin/users")
  447. async def get_users(
  448. request: Request,
  449. credentials: dict = Depends(get_current_user_with_refresh),
  450. page: int = 1,
  451. page_size: int = 20,
  452. keyword: Optional[str] = None
  453. ):
  454. """获取用户列表"""
  455. try:
  456. payload = credentials
  457. if not payload:
  458. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  459. # 调用 service 层
  460. system_service_ext = SystemServiceExt()
  461. users, total = await system_service_ext.get_users(page, page_size, keyword)
  462. return ApiResponse(
  463. code=0,
  464. message="获取用户列表成功",
  465. data={"items": users, "total": total, "page": page, "page_size": page_size},
  466. timestamp=datetime.now(timezone.utc).isoformat()
  467. ).model_dump()
  468. except Exception as e:
  469. logger.exception("获取用户列表错误")
  470. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  471. @router.post("/admin/users")
  472. async def create_user(
  473. request: Request,
  474. user_data: dict,
  475. credentials: dict = Depends(get_current_user_with_refresh)
  476. ):
  477. """创建用户"""
  478. try:
  479. #payload = verify_token(credentials.credentials)
  480. payload = credentials
  481. if not payload:
  482. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  483. is_superuser = payload.get("is_superuser", False)
  484. if not is_superuser:
  485. return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  486. creator_id = payload.get("sub")
  487. # 创建密码哈希
  488. password_hash = hash_password_simple(user_data['password'])
  489. # 调用 service 层
  490. system_service_ext = SystemServiceExt()
  491. success, message = await system_service_ext.create_user(user_data, password_hash, creator_id)
  492. if success:
  493. return ApiResponse(code=0, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  494. else:
  495. return ApiResponse(code=400, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  496. except Exception as e:
  497. logger.exception("创建用户错误")
  498. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  499. @router.get("/admin/users/{user_id}")
  500. async def get_user_detail(
  501. user_id: str,
  502. credentials: dict = Depends(get_current_user_with_refresh)
  503. ):
  504. """获取用户详情"""
  505. try:
  506. payload = credentials
  507. if not payload:
  508. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  509. # 调用 service 层获取用户详情
  510. system_service_ext = SystemServiceExt()
  511. user_detail = await system_service_ext.get_user_detail(user_id)
  512. if user_detail:
  513. return ApiResponse(code=0, data=user_detail, message="Success", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  514. else:
  515. return ApiResponse(code=404, message="用户不存在", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  516. except Exception as e:
  517. logger.exception("获取用户详情错误")
  518. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  519. @router.put("/admin/users/{user_id}")
  520. async def update_user(
  521. user_id: str,
  522. user_data: dict,
  523. credentials: dict = Depends(get_current_user_with_refresh)
  524. ):
  525. """更新用户"""
  526. try:
  527. payload = credentials
  528. if not payload:
  529. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  530. updater_id = payload.get("sub")
  531. # 只有当密码不为空时才进行哈希处理
  532. if user_data.get('password'):
  533. password_hash = hash_password_simple(user_data['password'])
  534. user_data['password'] = password_hash
  535. # 调用 service 层
  536. system_service_ext = SystemServiceExt()
  537. success, message = await system_service_ext.update_user(user_id, user_data, updater_id)
  538. if success:
  539. return ApiResponse(code=0, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  540. else:
  541. return ApiResponse(code=400, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  542. except Exception as e:
  543. logger.exception("更新用户错误")
  544. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  545. @router.delete("/admin/users/{user_id}")
  546. async def delete_user(
  547. user_id: str,
  548. credentials: dict = Depends(get_current_user_with_refresh)
  549. ):
  550. """删除用户"""
  551. try:
  552. payload = credentials
  553. if not payload:
  554. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  555. is_superuser = payload.get("is_superuser", False)
  556. if not is_superuser:
  557. return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  558. current_user_id = payload.get("sub")
  559. # 不能删除自己
  560. if user_id == current_user_id:
  561. return ApiResponse(code=400, message="不能删除自己", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  562. # 调用 service 层
  563. system_service_ext = SystemServiceExt()
  564. success, message = await system_service_ext.delete_user(user_id, current_user_id)
  565. if success:
  566. return ApiResponse(code=0, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  567. else:
  568. return ApiResponse(code=400, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  569. except Exception as e:
  570. logger.exception("删除用户错误")
  571. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  572. # 角色管理API
  573. @router.post("/admin/roles")
  574. async def create_role(
  575. role_data: dict,
  576. credentials: dict = Depends(get_current_user_with_refresh)
  577. ):
  578. """创建角色"""
  579. try:
  580. payload = credentials
  581. if not payload:
  582. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  583. current_user_id = payload.get("sub")
  584. # 调用 service 层
  585. system_service = SystemService()
  586. success, message = await system_service.create_role(role_data , current_user_id)
  587. if success:
  588. return ApiResponse(code=0, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  589. else:
  590. return ApiResponse(code=400, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  591. except Exception as e:
  592. logger.exception("创建角色错误")
  593. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  594. @router.put("/admin/roles/{role_id}")
  595. async def update_role(
  596. role_id: str,
  597. role_data: dict,
  598. credentials: dict = Depends(get_current_user_with_refresh)
  599. ):
  600. """更新角色"""
  601. try:
  602. payload = credentials
  603. if not payload:
  604. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  605. is_superuser = payload.get("is_superuser", False)
  606. if not is_superuser:
  607. return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  608. user_id = payload.get("sub")
  609. # 调用 service 层
  610. system_service = SystemService()
  611. success, message = await system_service.update_role(role_id, role_data , user_id)
  612. if success:
  613. return ApiResponse(code=0, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  614. else:
  615. code = 404 if "不存在" in message else 400
  616. return ApiResponse(code=code, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  617. except Exception as e:
  618. logger.exception("更新角色错误")
  619. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  620. @router.delete("/admin/roles/{role_id}")
  621. async def delete_role(
  622. role_id: str,
  623. credentials: dict = Depends(get_current_user_with_refresh)
  624. ):
  625. """删除角色"""
  626. try:
  627. payload = credentials
  628. if not payload:
  629. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  630. is_superuser = payload.get("is_superuser", False)
  631. if not is_superuser:
  632. return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  633. # 调用 service 层
  634. system_service = SystemService()
  635. success, message = await system_service.delete_role(role_id)
  636. if success:
  637. return ApiResponse(code=0, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  638. else:
  639. code = 404 if "不存在" in message else 400
  640. return ApiResponse(code=code, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  641. except Exception as e:
  642. logger.exception("删除角色错误")
  643. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  644. # 角色菜单权限管理API
  645. @router.get("/admin/roles/{role_id}/menus")
  646. async def get_role_menus(
  647. role_id: str,
  648. credentials: dict = Depends(get_current_user_with_refresh)
  649. ):
  650. """获取角色的菜单权限"""
  651. try:
  652. payload = credentials
  653. if not payload:
  654. return ApiResponse(
  655. code=401,
  656. message="无效的访问令牌",
  657. timestamp=datetime.now(timezone.utc).isoformat()
  658. ).model_dump()
  659. # 调用 service 层
  660. system_service = SystemService()
  661. success, data, message = await system_service.get_role_menus(role_id)
  662. if success:
  663. return ApiResponse(
  664. code=0,
  665. message=message,
  666. data=data,
  667. timestamp=datetime.now(timezone.utc).isoformat()
  668. ).model_dump()
  669. else:
  670. code = 404 if "不存在" in message else 500
  671. return ApiResponse(
  672. code=code,
  673. message=message,
  674. timestamp=datetime.now(timezone.utc).isoformat()
  675. ).model_dump()
  676. except Exception as e:
  677. logger.exception("获取角色菜单权限错误")
  678. return ApiResponse(
  679. code=500,
  680. message="服务器内部错误",
  681. timestamp=datetime.now(timezone.utc).isoformat()
  682. ).model_dump()
  683. @router.put("/admin/roles/{role_id}/menus")
  684. async def update_role_menus(
  685. role_id: str,
  686. request: Request,
  687. credentials: dict = Depends(get_current_user_with_refresh)
  688. ):
  689. """更新角色的菜单权限"""
  690. try:
  691. payload = credentials
  692. if not payload:
  693. return ApiResponse(
  694. code=401,
  695. message="无效的访问令牌",
  696. timestamp=datetime.now(timezone.utc).isoformat()
  697. ).model_dump()
  698. # 获取请求数据
  699. body = await request.json()
  700. menu_ids = body.get("menu_ids", [])
  701. if not isinstance(menu_ids, list):
  702. return ApiResponse(
  703. code=400,
  704. message="菜单ID列表格式错误",
  705. timestamp=datetime.now(timezone.utc).isoformat()
  706. ).model_dump()
  707. # 调用 service 层
  708. system_service = SystemService()
  709. updater_id = payload.get("sub")
  710. success, data, message = await system_service.update_role_menus(role_id, menu_ids, updater_id)
  711. if success:
  712. return ApiResponse(
  713. code=0,
  714. message=message,
  715. data=data,
  716. timestamp=datetime.now(timezone.utc).isoformat()
  717. ).model_dump()
  718. else:
  719. code = 404 if "不存在" in message else 400
  720. return ApiResponse(
  721. code=code,
  722. message=message,
  723. timestamp=datetime.now(timezone.utc).isoformat()
  724. ).model_dump()
  725. except Exception as e:
  726. logger.exception("更新角色菜单权限错误")
  727. return ApiResponse(
  728. code=500,
  729. message="服务器内部错误",
  730. timestamp=datetime.now(timezone.utc).isoformat()
  731. ).model_dump()
  732. # 菜单管理API
  733. @router.post("/admin/menus")
  734. async def create_menu(
  735. request: Request,
  736. credentials: dict = Depends(get_current_user_with_refresh)
  737. ):
  738. """创建菜单"""
  739. try:
  740. payload = credentials
  741. if not payload:
  742. return ApiResponse(
  743. code=401,
  744. message="无效的访问令牌",
  745. timestamp=datetime.now(timezone.utc).isoformat()
  746. ).model_dump()
  747. # 获取请求数据
  748. body = await request.json()
  749. # 验证必填字段
  750. required_fields = ['title', 'name', 'menu_type']
  751. for field in required_fields:
  752. if field not in body or not body[field]:
  753. return ApiResponse(
  754. code=400,
  755. message=f"缺少必填字段: {field}",
  756. timestamp=datetime.now(timezone.utc).isoformat()
  757. ).model_dump()
  758. # 调用 service 层
  759. system_service = SystemService()
  760. creator_id = payload.get("sub")
  761. success, message = await system_service.create_menu(body, creator_id)
  762. if success:
  763. return ApiResponse(
  764. code=0,
  765. message=message,
  766. timestamp=datetime.now(timezone.utc).isoformat()
  767. ).model_dump()
  768. else:
  769. return ApiResponse(
  770. code=400,
  771. message=message,
  772. timestamp=datetime.now(timezone.utc).isoformat()
  773. ).model_dump()
  774. except Exception as e:
  775. logger.exception("创建菜单错误")
  776. return ApiResponse(
  777. code=500,
  778. message="服务器内部错误",
  779. timestamp=datetime.now(timezone.utc).isoformat()
  780. ).model_dump()
  781. @router.put("/admin/menus/{menu_id}")
  782. async def update_menu(
  783. menu_id: str,
  784. request: Request,
  785. credentials: dict = Depends(get_current_user_with_refresh)
  786. ):
  787. """更新菜单"""
  788. try:
  789. payload = credentials
  790. if not payload:
  791. return ApiResponse(
  792. code=401,
  793. message="无效的访问令牌",
  794. timestamp=datetime.now(timezone.utc).isoformat()
  795. ).model_dump()
  796. # 获取请求数据
  797. body = await request.json()
  798. # 调用 service 层
  799. system_service = SystemService()
  800. updater_id = payload.get("sub")
  801. success, message = await system_service.update_menu(menu_id, body, updater_id)
  802. if success:
  803. return ApiResponse(
  804. code=0,
  805. message=message,
  806. timestamp=datetime.now(timezone.utc).isoformat()
  807. ).model_dump()
  808. else:
  809. return ApiResponse(
  810. code=400,
  811. message=message,
  812. timestamp=datetime.now(timezone.utc).isoformat()
  813. ).model_dump()
  814. except Exception as e:
  815. logger.exception("更新菜单错误")
  816. return ApiResponse(
  817. code=500,
  818. message="服务器内部错误",
  819. timestamp=datetime.now(timezone.utc).isoformat()
  820. ).model_dump()
  821. @router.delete("/admin/menus/{menu_id}")
  822. async def delete_menu(
  823. menu_id: str,
  824. credentials: dict = Depends(get_current_user_with_refresh)
  825. ):
  826. """删除菜单"""
  827. try:
  828. payload = credentials
  829. if not payload:
  830. return ApiResponse(
  831. code=401,
  832. message="无效的访问令牌",
  833. timestamp=datetime.now(timezone.utc).isoformat()
  834. ).model_dump()
  835. # 调用 service 层
  836. system_service = SystemService()
  837. success, message = await system_service.delete_menu(menu_id)
  838. if success:
  839. return ApiResponse(
  840. code=0,
  841. message=message,
  842. timestamp=datetime.now(timezone.utc).isoformat()
  843. ).model_dump()
  844. else:
  845. return ApiResponse(
  846. code=400,
  847. message=message,
  848. timestamp=datetime.now(timezone.utc).isoformat()
  849. ).model_dump()
  850. except Exception as e:
  851. logger.exception("删除菜单错误")
  852. return ApiResponse(
  853. code=500,
  854. message="服务器内部错误",
  855. timestamp=datetime.now(timezone.utc).isoformat()
  856. ).model_dump()
  857. @router.post("/admin/menus")
  858. async def create_menu(
  859. menu_data: dict,
  860. credentials: dict = Depends(get_current_user_with_refresh)
  861. ):
  862. """创建菜单"""
  863. try:
  864. payload = credentials
  865. if not payload:
  866. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  867. is_superuser = payload.get("is_superuser", False)
  868. if not is_superuser:
  869. return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  870. user_id = payload.get("sub")
  871. # 调用 service 层
  872. system_service = SystemService()
  873. success, message = await system_service.create_menu(menu_data , user_id)
  874. if success:
  875. return ApiResponse(code=0, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  876. else:
  877. return ApiResponse(code=400, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  878. except Exception as e:
  879. logger.exception("创建菜单错误")
  880. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  881. @router.put("/admin/menus/{menu_id}")
  882. async def update_menu(
  883. menu_id: str,
  884. menu_data: dict,
  885. credentials: dict = Depends(get_current_user_with_refresh)
  886. ):
  887. """更新菜单"""
  888. try:
  889. payload = credentials
  890. if not payload:
  891. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  892. is_superuser = payload.get("is_superuser", False)
  893. if not is_superuser:
  894. return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  895. user_id = payload.get("sub")
  896. # 调用 service 层
  897. system_service = SystemService()
  898. success, message = await system_service.update_menu(menu_id, menu_data , user_id)
  899. if success:
  900. return ApiResponse(code=0, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  901. else:
  902. return ApiResponse(code=400, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  903. except Exception as e:
  904. logger.exception("更新菜单错误")
  905. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  906. @router.delete("/admin/menus/{menu_id}")
  907. async def delete_menu(
  908. menu_id: str,
  909. credentials: dict = Depends(get_current_user_with_refresh)
  910. ):
  911. """删除菜单"""
  912. try:
  913. payload = credentials
  914. if not payload:
  915. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  916. is_superuser = payload.get("is_superuser", False)
  917. if not is_superuser:
  918. return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  919. # 调用 service 层
  920. system_service = SystemService()
  921. success, message = await system_service.delete_menu(menu_id)
  922. if success:
  923. return ApiResponse(code=0, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  924. else:
  925. return ApiResponse(code=400, message=message, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  926. except Exception as e:
  927. logger.exception("删除菜单错误")
  928. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  929. # 获取所有角色(用于下拉选择)
  930. @router.get("/roles/all")
  931. async def get_all_roles_simple(credentials: dict = Depends(get_current_user_with_refresh)):
  932. """获取所有角色(简化版,用于下拉选择)"""
  933. try:
  934. payload = credentials
  935. if not payload:
  936. return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  937. # 调用 service 层
  938. system_service = SystemService()
  939. roles = await system_service.get_all_roles_simple()
  940. return ApiResponse(code=0, message="获取角色列表成功", data=roles, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  941. except Exception as e:
  942. logger.exception("获取角色列表错误")
  943. return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
  944. @router.get("/apps")
  945. async def get_apps(
  946. page: int = 1,
  947. page_size: int = 20,
  948. keyword: str = "",
  949. status: str = "",
  950. credentials: dict = Depends(get_current_user_with_refresh)
  951. ):
  952. """获取应用列表"""
  953. try:
  954. # 验证令牌
  955. payload = credentials
  956. if not payload:
  957. return ApiResponse(
  958. code=200002,
  959. message="无效的访问令牌",
  960. timestamp=datetime.now(timezone.utc).isoformat()
  961. ).model_dump()
  962. user_id = payload.get("sub")
  963. # 调用 service 层检查用户角色
  964. system_service_ext = SystemServiceExt()
  965. is_app_manager = await system_service_ext.check_user_app_manager_role(user_id)
  966. # 调用 service 层获取应用列表
  967. apps, total = await system_service_ext.get_apps(page, page_size, user_id, is_app_manager, keyword, status)
  968. return ApiResponse(
  969. code=0,
  970. message="获取应用列表成功",
  971. data={
  972. "items": apps,
  973. "total": total,
  974. "page": page,
  975. "page_size": page_size
  976. },
  977. timestamp=datetime.now(timezone.utc).isoformat()
  978. ).model_dump()
  979. except Exception as e:
  980. logger.exception("获取应用列表错误")
  981. return ApiResponse(
  982. code=500001,
  983. message="服务器内部错误",
  984. timestamp=datetime.now(timezone.utc).isoformat()
  985. ).model_dump()
  986. @router.get("/apps/{app_id}")
  987. async def get_app_detail(
  988. app_id: str,
  989. credentials: dict = Depends(get_current_user_with_refresh)
  990. ):
  991. """获取应用详情(包含密钥)"""
  992. try:
  993. # 验证令牌
  994. payload = credentials
  995. if not payload:
  996. return ApiResponse(
  997. code=200002,
  998. message="无效的访问令牌",
  999. timestamp=datetime.now(timezone.utc).isoformat()
  1000. ).model_dump()
  1001. user_id = payload.get("sub")
  1002. # 调用 service 层
  1003. system_service_ext = SystemServiceExt()
  1004. app_detail = await system_service_ext.get_app_detail(app_id, user_id)
  1005. if not app_detail:
  1006. return ApiResponse(
  1007. code=200001,
  1008. message="应用不存在或无权限",
  1009. timestamp=datetime.now(timezone.utc).isoformat()
  1010. ).model_dump()
  1011. return ApiResponse(
  1012. code=0,
  1013. message="获取应用详情成功",
  1014. data=app_detail,
  1015. timestamp=datetime.now(timezone.utc).isoformat()
  1016. ).model_dump()
  1017. except Exception as e:
  1018. logger.exception("获取应用详情错误")
  1019. return ApiResponse(
  1020. code=500001,
  1021. message="服务器内部错误",
  1022. timestamp=datetime.now(timezone.utc).isoformat()
  1023. ).model_dump()
  1024. @router.post("/apps")
  1025. async def create_app(
  1026. request: Request,
  1027. app_data: dict,
  1028. credentials: dict = Depends(get_current_user_with_refresh)
  1029. ):
  1030. """创建应用"""
  1031. try:
  1032. # 验证令牌
  1033. payload = credentials
  1034. if not payload:
  1035. return ApiResponse(
  1036. code=200002,
  1037. message="无效的访问令牌",
  1038. timestamp=datetime.now(timezone.utc).isoformat()
  1039. ).model_dump()
  1040. user_id = payload.get("sub")
  1041. # 验证必要字段
  1042. if not app_data.get('name') or not app_data.get('redirect_uris'):
  1043. return ApiResponse(
  1044. code=100001,
  1045. message="缺少必要参数",
  1046. timestamp=datetime.now(timezone.utc).isoformat()
  1047. ).model_dump()
  1048. # 调用 service 层
  1049. system_service_ext = SystemServiceExt()
  1050. success, message, app_info = await system_service_ext.create_app(app_data, user_id)
  1051. if success:
  1052. return ApiResponse(
  1053. code=0,
  1054. message=message,
  1055. data=app_info,
  1056. timestamp=datetime.now(timezone.utc).isoformat()
  1057. ).model_dump()
  1058. else:
  1059. return ApiResponse(
  1060. code=500001,
  1061. message=message,
  1062. timestamp=datetime.now(timezone.utc).isoformat()
  1063. ).model_dump()
  1064. except Exception as e:
  1065. logger.exception("创建应用错误")
  1066. return ApiResponse(
  1067. code=500001,
  1068. message="服务器内部错误",
  1069. timestamp=datetime.now(timezone.utc).isoformat()
  1070. ).model_dump()
  1071. @router.put("/apps/{app_id}/status")
  1072. async def toggle_app_status(
  1073. app_id: str,
  1074. status_data: dict,
  1075. credentials: dict = Depends(get_current_user_with_refresh)
  1076. ):
  1077. """切换应用状态"""
  1078. try:
  1079. # 验证令牌
  1080. payload = credentials
  1081. if not payload:
  1082. return ApiResponse(
  1083. code=200002,
  1084. message="无效的访问令牌",
  1085. timestamp=datetime.now(timezone.utc).isoformat()
  1086. ).model_dump()
  1087. user_id = payload.get("sub")
  1088. is_active = status_data.get('is_active')
  1089. if is_active is None:
  1090. return ApiResponse(
  1091. code=100001,
  1092. message="缺少必要参数",
  1093. timestamp=datetime.now(timezone.utc).isoformat()
  1094. ).model_dump()
  1095. # 调用 service 层
  1096. system_service_ext = SystemServiceExt()
  1097. success, message = await system_service_ext.toggle_app_status(app_id, is_active, user_id)
  1098. if success:
  1099. return ApiResponse(
  1100. code=0,
  1101. message=message,
  1102. timestamp=datetime.now(timezone.utc).isoformat()
  1103. ).model_dump()
  1104. else:
  1105. return ApiResponse(
  1106. code=200001,
  1107. message=message,
  1108. timestamp=datetime.now(timezone.utc).isoformat()
  1109. ).model_dump()
  1110. except Exception as e:
  1111. logger.exception("切换应用状态错误")
  1112. return ApiResponse(
  1113. code=500001,
  1114. message="服务器内部错误",
  1115. timestamp=datetime.now(timezone.utc).isoformat()
  1116. ).model_dump()
  1117. @router.put("/apps/{app_id}")
  1118. async def update_app(
  1119. app_id: str,
  1120. app_data: dict,
  1121. credentials: dict = Depends(get_current_user_with_refresh)
  1122. ):
  1123. """更新应用信息"""
  1124. try:
  1125. # 验证令牌
  1126. payload = credentials
  1127. if not payload:
  1128. return ApiResponse(
  1129. code=200002,
  1130. message="无效的访问令牌",
  1131. timestamp=datetime.now(timezone.utc).isoformat()
  1132. ).model_dump()
  1133. user_id = payload.get("sub")
  1134. # 验证必要参数
  1135. name = app_data.get('name', '').strip()
  1136. if not name:
  1137. return ApiResponse(
  1138. code=100001,
  1139. message="应用名称不能为空",
  1140. timestamp=datetime.now(timezone.utc).isoformat()
  1141. ).model_dump()
  1142. # 调用 service 层
  1143. system_service_ext = SystemServiceExt()
  1144. success, message, app_result = await system_service_ext.update_app(app_id, app_data, user_id)
  1145. if success:
  1146. return ApiResponse(
  1147. code=0,
  1148. message=message,
  1149. data=app_result,
  1150. timestamp=datetime.now(timezone.utc).isoformat()
  1151. ).model_dump()
  1152. else:
  1153. return ApiResponse(
  1154. code=200001,
  1155. message=message,
  1156. timestamp=datetime.now(timezone.utc).isoformat()
  1157. ).model_dump()
  1158. except Exception as e:
  1159. logger.exception("更新应用错误")
  1160. return ApiResponse(
  1161. code=500001,
  1162. message="服务器内部错误",
  1163. timestamp=datetime.now(timezone.utc).isoformat()
  1164. ).model_dump()
  1165. @router.delete("/apps/{app_id}")
  1166. async def delete_app(
  1167. app_id: str,
  1168. credentials: dict = Depends(get_current_user_with_refresh)
  1169. ):
  1170. """删除应用"""
  1171. try:
  1172. # 验证令牌
  1173. payload = credentials
  1174. if not payload:
  1175. return ApiResponse(
  1176. code=200002,
  1177. message="无效的访问令牌",
  1178. timestamp=datetime.now(timezone.utc).isoformat()
  1179. ).model_dump()
  1180. user_id = payload.get("sub")
  1181. # 调用 service 层
  1182. system_service_ext = SystemServiceExt()
  1183. success, message = await system_service_ext.delete_app_by_id(app_id, user_id)
  1184. if success:
  1185. return ApiResponse(
  1186. code=0,
  1187. message=message,
  1188. timestamp=datetime.now(timezone.utc).isoformat()
  1189. ).model_dump()
  1190. else:
  1191. return ApiResponse(
  1192. code=200001,
  1193. message=message,
  1194. timestamp=datetime.now(timezone.utc).isoformat()
  1195. ).model_dump()
  1196. except Exception as e:
  1197. logger.exception("删除应用错误")
  1198. return ApiResponse(
  1199. code=500001,
  1200. message="服务器内部错误",
  1201. timestamp=datetime.now(timezone.utc).isoformat()
  1202. ).model_dump()
  1203. except Exception as e:
  1204. logger.exception("删除应用错误")
  1205. return ApiResponse(
  1206. code=500001,
  1207. message="服务器内部错误",
  1208. timestamp=datetime.now(timezone.utc).isoformat()
  1209. ).model_dump()
  1210. @router.post("/apps/{app_id}/reset-secret")
  1211. async def reset_app_secret(
  1212. app_id: str,
  1213. credentials: dict = Depends(get_current_user_with_refresh)
  1214. ):
  1215. """重置应用密钥"""
  1216. try:
  1217. # 验证令牌
  1218. payload = credentials
  1219. if not payload:
  1220. return ApiResponse(
  1221. code=200002,
  1222. message="无效的访问令牌",
  1223. timestamp=datetime.now(timezone.utc).isoformat()
  1224. ).model_dump()
  1225. user_id = payload.get("sub")
  1226. # 调用 service 层
  1227. system_service_ext = SystemServiceExt()
  1228. success, message, new_secret = await system_service_ext.reset_app_secret(app_id, user_id)
  1229. if success:
  1230. return ApiResponse(
  1231. code=0,
  1232. message=message,
  1233. data={"app_secret": new_secret},
  1234. timestamp=datetime.now(timezone.utc).isoformat()
  1235. ).model_dump()
  1236. else:
  1237. return ApiResponse(
  1238. code=200001,
  1239. message=message,
  1240. timestamp=datetime.now(timezone.utc).isoformat()
  1241. ).model_dump()
  1242. except Exception as e:
  1243. logger.exception("重置应用密钥错误")
  1244. return ApiResponse(
  1245. code=500001,
  1246. message="服务器内部错误",
  1247. timestamp=datetime.now(timezone.utc).isoformat()
  1248. ).model_dump()
  1249. def generate_random_string(length=32):
  1250. """生成随机字符串"""
  1251. import secrets
  1252. import string
  1253. alphabet = string.ascii_letters + string.digits
  1254. return ''.join(secrets.choice(alphabet) for _ in range(length))