GetJkesRunOverview.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. const API = require('../../lib/API.js')
  2. const db = require('../../plugin/DataBase/db.js')
  3. const { BaseStdResponse } = require('../../BaseStdResponse.js')
  4. const AccessControl = require('../../lib/AccessControl.js')
  5. const { fetchJkesMonthKm, fetchJkesTotalKm } = require('../../plugin/jkes/stats')
  6. const {
  7. readState,
  8. DOUBLE_RUNS_CAP,
  9. refreshMonthKmFromApi,
  10. normalizeMonthTargetKm
  11. } = require('../../plugin/jkes/monthPolicy')
  12. const {
  13. markLoginExpiredByStudentNum,
  14. LOGIN_EXPIRED_MSG
  15. } = require('../../plugin/jkes/syncLepaoAccountFromToken')
  16. /**
  17. * 从 JKES 官方接口拉取本月/累计里程,并返回本地月度缓存。
  18. * monthTargetKm 为学校要求的「本月最低」参考,非可跑里程上限。
  19. */
  20. class GetJkesRunOverview extends API {
  21. constructor() {
  22. super()
  23. this.setPath('/Lepao/JkesRunOverview')
  24. this.setMethod('GET')
  25. }
  26. async onRequest(req, res) {
  27. const { uuid, session, student_num } = req.query
  28. if ([uuid, session, student_num].some((v) => v === '' || v == null))
  29. return res.json({
  30. ...BaseStdResponse.MISSING_PARAMETER
  31. })
  32. if (!await AccessControl.checkSession(uuid, session))
  33. return res.status(401).json({
  34. ...BaseStdResponse.ACCESS_DENIED
  35. })
  36. try {
  37. const rows = await db.query(
  38. `SELECT student_num, token, create_user, target_count
  39. FROM lepao_account WHERE student_num = ?`,
  40. [student_num]
  41. )
  42. if (!rows || rows.length === 0)
  43. return res.json({
  44. ...BaseStdResponse.ERR,
  45. msg: '未找到乐跑账号'
  46. })
  47. const acc = rows[0]
  48. if (acc.create_user !== uuid) {
  49. const permission = await AccessControl.getPermission(uuid)
  50. if (!permission.includes('admin') && !permission.includes('service'))
  51. return res.json({
  52. ...BaseStdResponse.ERR,
  53. msg: '无权查看该账号'
  54. })
  55. }
  56. if (!acc.token)
  57. return res.json({
  58. ...BaseStdResponse.ERR,
  59. msg: '账号未登录或 token 无效,请先更新账号'
  60. })
  61. const now = new Date()
  62. const y = now.getFullYear()
  63. const m = now.getMonth() + 1
  64. await refreshMonthKmFromApi(student_num, acc.token, now)
  65. const monthKm = await fetchJkesMonthKm(acc.token, y, m)
  66. const totalKm = await fetchJkesTotalKm(acc.token)
  67. const local = await readState(student_num, now)
  68. const monthTargetKm = normalizeMonthTargetKm(acc.target_count)
  69. return res.json({
  70. ...BaseStdResponse.OK,
  71. data: {
  72. student_num,
  73. monthKmOfficial: monthKm,
  74. totalKmOfficial: totalKm,
  75. monthKmCached: local.km,
  76. doubleRunsUsed: local.doubles,
  77. monthTargetKm,
  78. monthTargetIsMinimumNotCap: true,
  79. plannedDoubleRunDays: DOUBLE_RUNS_CAP
  80. }
  81. })
  82. } catch (e) {
  83. this.logger.error(`JkesRunOverview ${e.stack || e}`)
  84. if (e?.loginExpired) {
  85. await markLoginExpiredByStudentNum(student_num)
  86. return res.json({
  87. ...BaseStdResponse.ERR,
  88. msg: e.message || LOGIN_EXPIRED_MSG
  89. })
  90. }
  91. return res.json({
  92. ...BaseStdResponse.ERR,
  93. msg: '获取 JKES 跑步数据失败'
  94. })
  95. }
  96. }
  97. }
  98. module.exports.GetJkesRunOverview = GetJkesRunOverview