officialAccountAccess.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. const db = require('../../plugin/DataBase/db')
  2. const AccessControl = require('../AccessControl')
  3. const { BaseStdResponse } = require('../../BaseStdResponse')
  4. function isMissing(value) {
  5. return value === '' || value === null || value === undefined
  6. }
  7. function errorResponse(base, msg) {
  8. return { ...base, msg }
  9. }
  10. async function queryAccount(studentNum) {
  11. const rows = await db.query(
  12. `SELECT uid, token, school_id, student_num, userAgent, state, create_user
  13. FROM lepao_account
  14. WHERE student_num = ?`,
  15. [studentNum]
  16. )
  17. return rows?.[0] || null
  18. }
  19. function validateRunnableAccount(account) {
  20. if (!account) {
  21. return errorResponse(BaseStdResponse.ERR, '未找到该乐跑账号')
  22. }
  23. if (account.state !== 1) {
  24. return errorResponse(BaseStdResponse.ERR, '仅状态为正常的账号可查看官方记录')
  25. }
  26. if (!account.uid || !account.token || !account.school_id) {
  27. return errorResponse(BaseStdResponse.ERR, '乐跑账号登录信息不完整,请使用登录器更新账号')
  28. }
  29. return null
  30. }
  31. async function loadUserOfficialAccount(uuid, studentNum) {
  32. const account = await queryAccount(studentNum)
  33. if (!account || account.create_user !== uuid) {
  34. return {
  35. error: errorResponse(BaseStdResponse.ERR, '未找到该乐跑账号或无权限操作')
  36. }
  37. }
  38. const invalid = validateRunnableAccount(account)
  39. if (invalid) return { error: invalid }
  40. return { account }
  41. }
  42. async function loadAdminOfficialAccount(uuid, studentNum) {
  43. const permission = await AccessControl.getPermission(uuid)
  44. if (!permission.includes('admin') && !permission.includes('service') && !permission.includes('server')) {
  45. return {
  46. error: BaseStdResponse.PERMISSION_DENIED
  47. }
  48. }
  49. const account = await queryAccount(studentNum)
  50. const invalid = validateRunnableAccount(account)
  51. if (invalid) return { error: invalid }
  52. return { account }
  53. }
  54. function isLoginExpiredError(error) {
  55. const msg = error?.message || ''
  56. return (
  57. error?.code === 'LEPAO_LOGIN_EXPIRED' ||
  58. String(msg).includes('重新登录') ||
  59. String(msg).includes('登录已过期') ||
  60. String(msg).includes('登录失效')
  61. )
  62. }
  63. async function markAccountLoginExpired(studentNum, logger) {
  64. if (!studentNum) return
  65. try {
  66. await db.query('UPDATE lepao_account SET state = 0, update_time = ? WHERE student_num = ?', [
  67. Date.now(),
  68. studentNum
  69. ])
  70. logger?.warn?.(`${studentNum} 官方乐跑登录已失效,账号状态已更新为未登录`)
  71. } catch (updateError) {
  72. logger?.error?.(`更新乐跑账号登录状态失败 ${studentNum}: ${updateError.stack || updateError}`)
  73. }
  74. }
  75. async function mapOfficialError(error, studentNum, logger) {
  76. if (isLoginExpiredError(error)) {
  77. await markAccountLoginExpired(studentNum, logger)
  78. return errorResponse(BaseStdResponse.ERR, '乐跑登录已过期,请使用登录器更新账号')
  79. }
  80. const msg = error?.message || '获取官方乐跑记录失败'
  81. return errorResponse(BaseStdResponse.ERR, msg)
  82. }
  83. /** 官方学期记录接口返回的 total_score_num 同步到 lepao_account.total_num */
  84. async function syncOfficialTotalNum(studentNum, officialData, logger) {
  85. if (!studentNum || !officialData) return
  86. const totalScoreNum = Number(officialData.total_score_num)
  87. if (!Number.isFinite(totalScoreNum)) return
  88. try {
  89. const rows = await db.query(
  90. 'UPDATE lepao_account SET total_num = ? WHERE student_num = ?',
  91. [totalScoreNum, studentNum]
  92. )
  93. } catch (error) {
  94. logger?.error?.(`同步官方 total_num 失败 ${studentNum}: ${error.stack || error}`)
  95. }
  96. }
  97. module.exports = {
  98. isMissing,
  99. loadUserOfficialAccount,
  100. loadAdminOfficialAccount,
  101. isLoginExpiredError,
  102. markAccountLoginExpired,
  103. mapOfficialError,
  104. syncOfficialTotalNum
  105. }