You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

37 lines
3.8 KiB

  1. import fs from 'node:fs'
  2. import crypto from 'node:crypto'
  3. import {login,call} from './role-permissions-live.mjs'
  4. const fixture=JSON.parse(fs.readFileSync('../../.codex-tmp/guide-formal/fixture.json')),session=await login('root'),token=session.accessToken,checks=[]
  5. const check=(name,pass,detail='')=>{checks.push({name,pass,detail});console.log(pass?'PASS':'FAIL',name);if(!pass)process.exitCode=1}
  6. let user
  7. try{
  8. const roles=(await call('auth/v1/roles/all',token)).data,role=(roles.records||roles).find(r=>r.code==='student')
  9. const me=(await call('auth/v1/auth/me',token)).data,password='G!'+crypto.randomBytes(7).toString('hex'),username='guide_'+crypto.randomBytes(5).toString('hex')
  10. const created=await call('auth/v1/users',token,{username,password,displayName:'作业指导闭环测试学员',departmentId:me.departmentId,roleIds:[role.id],defaultRoleId:role.id,enabled:true,remark:'UTE2E-GUIDE-FORMAL'})
  11. if(created.status!==200)throw new Error('测试学员创建失败 '+created.message)
  12. user=created.data
  13. const logged=await call('auth/v1/auth/login',null,{userId:user.id,password,roleCode:'student',rememberMe:false})
  14. const actor=logged.data?.accessToken
  15. if(!actor)throw new Error('测试学员登录失败 '+logged.status+' '+logged.message)
  16. const base=`tran/v1/teaching/guides/${fixture.id}`
  17. const content=await call(`tran/v1/content/projects/${fixture.id}`,actor);check('学员不能进入内容编辑接口',content.status===403)
  18. const detail=await call(base,actor);check('学员可以阅读正式发布版本',detail.status===200)
  19. check('学员投影没有文件存储 URI',!JSON.stringify(detail.data).includes('fsvc://'))
  20. const state=(await call(`${base}/reader-state`,actor)).data;check('学员看不到其他用户的笔记和收藏',state?.notes.length===0&&state.favorite===false)
  21. const saved=await call(`${base}/reader-state`,actor,{...state,pageId:'page:0',pageIndex:0,pageCount:3,favorite:true,notes:[{id:'student-note',pageId:'page:0',text:'学员本人私人笔记'}]},'PUT');check('学员能保存本人的阅读记录',saved.status===200)
  22. const owner=(await call(`${base}/reader-state`,token)).data;check('学员写入不覆盖教员记录',!owner.notes.some(n=>n.id==='student-note'))
  23. const stats=await call(`${base}/reader-statistics`,actor);check('学员不能查看教员聚合统计',stats.status===403)
  24. const start=await call(`${base}/reading/start`,actor,{},'PUT');check('开始阅读产生正式记录',start.status===200,start.message)
  25. const complete=await call(`${base}/reading/complete`,actor,{},'PUT');check('阅读完成记录成功',complete.status===200,complete.message)
  26. const feedback=await call(`${base}/feedback`,actor,{content:'实测反馈:狐狸和卡车指导书资源已加载,请复核说明。'});check('学员反馈写入正式服务',feedback.status===200)
  27. if(feedback.data?.id){const managed=await call(`${base}/feedback/${feedback.data.id}`,token,{version:feedback.data.version,status:'HANDLED',reply:'已通过正式接口复核。'},'PUT');check('教员回复并处理反馈',managed.status===200,managed.message)}
  28. const asset=detail.data?.assets.find(a=>a.type==='MODEL_FILE')
  29. const response=await fetch(`http://127.0.0.1:6180/api/${base}/assets/${asset.assetCode}/content`,{headers:{Authorization:`Bearer ${actor}`}})
  30. const bytes=await response.arrayBuffer();check('学员通过教学接口下载 GLB',response.ok&&new TextDecoder().decode(bytes.slice(0,4))==='glTF')
  31. await call('auth/v1/auth/logout',actor,{})
  32. }catch(e){check('权限与阅读反馈流程',false,e.message)}
  33. finally{
  34. if(user?.id){const current=await call(`auth/v1/users/${user.id}`,token);const removed=await call(`auth/v1/users/${user.id}`,token,{version:current.data.version},'DELETE');check('临时测试学员已清理',removed.status===200,removed.message)}
  35. fs.writeFileSync('reports/guide-formal-20260910/permissions.json',JSON.stringify({checks},null,2))
  36. }