b_user.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. package internal
  2. import (
  3. "context"
  4. "strings"
  5. "github.com/gogf/gf/v2/util/guid"
  6. "yx-dataset-server/app/errors"
  7. "yx-dataset-server/app/model"
  8. "yx-dataset-server/app/schema"
  9. "yx-dataset-server/library/redis"
  10. "yx-dataset-server/library/utils"
  11. )
  12. // NewUser 创建User
  13. func NewUser(
  14. mUser model.IUser,
  15. mRelation model.IDatasetRelation,
  16. mTrans model.ITrans,
  17. mMenu model.IMenu,
  18. mRoleMenu model.IRoleMenu,
  19. mDataset model.IDataset,
  20. mOrganization model.IOrganization,
  21. mRole model.IRole,
  22. ) *User {
  23. return &User{
  24. UserModel: mUser,
  25. relationModel: mRelation,
  26. transModel: mTrans,
  27. menuModel: mMenu,
  28. roleMenuModel: mRoleMenu,
  29. datasetModel: mDataset,
  30. orgModel: mOrganization,
  31. roleModel: mRole,
  32. }
  33. }
  34. // User 创建User对象
  35. type User struct {
  36. UserModel model.IUser
  37. relationModel model.IDatasetRelation
  38. transModel model.ITrans
  39. menuModel model.IMenu
  40. roleMenuModel model.IRoleMenu
  41. datasetModel model.IDataset
  42. orgModel model.IOrganization
  43. roleModel model.IRole
  44. }
  45. // classifyDatasets 按 type 分桶填充
  46. func classifyDatasets(user *schema.User, datasets schema.Datasets) {
  47. user.Datasets = datasets
  48. user.PublicDatasets = make(schema.Datasets, 0)
  49. user.OrgDatasets = make(schema.Datasets, 0)
  50. user.PersonalDatasets = make(schema.Datasets, 0)
  51. for _, d := range datasets {
  52. switch d.Type {
  53. case schema.DatasetTypePublic:
  54. user.PublicDatasets = append(user.PublicDatasets, d)
  55. case schema.DatasetTypeOrg:
  56. user.OrgDatasets = append(user.OrgDatasets, d)
  57. case schema.DatasetTypePersonal:
  58. user.PersonalDatasets = append(user.PersonalDatasets, d)
  59. }
  60. }
  61. }
  62. // loadUserDatasets 加载指定用户的可访问知识库并按类型分桶填充
  63. // 特殊规则:系统管理员(root 另行处理于 getRootInfo)——
  64. //
  65. // 可查看全部公共/共享知识库(type=1) + 本人的个人知识库(type=3)
  66. func (a *User) loadUserDatasets(ctx context.Context, user *schema.User) error {
  67. // 系统管理员:全部公共KB + 本人的个人KB
  68. if user.RoleId != "" {
  69. role, err := a.roleModel.Get(ctx, user.RoleId)
  70. if err != nil {
  71. return err
  72. }
  73. if role != nil && role.Code == RoleCodeSystemAdmin {
  74. return a.loadAdminDatasets(ctx, user)
  75. }
  76. }
  77. // 其他角色:仅限 DatasetRelation 里显式授权的
  78. rel, err := a.relationModel.Query(ctx, schema.DatasetRelationQueryParam{BizId: user.RecordID})
  79. if err != nil {
  80. return err
  81. }
  82. if len(rel.Data) == 0 {
  83. classifyDatasets(user, schema.Datasets{})
  84. return nil
  85. }
  86. datasets, err := a.datasetModel.Query(ctx, schema.DatasetQueryParam{RecordIds: rel.Data.ToDatasetIds()})
  87. if err != nil {
  88. return err
  89. }
  90. classifyDatasets(user, datasets.Data)
  91. return nil
  92. }
  93. // loadAdminDatasets 为 root / 系统管理员加载:全部公共KB + 本人个人KB
  94. func (a *User) loadAdminDatasets(ctx context.Context, user *schema.User) error {
  95. public, err := a.datasetModel.Query(ctx, schema.DatasetQueryParam{Type: schema.DatasetTypePublic})
  96. if err != nil {
  97. return err
  98. }
  99. all := make(schema.Datasets, 0, len(public.Data))
  100. all = append(all, public.Data...)
  101. // 本人个人知识库(通过 DatasetRelation 绑定)
  102. rel, err := a.relationModel.Query(ctx, schema.DatasetRelationQueryParam{
  103. BizId: user.RecordID,
  104. Type: schema.DatasetTypePersonal,
  105. })
  106. if err != nil {
  107. return err
  108. }
  109. if len(rel.Data) > 0 {
  110. personal, err := a.datasetModel.Query(ctx, schema.DatasetQueryParam{RecordIds: rel.Data.ToDatasetIds()})
  111. if err != nil {
  112. return err
  113. }
  114. all = append(all, personal.Data...)
  115. }
  116. classifyDatasets(user, all)
  117. return nil
  118. }
  119. // Query 查询数据
  120. func (a *User) Query(ctx context.Context, params schema.UserQueryParam, opts ...schema.UserOptions) (*schema.UserQueryResult, error) {
  121. if isSys, err := IsSystemAdmin(ctx, a.UserModel, a.roleModel); !isSys {
  122. if err != nil {
  123. return nil, err
  124. }
  125. current, err := a.UserModel.Get(ctx, GetUserID(ctx))
  126. if err != nil {
  127. return nil, err
  128. }
  129. params.OrgId = current.OrgId
  130. }
  131. result, err := a.UserModel.Query(ctx, params, opts...)
  132. if err != nil {
  133. return nil, err
  134. }
  135. result.Data.FillCreator(result.Data)
  136. for _, v := range result.Data {
  137. v.Used, _ = redis.GetRedisClient().Get(ctx, "chart:user:"+v.RecordID).Int()
  138. v.Unused = v.ChartNum - v.Used
  139. }
  140. roles, err := a.roleModel.Query(ctx, schema.RoleQueryParam{})
  141. if err != nil {
  142. return nil, err
  143. }
  144. result.Data.FillRoleName(roles.Data)
  145. orgs, err := a.orgModel.Query(ctx, schema.OrganizationQueryParam{})
  146. if err != nil {
  147. return nil, err
  148. }
  149. result.Data.FillOrgName(orgs.Data)
  150. return result, nil
  151. }
  152. // Get 查询指定数据
  153. func (a *User) Get(ctx context.Context, recordID string, opts ...schema.UserOptions) (*schema.User, error) {
  154. item, err := a.UserModel.Get(ctx, recordID, opts...)
  155. if err != nil {
  156. return nil, err
  157. } else if item == nil {
  158. return nil, errors.ErrNotFound
  159. }
  160. // 查询用户菜单
  161. roleMenu, err := a.roleMenuModel.Query(ctx, schema.RoleMenuQueryParam{RoleId: item.RoleId})
  162. if err != nil {
  163. return nil, err
  164. }
  165. menus, err := a.menuModel.Query(ctx, schema.MenuQueryParam{RecordIDs: roleMenu.Data.ToMenuIds()})
  166. if err != nil {
  167. return nil, err
  168. }
  169. item.Menu = menus.Data.ToTrees()
  170. role, err := a.roleModel.Get(ctx, item.RoleId)
  171. if err != nil {
  172. return nil, err
  173. }
  174. if role != nil {
  175. item.RoleCode = role.Code
  176. item.RoleName = role.Name
  177. }
  178. org, err := a.orgModel.Get(ctx, item.OrgId)
  179. if err != nil {
  180. return nil, err
  181. }
  182. if org != nil {
  183. item.OrgName = org.Name
  184. }
  185. if err := a.loadUserDatasets(ctx, item); err != nil {
  186. return nil, err
  187. }
  188. item.Password = "******"
  189. item.Used, _ = redis.GetRedisClient().Get(ctx, "chart:user:"+item.RecordID).Int()
  190. item.Unused = item.ChartNum - item.Used
  191. return item, nil
  192. }
  193. // GetCurrentUser 查询当前用户
  194. func (a *User) GetCurrentUser(ctx context.Context, recordID string, opts ...schema.UserOptions) (*schema.User, error) {
  195. if CheckIsRootUser(ctx) {
  196. return a.getRootInfo(ctx)
  197. }
  198. item, err := a.UserModel.Get(ctx, recordID, opts...)
  199. if err != nil {
  200. return nil, err
  201. } else if item == nil {
  202. return nil, errors.ErrNotFound
  203. }
  204. roleMenu, err := a.roleMenuModel.Query(ctx, schema.RoleMenuQueryParam{RoleId: item.RoleId})
  205. if err != nil {
  206. return nil, err
  207. }
  208. menus, err := a.menuModel.Query(ctx, schema.MenuQueryParam{RecordIDs: roleMenu.Data.ToMenuIds()})
  209. if err != nil {
  210. return nil, err
  211. }
  212. item.Menu = menus.Data.ToTrees()
  213. role, err := a.roleModel.Get(ctx, item.RoleId)
  214. if err != nil {
  215. return nil, err
  216. }
  217. if role != nil {
  218. item.RoleCode = role.Code
  219. item.RoleName = role.Name
  220. }
  221. org, err := a.orgModel.Get(ctx, item.OrgId)
  222. if err != nil {
  223. return nil, err
  224. }
  225. if org != nil {
  226. item.OrgName = org.Name
  227. }
  228. if err := a.loadUserDatasets(ctx, item); err != nil {
  229. return nil, err
  230. }
  231. item.Password = "******"
  232. item.Used, _ = redis.GetRedisClient().Get(ctx, "chart:user:"+item.RecordID).Int()
  233. item.Unused = item.ChartNum - item.Used
  234. return item, nil
  235. }
  236. // GetCurrentUserDatasets 获取当前用户有权限的知识库(按组织分组)
  237. func (a *User) GetCurrentUserDatasets(ctx context.Context, opts ...schema.UserOptions) (schema.Organizations, error) {
  238. rel, err := a.relationModel.Query(ctx, schema.DatasetRelationQueryParam{BizId: GetUserID(ctx)})
  239. if err != nil {
  240. return nil, err
  241. }
  242. dataset, err := a.datasetModel.Query(ctx, schema.DatasetQueryParam{RecordIds: rel.Data.ToDatasetIds()})
  243. if err != nil {
  244. return nil, err
  245. }
  246. orgs, err := a.orgModel.Query(ctx, schema.OrganizationQueryParam{RecordIds: dataset.Data.ToOrgIds()})
  247. if err != nil {
  248. return nil, err
  249. }
  250. orgs.Data.FillDataset(dataset.Data)
  251. return orgs.Data, nil
  252. }
  253. func (a *User) getUpdate(ctx context.Context, recordID string) (*schema.User, error) {
  254. return a.Get(ctx, recordID)
  255. }
  256. // Create 创建数据
  257. // item.Datasets 为分配给该用户的知识库列表(schema.Dataset,仅 RecordID 必填)
  258. // - 类型从知识库本身读取
  259. // - 仅允许分配 共享(1) / 企业(2) 两类;个人(3) 不由创建/编辑用户接口管理
  260. func (a *User) Create(ctx context.Context, item schema.User) error {
  261. item.RecordID = guid.S()
  262. item.Status = true
  263. item.Password = utils.SHA1HashString(strings.ToUpper(item.Password))
  264. return ExecTrans(ctx, a.transModel, func(ctx context.Context) error {
  265. if err := a.UserModel.Create(ctx, item); err != nil {
  266. return err
  267. }
  268. return a.syncAssignedDatasets(ctx, item.RecordID, item.Datasets)
  269. })
  270. }
  271. // syncAssignedDatasets 同步“分配给用户”的共享/企业 KB 关系(不影响个人 KB)
  272. func (a *User) syncAssignedDatasets(ctx context.Context, userId string, datasets schema.Datasets) error {
  273. // 仅清理 type=1/2 的分配,保留 type=3 个人 KB
  274. if err := a.relationModel.DeleteByBizIdAndType(ctx, userId, schema.DatasetTypePublic); err != nil {
  275. return err
  276. }
  277. if err := a.relationModel.DeleteByBizIdAndType(ctx, userId, schema.DatasetTypeOrg); err != nil {
  278. return err
  279. }
  280. for _, d := range datasets {
  281. if d.RecordID == "" {
  282. continue
  283. }
  284. ds, err := a.datasetModel.Get(ctx, d.RecordID)
  285. if err != nil {
  286. return err
  287. }
  288. if ds == nil {
  289. return errors.New400Response("知识库不存在: " + d.RecordID)
  290. }
  291. if ds.Type == schema.DatasetTypePersonal {
  292. // 个人知识库不通过“分配”流转
  293. continue
  294. }
  295. if err := a.relationModel.Create(ctx, schema.DatasetRelation{
  296. RecordID: guid.S(),
  297. DatasetId: ds.RecordID,
  298. BizId: userId,
  299. Type: ds.Type,
  300. CreatorId: GetUserID(ctx),
  301. }); err != nil {
  302. return err
  303. }
  304. }
  305. return nil
  306. }
  307. // Update 更新数据
  308. // 知识库权限变化后是否刷新对话助手,改为前端通过独立接口触发确认:
  309. //
  310. // GET /web/v1/chat_assistants/permission/check -> 检查是否一致
  311. // POST /web/v1/chat_assistants/permission/sync -> 用户确认后同步
  312. func (a *User) Update(ctx context.Context, recordID string, item schema.User) error {
  313. oldItem, err := a.UserModel.Get(ctx, recordID)
  314. if err != nil {
  315. return err
  316. } else if oldItem == nil {
  317. return errors.ErrNotFound
  318. }
  319. if item.Password != "" {
  320. item.Password = utils.SHA1HashString(strings.ToUpper(item.Password))
  321. }
  322. return ExecTrans(ctx, a.transModel, func(ctx context.Context) error {
  323. if err := a.syncAssignedDatasets(ctx, recordID, item.Datasets); err != nil {
  324. return err
  325. }
  326. return a.UserModel.Update(ctx, recordID, item)
  327. })
  328. }
  329. // Delete 删除数据
  330. func (a *User) Delete(ctx context.Context, recordID string) error {
  331. oldItem, err := a.UserModel.Get(ctx, recordID)
  332. if err != nil {
  333. return err
  334. } else if oldItem == nil {
  335. return errors.ErrNotFound
  336. }
  337. return ExecTrans(ctx, a.transModel, func(ctx context.Context) error {
  338. // 清理该用户的全部授权(含个人KB的映射)
  339. if err := a.relationModel.DeleteByBizId(ctx, recordID); err != nil {
  340. return err
  341. }
  342. return a.UserModel.Delete(ctx, recordID)
  343. })
  344. }
  345. // UpdateStatus 更新状态
  346. func (a *User) UpdateStatus(ctx context.Context, recordID string, status bool) error {
  347. oldItem, err := a.UserModel.Get(ctx, recordID)
  348. if err != nil {
  349. return err
  350. } else if oldItem == nil {
  351. return errors.ErrNotFound
  352. }
  353. return a.UserModel.UpdateStatus(ctx, recordID, status)
  354. }
  355. func (a *User) getRootInfo(ctx context.Context) (*schema.User, error) {
  356. user := GetRootUser()
  357. user.Password = "******"
  358. menu, err := a.menuModel.Query(ctx, schema.MenuQueryParam{})
  359. if err != nil {
  360. return nil, err
  361. }
  362. user.Menu = menu.Data.ToTrees()
  363. // root:全部公共/共享知识库 + root 本人的个人知识库
  364. if err := a.loadAdminDatasets(ctx, user); err != nil {
  365. return nil, err
  366. }
  367. return user, nil
  368. }