@strapi/admin 5.56.0 → 5.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/dist/admin/admin/src/components/Filters.js +1 -1
  2. package/dist/admin/admin/src/components/Filters.js.map +1 -1
  3. package/dist/admin/admin/src/components/Filters.mjs +1 -1
  4. package/dist/admin/admin/src/components/Filters.mjs.map +1 -1
  5. package/dist/admin/admin/src/components/FormInputs/Enumeration.js +2 -2
  6. package/dist/admin/admin/src/components/FormInputs/Enumeration.js.map +1 -1
  7. package/dist/admin/admin/src/components/FormInputs/Enumeration.mjs +2 -2
  8. package/dist/admin/admin/src/components/FormInputs/Enumeration.mjs.map +1 -1
  9. package/dist/admin/admin/src/components/MediaLibraryBanner.js +38 -2
  10. package/dist/admin/admin/src/components/MediaLibraryBanner.js.map +1 -1
  11. package/dist/admin/admin/src/components/MediaLibraryBanner.mjs +18 -2
  12. package/dist/admin/admin/src/components/MediaLibraryBanner.mjs.map +1 -1
  13. package/dist/admin/admin/src/components/RelativeTime.js +9 -0
  14. package/dist/admin/admin/src/components/RelativeTime.js.map +1 -1
  15. package/dist/admin/admin/src/components/RelativeTime.mjs +10 -1
  16. package/dist/admin/admin/src/components/RelativeTime.mjs.map +1 -1
  17. package/dist/admin/admin/src/components/TopBanners.js +52 -0
  18. package/dist/admin/admin/src/components/TopBanners.js.map +1 -0
  19. package/dist/admin/admin/src/components/TopBanners.mjs +30 -0
  20. package/dist/admin/admin/src/components/TopBanners.mjs.map +1 -0
  21. package/dist/admin/admin/src/features/Tracking.js +28 -8
  22. package/dist/admin/admin/src/features/Tracking.js.map +1 -1
  23. package/dist/admin/admin/src/features/Tracking.mjs +29 -10
  24. package/dist/admin/admin/src/features/Tracking.mjs.map +1 -1
  25. package/dist/admin/admin/src/layouts/AuthenticatedLayout.js +4 -20
  26. package/dist/admin/admin/src/layouts/AuthenticatedLayout.js.map +1 -1
  27. package/dist/admin/admin/src/layouts/AuthenticatedLayout.mjs +4 -20
  28. package/dist/admin/admin/src/layouts/AuthenticatedLayout.mjs.map +1 -1
  29. package/dist/admin/admin/src/layouts/useAuthenticatedAccessTracking.js +59 -0
  30. package/dist/admin/admin/src/layouts/useAuthenticatedAccessTracking.js.map +1 -0
  31. package/dist/admin/admin/src/layouts/useAuthenticatedAccessTracking.mjs +37 -0
  32. package/dist/admin/admin/src/layouts/useAuthenticatedAccessTracking.mjs.map +1 -0
  33. package/dist/admin/admin/src/translations/en.json.js +5 -0
  34. package/dist/admin/admin/src/translations/en.json.js.map +1 -1
  35. package/dist/admin/admin/src/translations/en.json.mjs +5 -0
  36. package/dist/admin/admin/src/translations/en.json.mjs.map +1 -1
  37. package/dist/admin/admin/src/utils/getFetchClient.js +3 -3
  38. package/dist/admin/admin/src/utils/getFetchClient.js.map +1 -1
  39. package/dist/admin/admin/src/utils/getFetchClient.mjs +2 -2
  40. package/dist/admin/admin/src/utils/getFetchClient.mjs.map +1 -1
  41. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.js +6 -1
  42. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.js.map +1 -1
  43. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.mjs +6 -1
  44. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.mjs.map +1 -1
  45. package/dist/admin/src/components/MediaLibraryBanner.d.ts +10 -1
  46. package/dist/admin/src/components/TopBanners.d.ts +8 -0
  47. package/dist/admin/src/features/Tracking.d.ts +12 -1
  48. package/dist/admin/src/layouts/useAuthenticatedAccessTracking.d.ts +6 -0
  49. package/dist/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.d.ts +5 -0
  50. package/dist/ee/server/src/controllers/admin.d.ts.map +1 -1
  51. package/dist/ee/server/src/controllers/authentication-utils/utils.d.ts +8 -2
  52. package/dist/ee/server/src/controllers/authentication-utils/utils.d.ts.map +1 -1
  53. package/dist/ee/server/src/controllers/authentication.d.ts.map +1 -1
  54. package/dist/ee/server/src/controllers/user.d.ts.map +1 -1
  55. package/dist/ee/server/src/index.d.ts +4 -1
  56. package/dist/ee/server/src/index.d.ts.map +1 -1
  57. package/dist/ee/server/src/services/index.d.ts +4 -1
  58. package/dist/ee/server/src/services/index.d.ts.map +1 -1
  59. package/dist/ee/server/src/services/metrics.d.ts.map +1 -1
  60. package/dist/ee/server/src/services/persist-tables.d.ts.map +1 -1
  61. package/dist/ee/server/src/services/seat-enforcement.d.ts +3 -1
  62. package/dist/ee/server/src/services/seat-enforcement.d.ts.map +1 -1
  63. package/dist/server/ee/server/src/controllers/admin.js +3 -4
  64. package/dist/server/ee/server/src/controllers/admin.js.map +1 -1
  65. package/dist/server/ee/server/src/controllers/admin.mjs +3 -4
  66. package/dist/server/ee/server/src/controllers/admin.mjs.map +1 -1
  67. package/dist/server/ee/server/src/controllers/authentication-utils/utils.js +2 -2
  68. package/dist/server/ee/server/src/controllers/authentication-utils/utils.js.map +1 -1
  69. package/dist/server/ee/server/src/controllers/authentication-utils/utils.mjs +2 -2
  70. package/dist/server/ee/server/src/controllers/authentication-utils/utils.mjs.map +1 -1
  71. package/dist/server/ee/server/src/controllers/authentication.js +11 -11
  72. package/dist/server/ee/server/src/controllers/authentication.js.map +1 -1
  73. package/dist/server/ee/server/src/controllers/authentication.mjs +11 -11
  74. package/dist/server/ee/server/src/controllers/authentication.mjs.map +1 -1
  75. package/dist/server/ee/server/src/controllers/user.js +7 -8
  76. package/dist/server/ee/server/src/controllers/user.js.map +1 -1
  77. package/dist/server/ee/server/src/controllers/user.mjs +8 -9
  78. package/dist/server/ee/server/src/controllers/user.mjs.map +1 -1
  79. package/dist/server/ee/server/src/services/metrics.js +9 -7
  80. package/dist/server/ee/server/src/services/metrics.js.map +1 -1
  81. package/dist/server/ee/server/src/services/metrics.mjs +9 -7
  82. package/dist/server/ee/server/src/services/metrics.mjs.map +1 -1
  83. package/dist/server/ee/server/src/services/persist-tables.js +3 -4
  84. package/dist/server/ee/server/src/services/persist-tables.js.map +1 -1
  85. package/dist/server/ee/server/src/services/persist-tables.mjs +3 -4
  86. package/dist/server/ee/server/src/services/persist-tables.mjs.map +1 -1
  87. package/dist/server/ee/server/src/services/role.js +2 -2
  88. package/dist/server/ee/server/src/services/role.js.map +1 -1
  89. package/dist/server/ee/server/src/services/role.mjs +1 -1
  90. package/dist/server/ee/server/src/services/role.mjs.map +1 -1
  91. package/dist/server/ee/server/src/services/seat-enforcement.js +20 -20
  92. package/dist/server/ee/server/src/services/seat-enforcement.js.map +1 -1
  93. package/dist/server/ee/server/src/services/seat-enforcement.mjs +20 -20
  94. package/dist/server/ee/server/src/services/seat-enforcement.mjs.map +1 -1
  95. package/dist/server/ee/server/src/services/user.js +1 -2
  96. package/dist/server/ee/server/src/services/user.js.map +1 -1
  97. package/dist/server/ee/server/src/services/user.mjs +2 -3
  98. package/dist/server/ee/server/src/services/user.mjs.map +1 -1
  99. package/dist/server/ee/server/src/utils/sso-lock.js +2 -2
  100. package/dist/server/ee/server/src/utils/sso-lock.js.map +1 -1
  101. package/dist/server/ee/server/src/utils/sso-lock.mjs +1 -1
  102. package/dist/server/ee/server/src/utils/sso-lock.mjs.map +1 -1
  103. package/dist/server/server/src/audit-logs/admin-users.js +3 -3
  104. package/dist/server/server/src/audit-logs/admin-users.js.map +1 -1
  105. package/dist/server/server/src/audit-logs/admin-users.mjs +2 -2
  106. package/dist/server/server/src/audit-logs/admin-users.mjs.map +1 -1
  107. package/dist/server/server/src/audit-logs/tokens.js +3 -3
  108. package/dist/server/server/src/audit-logs/tokens.js.map +1 -1
  109. package/dist/server/server/src/audit-logs/tokens.mjs +2 -2
  110. package/dist/server/server/src/audit-logs/tokens.mjs.map +1 -1
  111. package/dist/server/server/src/audit-logs/webhooks.js +2 -2
  112. package/dist/server/server/src/audit-logs/webhooks.js.map +1 -1
  113. package/dist/server/server/src/audit-logs/webhooks.mjs +1 -1
  114. package/dist/server/server/src/audit-logs/webhooks.mjs.map +1 -1
  115. package/dist/server/server/src/bootstrap.js +6 -4
  116. package/dist/server/server/src/bootstrap.js.map +1 -1
  117. package/dist/server/server/src/bootstrap.mjs +6 -4
  118. package/dist/server/server/src/bootstrap.mjs.map +1 -1
  119. package/dist/server/server/src/controllers/admin-token.js +8 -8
  120. package/dist/server/server/src/controllers/admin-token.js.map +1 -1
  121. package/dist/server/server/src/controllers/admin-token.mjs +4 -4
  122. package/dist/server/server/src/controllers/admin-token.mjs.map +1 -1
  123. package/dist/server/server/src/controllers/admin.js +3 -5
  124. package/dist/server/server/src/controllers/admin.js.map +1 -1
  125. package/dist/server/server/src/controllers/admin.mjs +2 -4
  126. package/dist/server/server/src/controllers/admin.mjs.map +1 -1
  127. package/dist/server/server/src/controllers/api-token.js +8 -8
  128. package/dist/server/server/src/controllers/api-token.js.map +1 -1
  129. package/dist/server/server/src/controllers/api-token.mjs +4 -4
  130. package/dist/server/server/src/controllers/api-token.mjs.map +1 -1
  131. package/dist/server/server/src/controllers/formatters/conditions.js +2 -2
  132. package/dist/server/server/src/controllers/formatters/conditions.js.map +1 -1
  133. package/dist/server/server/src/controllers/formatters/conditions.mjs +2 -2
  134. package/dist/server/server/src/controllers/formatters/conditions.mjs.map +1 -1
  135. package/dist/server/server/src/controllers/transfer/index.js +2 -2
  136. package/dist/server/server/src/controllers/transfer/index.js.map +1 -1
  137. package/dist/server/server/src/controllers/transfer/index.mjs +2 -2
  138. package/dist/server/server/src/controllers/transfer/index.mjs.map +1 -1
  139. package/dist/server/server/src/controllers/transfer/token.js +8 -8
  140. package/dist/server/server/src/controllers/transfer/token.js.map +1 -1
  141. package/dist/server/server/src/controllers/transfer/token.mjs +4 -4
  142. package/dist/server/server/src/controllers/transfer/token.mjs.map +1 -1
  143. package/dist/server/server/src/domain/action/index.js +18 -16
  144. package/dist/server/server/src/domain/action/index.js.map +1 -1
  145. package/dist/server/server/src/domain/action/index.mjs +16 -14
  146. package/dist/server/server/src/domain/action/index.mjs.map +1 -1
  147. package/dist/server/server/src/domain/action/provider.mjs +4 -4
  148. package/dist/server/server/src/domain/action/provider.mjs.map +1 -1
  149. package/dist/server/server/src/domain/condition/index.js +7 -4
  150. package/dist/server/server/src/domain/condition/index.js.map +1 -1
  151. package/dist/server/server/src/domain/condition/index.mjs +7 -4
  152. package/dist/server/server/src/domain/condition/index.mjs.map +1 -1
  153. package/dist/server/server/src/domain/permission/index.js +24 -15
  154. package/dist/server/server/src/domain/permission/index.js.map +1 -1
  155. package/dist/server/server/src/domain/permission/index.mjs +21 -12
  156. package/dist/server/server/src/domain/permission/index.mjs.map +1 -1
  157. package/dist/server/server/src/middlewares/rateLimit.js +5 -5
  158. package/dist/server/server/src/middlewares/rateLimit.js.map +1 -1
  159. package/dist/server/server/src/middlewares/rateLimit.mjs +4 -4
  160. package/dist/server/server/src/middlewares/rateLimit.mjs.map +1 -1
  161. package/dist/server/server/src/register.js +6 -0
  162. package/dist/server/server/src/register.js.map +1 -1
  163. package/dist/server/server/src/register.mjs +6 -0
  164. package/dist/server/server/src/register.mjs.map +1 -1
  165. package/dist/server/server/src/services/action.js +1 -2
  166. package/dist/server/server/src/services/action.js.map +1 -1
  167. package/dist/server/server/src/services/action.mjs +1 -2
  168. package/dist/server/server/src/services/action.mjs.map +1 -1
  169. package/dist/server/server/src/services/api-token.js +61 -49
  170. package/dist/server/server/src/services/api-token.js.map +1 -1
  171. package/dist/server/server/src/services/api-token.mjs +53 -41
  172. package/dist/server/server/src/services/api-token.mjs.map +1 -1
  173. package/dist/server/server/src/services/condition.js +2 -2
  174. package/dist/server/server/src/services/condition.js.map +1 -1
  175. package/dist/server/server/src/services/condition.mjs +1 -1
  176. package/dist/server/server/src/services/condition.mjs.map +1 -1
  177. package/dist/server/server/src/services/content-type.js +5 -4
  178. package/dist/server/server/src/services/content-type.js.map +1 -1
  179. package/dist/server/server/src/services/content-type.mjs +8 -7
  180. package/dist/server/server/src/services/content-type.mjs.map +1 -1
  181. package/dist/server/server/src/services/homepage.js +2 -1
  182. package/dist/server/server/src/services/homepage.js.map +1 -1
  183. package/dist/server/server/src/services/homepage.mjs +2 -1
  184. package/dist/server/server/src/services/homepage.mjs.map +1 -1
  185. package/dist/server/server/src/services/passport/local-strategy.js +2 -2
  186. package/dist/server/server/src/services/passport/local-strategy.js.map +1 -1
  187. package/dist/server/server/src/services/passport/local-strategy.mjs +1 -1
  188. package/dist/server/server/src/services/passport/local-strategy.mjs.map +1 -1
  189. package/dist/server/server/src/services/passport.js +1 -2
  190. package/dist/server/server/src/services/passport.js.map +1 -1
  191. package/dist/server/server/src/services/passport.mjs +1 -2
  192. package/dist/server/server/src/services/passport.mjs.map +1 -1
  193. package/dist/server/server/src/services/permission/engine.js +4 -4
  194. package/dist/server/server/src/services/permission/engine.js.map +1 -1
  195. package/dist/server/server/src/services/permission/engine.mjs +2 -2
  196. package/dist/server/server/src/services/permission/engine.mjs.map +1 -1
  197. package/dist/server/server/src/services/permission/permissions-manager/index.js +2 -3
  198. package/dist/server/server/src/services/permission/permissions-manager/index.js.map +1 -1
  199. package/dist/server/server/src/services/permission/permissions-manager/index.mjs +1 -2
  200. package/dist/server/server/src/services/permission/permissions-manager/index.mjs.map +1 -1
  201. package/dist/server/server/src/services/permission/permissions-manager/permission-fields.js +6 -6
  202. package/dist/server/server/src/services/permission/permissions-manager/permission-fields.js.map +1 -1
  203. package/dist/server/server/src/services/permission/permissions-manager/permission-fields.mjs +4 -4
  204. package/dist/server/server/src/services/permission/permissions-manager/permission-fields.mjs.map +1 -1
  205. package/dist/server/server/src/services/permission/permissions-manager/sanitize.js +47 -41
  206. package/dist/server/server/src/services/permission/permissions-manager/sanitize.js.map +1 -1
  207. package/dist/server/server/src/services/permission/permissions-manager/sanitize.mjs +44 -38
  208. package/dist/server/server/src/services/permission/permissions-manager/sanitize.mjs.map +1 -1
  209. package/dist/server/server/src/services/permission/permissions-manager/validate.js +30 -26
  210. package/dist/server/server/src/services/permission/permissions-manager/validate.js.map +1 -1
  211. package/dist/server/server/src/services/permission/permissions-manager/validate.mjs +28 -24
  212. package/dist/server/server/src/services/permission/permissions-manager/validate.mjs.map +1 -1
  213. package/dist/server/server/src/services/permission/queries.js +9 -9
  214. package/dist/server/server/src/services/permission/queries.js.map +1 -1
  215. package/dist/server/server/src/services/permission/queries.mjs +9 -9
  216. package/dist/server/server/src/services/permission/queries.mjs.map +1 -1
  217. package/dist/server/server/src/services/permission/rename-fields.js +118 -0
  218. package/dist/server/server/src/services/permission/rename-fields.js.map +1 -0
  219. package/dist/server/server/src/services/permission/rename-fields.mjs +116 -0
  220. package/dist/server/server/src/services/permission/rename-fields.mjs.map +1 -0
  221. package/dist/server/server/src/services/permission/sections-builder/index.js +2 -2
  222. package/dist/server/server/src/services/permission/sections-builder/index.js.map +1 -1
  223. package/dist/server/server/src/services/permission/sections-builder/index.mjs +2 -2
  224. package/dist/server/server/src/services/permission/sections-builder/index.mjs.map +1 -1
  225. package/dist/server/server/src/services/permission/sections-builder/section.js +1 -2
  226. package/dist/server/server/src/services/permission/sections-builder/section.js.map +1 -1
  227. package/dist/server/server/src/services/permission/sections-builder/section.mjs +1 -2
  228. package/dist/server/server/src/services/permission/sections-builder/section.mjs.map +1 -1
  229. package/dist/server/server/src/services/permission/sections-builder/utils.js +6 -6
  230. package/dist/server/server/src/services/permission/sections-builder/utils.js.map +1 -1
  231. package/dist/server/server/src/services/permission/sections-builder/utils.mjs +4 -4
  232. package/dist/server/server/src/services/permission/sections-builder/utils.mjs.map +1 -1
  233. package/dist/server/server/src/services/role.js +20 -19
  234. package/dist/server/server/src/services/role.js.map +1 -1
  235. package/dist/server/server/src/services/role.mjs +20 -19
  236. package/dist/server/server/src/services/role.mjs.map +1 -1
  237. package/dist/server/server/src/services/transfer/token.js +20 -16
  238. package/dist/server/server/src/services/transfer/token.js.map +1 -1
  239. package/dist/server/server/src/services/transfer/token.mjs +14 -10
  240. package/dist/server/server/src/services/transfer/token.mjs.map +1 -1
  241. package/dist/server/server/src/services/user.js +2 -3
  242. package/dist/server/server/src/services/user.js.map +1 -1
  243. package/dist/server/server/src/services/user.mjs +3 -4
  244. package/dist/server/server/src/services/user.mjs.map +1 -1
  245. package/dist/server/server/src/strategies/api-token-utils.js +2 -3
  246. package/dist/server/server/src/strategies/api-token-utils.js.map +1 -1
  247. package/dist/server/server/src/strategies/api-token-utils.mjs +2 -3
  248. package/dist/server/server/src/strategies/api-token-utils.mjs.map +1 -1
  249. package/dist/server/server/src/strategies/content-api-token.js +3 -3
  250. package/dist/server/server/src/strategies/content-api-token.js.map +1 -1
  251. package/dist/server/server/src/strategies/content-api-token.mjs +1 -1
  252. package/dist/server/server/src/strategies/content-api-token.mjs.map +1 -1
  253. package/dist/server/server/src/strategies/data-transfer.js +4 -4
  254. package/dist/server/server/src/strategies/data-transfer.js.map +1 -1
  255. package/dist/server/server/src/strategies/data-transfer.mjs +3 -3
  256. package/dist/server/server/src/strategies/data-transfer.mjs.map +1 -1
  257. package/dist/server/server/src/validation/common-validators.js +9 -10
  258. package/dist/server/server/src/validation/common-validators.js.map +1 -1
  259. package/dist/server/server/src/validation/common-validators.mjs +13 -14
  260. package/dist/server/server/src/validation/common-validators.mjs.map +1 -1
  261. package/dist/server/server/src/validation/user.js +1 -2
  262. package/dist/server/server/src/validation/user.js.map +1 -1
  263. package/dist/server/server/src/validation/user.mjs +1 -2
  264. package/dist/server/server/src/validation/user.mjs.map +1 -1
  265. package/dist/server/src/audit-logs/tokens.d.ts.map +1 -1
  266. package/dist/server/src/bootstrap.d.ts.map +1 -1
  267. package/dist/server/src/controllers/admin-token.d.ts.map +1 -1
  268. package/dist/server/src/controllers/admin.d.ts.map +1 -1
  269. package/dist/server/src/controllers/api-token.d.ts.map +1 -1
  270. package/dist/server/src/controllers/formatters/conditions.d.ts +1 -1
  271. package/dist/server/src/controllers/formatters/conditions.d.ts.map +1 -1
  272. package/dist/server/src/controllers/homepage.d.ts +1 -1
  273. package/dist/server/src/controllers/index.d.ts +1 -1
  274. package/dist/server/src/controllers/transfer/index.d.ts.map +1 -1
  275. package/dist/server/src/controllers/transfer/token.d.ts.map +1 -1
  276. package/dist/server/src/domain/action/index.d.ts +1 -0
  277. package/dist/server/src/domain/action/index.d.ts.map +1 -1
  278. package/dist/server/src/domain/condition/index.d.ts +2 -2
  279. package/dist/server/src/domain/condition/index.d.ts.map +1 -1
  280. package/dist/server/src/domain/permission/index.d.ts.map +1 -1
  281. package/dist/server/src/index.d.ts +3 -3
  282. package/dist/server/src/index.d.ts.map +1 -1
  283. package/dist/server/src/middlewares/index.d.ts.map +1 -1
  284. package/dist/server/src/middlewares/rateLimit.d.ts.map +1 -1
  285. package/dist/server/src/register.d.ts.map +1 -1
  286. package/dist/server/src/services/action.d.ts.map +1 -1
  287. package/dist/server/src/services/api-token.d.ts.map +1 -1
  288. package/dist/server/src/services/condition.d.ts.map +1 -1
  289. package/dist/server/src/services/content-type.d.ts.map +1 -1
  290. package/dist/server/src/services/homepage.d.ts +1 -1
  291. package/dist/server/src/services/homepage.d.ts.map +1 -1
  292. package/dist/server/src/services/index.d.ts +2 -2
  293. package/dist/server/src/services/index.d.ts.map +1 -1
  294. package/dist/server/src/services/passport/local-strategy.d.ts.map +1 -1
  295. package/dist/server/src/services/passport.d.ts.map +1 -1
  296. package/dist/server/src/services/permission/engine.d.ts.map +1 -1
  297. package/dist/server/src/services/permission/permissions-manager/permission-fields.d.ts.map +1 -1
  298. package/dist/server/src/services/permission/permissions-manager/sanitize.d.ts.map +1 -1
  299. package/dist/server/src/services/permission/permissions-manager/validate.d.ts.map +1 -1
  300. package/dist/server/src/services/permission/queries.d.ts.map +1 -1
  301. package/dist/server/src/services/permission/rename-fields.d.ts +21 -0
  302. package/dist/server/src/services/permission/rename-fields.d.ts.map +1 -0
  303. package/dist/server/src/services/permission/sections-builder/section.d.ts.map +1 -1
  304. package/dist/server/src/services/permission/sections-builder/utils.d.ts +1 -1
  305. package/dist/server/src/services/permission/sections-builder/utils.d.ts.map +1 -1
  306. package/dist/server/src/services/role.d.ts +1 -1
  307. package/dist/server/src/services/role.d.ts.map +1 -1
  308. package/dist/server/src/services/transfer/token.d.ts.map +1 -1
  309. package/dist/server/src/strategies/content-api-token.d.ts.map +1 -1
  310. package/dist/server/src/validation/user.d.ts.map +1 -1
  311. package/package.json +9 -9
@@ -1 +1 @@
1
- {"version":3,"file":"user.js","sources":["../../../../../../ee/server/src/services/user.ts"],"sourcesContent":["import _ from 'lodash';\nimport { pipe, map, castArray, toNumber } from 'lodash/fp';\nimport { arrays, errors } from '@strapi/utils';\nimport { hasSuperAdminRole } from '../../../../server/src/domain/user';\nimport constants from '../../../../server/src/services/constants';\nimport {\n LEGACY_USER_EVENTS,\n emitAdminUserDeleted,\n emitAdminUserUpdateAudits,\n touchesTrackedFields,\n} from '../../../../server/src/audit-logs/admin-users';\nimport { getService } from '../utils';\n\nconst { ValidationError } = errors;\nconst { SUPER_ADMIN_CODE } = constants;\n\nconst getSessionManager = () => {\n const manager = strapi.sessionManager;\n return manager ?? null;\n};\n\n/** Checks if ee disabled users list needs to be updated\n * @param {string} id\n * @param {object} input\n */\nconst updateEEDisabledUsersList = async (id: string, input: any) => {\n const disabledUsers = await getService('seat-enforcement').getDisabledUserList();\n\n if (!disabledUsers) {\n return;\n }\n\n const user = disabledUsers.find((user: any) => user.id === Number(id));\n if (!user) {\n return;\n }\n\n if (user.isActive !== input.isActive) {\n const newDisabledUsersList = disabledUsers.filter((user: any) => user.id !== Number(id));\n await strapi.store.set({\n type: 'ee',\n key: 'disabled_users',\n value: newDisabledUsersList,\n });\n }\n};\n\nconst castNumberArray = pipe(castArray, map(toNumber));\n\nconst removeFromEEDisabledUsersList = async (ids: unknown) => {\n let idsToCheck: any;\n if (typeof ids === 'object') {\n idsToCheck = castNumberArray(ids);\n } else {\n idsToCheck = [Number(ids)];\n }\n\n const disabledUsers = await getService('seat-enforcement').getDisabledUserList();\n\n if (!disabledUsers) {\n return;\n }\n\n const newDisabledUsersList = disabledUsers.filter((user: any) => !idsToCheck.includes(user.id));\n await strapi.store.set({\n type: 'ee',\n key: 'disabled_users',\n value: newDisabledUsersList,\n });\n};\n\n/**\n * Update a user in database\n * @param id query params to find the user to update\n * @param attributes A partial user object\n * @returns {Promise<user>}\n */\nconst updateById = async (id: any, attributes: any) => {\n // Check at least one super admin remains\n if (_.has(attributes, 'roles')) {\n const lastAdminUser = await isLastSuperAdminUser(id);\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n const willRemoveSuperAdminRole = !arrays.includesString(attributes.roles, superAdminRole.id);\n\n if (lastAdminUser && willRemoveSuperAdminRole) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n\n // cannot disable last super admin\n if (attributes.isActive === false) {\n const lastAdminUser = await isLastSuperAdminUser(id);\n if (lastAdminUser) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n\n // The audit log records what changed, so it needs the row before the write\n const previous = touchesTrackedFields(attributes)\n ? await strapi.db.query('admin::user').findOne({ where: { id }, populate: ['roles'] })\n : null;\n\n // hash password if a new one is sent\n if (_.has(attributes, 'password')) {\n const hashedPassword = await getService('auth').hashPassword(attributes.password);\n\n const updatedUser = await strapi.db.query('admin::user').update({\n where: { id },\n data: {\n ...attributes,\n password: hashedPassword,\n },\n populate: ['roles'],\n });\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.UPDATE, { user: sanitizeUser(updatedUser) });\n await emitAdminUserUpdateAudits({ strapi }, { previous, updated: updatedUser, attributes });\n\n return updatedUser;\n }\n\n const updatedUser = await strapi.db.query('admin::user').update({\n where: { id },\n data: attributes,\n populate: ['roles'],\n });\n\n await updateEEDisabledUsersList(id, attributes);\n\n if (updatedUser) {\n strapi.eventHub.emit(LEGACY_USER_EVENTS.UPDATE, { user: sanitizeUser(updatedUser) });\n await emitAdminUserUpdateAudits({ strapi }, { previous, updated: updatedUser, attributes });\n }\n\n return updatedUser;\n};\n\n/** Delete a user\n * @param id id of the user to delete\n * @returns {Promise<user>}\n */\nconst deleteById = async (id: unknown) => {\n // Check at least one super admin remains\n const userToDelete = await strapi.db.query('admin::user').findOne({\n where: { id },\n populate: ['roles'],\n });\n\n if (!userToDelete) {\n return null;\n }\n\n if (userToDelete) {\n if (userToDelete.roles.some((r: any) => r.code === SUPER_ADMIN_CODE)) {\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n if (superAdminRole.usersCount === 1) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n }\n\n const deletedUser = await strapi.db\n .query('admin::user')\n .delete({ where: { id }, populate: ['roles'] });\n\n // Invalidate all sessions for the deleted user\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('admin')) {\n await sessionManager('admin').invalidateRefreshToken(String(id));\n }\n\n await removeFromEEDisabledUsersList(id);\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.DELETE, { user: sanitizeUser(deletedUser) });\n await emitAdminUserDeleted({ strapi }, deletedUser);\n\n return deletedUser;\n};\n\n/** Delete a user\n * @param ids ids of the users to delete\n * @returns {Promise<user>}\n */\nconst deleteByIds = async (ids: any) => {\n // Check at least one super admin remains\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n const nbOfSuperAdminToDelete = await strapi.db.query('admin::user').count({\n where: {\n id: ids,\n roles: { id: superAdminRole.id },\n },\n });\n\n if (superAdminRole.usersCount === nbOfSuperAdminToDelete) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n\n const deletedUsers = [];\n for (const id of ids) {\n const deletedUser = await strapi.db.query('admin::user').delete({\n where: { id },\n populate: ['roles'],\n });\n\n // Invalidate all sessions for the deleted user\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('admin')) {\n await sessionManager('admin').invalidateRefreshToken(String(id));\n }\n\n deletedUsers.push(deletedUser);\n }\n\n await removeFromEEDisabledUsersList(ids);\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.DELETE, {\n users: deletedUsers.map((deletedUser) => sanitizeUser(deletedUser)),\n });\n\n for (const deletedUser of deletedUsers) {\n await emitAdminUserDeleted({ strapi }, deletedUser);\n }\n\n return deletedUsers;\n};\n\nconst sanitizeUserRoles = (role: unknown) => _.pick(role, ['id', 'name', 'description', 'code']);\n\n/**\n * Check if a user is the last super admin\n * @param {int|string} userId user's id to look for\n */\nconst isLastSuperAdminUser = async (userId: unknown) => {\n const user = (await findOne(userId)) as any;\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n\n return superAdminRole.usersCount === 1 && hasSuperAdminRole(user);\n};\n\n/**\n * Remove private user fields\n * @param {Object} user - user to sanitize\n */\nconst sanitizeUser = (user: any) => {\n return {\n ..._.omit(user, [\n 'password',\n 'resetPasswordToken',\n 'resetPasswordTokenExpiresAt',\n 'registrationToken',\n 'roles',\n ]),\n roles: user.roles && user.roles.map(sanitizeUserRoles),\n };\n};\n\n/**\n * Find one user\n */\nconst findOne = async (id: any, populate = ['roles']) => {\n return strapi.db.query('admin::user').findOne({ where: { id }, populate });\n};\n\nconst getCurrentActiveUserCount = async () => {\n return strapi.db.query('admin::user').count({ where: { isActive: true } });\n};\n\nexport default {\n updateEEDisabledUsersList,\n removeFromEEDisabledUsersList,\n getCurrentActiveUserCount,\n deleteByIds,\n deleteById,\n updateById,\n};\n"],"names":["ValidationError","errors","SUPER_ADMIN_CODE","constants","getSessionManager","manager","strapi","sessionManager","updateEEDisabledUsersList","id","input","disabledUsers","getService","getDisabledUserList","user","find","Number","isActive","newDisabledUsersList","filter","store","set","type","key","value","castNumberArray","pipe","castArray","map","toNumber","removeFromEEDisabledUsersList","ids","idsToCheck","includes","updateById","attributes","_","has","lastAdminUser","isLastSuperAdminUser","superAdminRole","getSuperAdminWithUsersCount","willRemoveSuperAdminRole","arrays","includesString","roles","previous","touchesTrackedFields","db","query","findOne","where","populate","hashedPassword","hashPassword","password","updatedUser","update","data","eventHub","emit","LEGACY_USER_EVENTS","UPDATE","sanitizeUser","emitAdminUserUpdateAudits","updated","deleteById","userToDelete","some","r","code","usersCount","deletedUser","delete","hasOrigin","invalidateRefreshToken","String","DELETE","emitAdminUserDeleted","deleteByIds","nbOfSuperAdminToDelete","count","deletedUsers","push","users","sanitizeUserRoles","role","pick","userId","hasSuperAdminRole","omit","getCurrentActiveUserCount"],"mappings":"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"}
1
+ {"version":3,"file":"user.js","sources":["../../../../../../ee/server/src/services/user.ts"],"sourcesContent":["import _, { castArray, toNumber } from 'lodash';\n\nimport { arrays, errors } from '@strapi/utils';\nimport { hasSuperAdminRole } from '../../../../server/src/domain/user';\nimport constants from '../../../../server/src/services/constants';\nimport {\n LEGACY_USER_EVENTS,\n emitAdminUserDeleted,\n emitAdminUserUpdateAudits,\n touchesTrackedFields,\n} from '../../../../server/src/audit-logs/admin-users';\nimport { getService } from '../utils';\n\nconst { ValidationError } = errors;\nconst { SUPER_ADMIN_CODE } = constants;\n\nconst getSessionManager = () => {\n const manager = strapi.sessionManager;\n return manager ?? null;\n};\n\n/** Checks if ee disabled users list needs to be updated\n * @param {string} id\n * @param {object} input\n */\nconst updateEEDisabledUsersList = async (id: string, input: any) => {\n const disabledUsers = await getService('seat-enforcement').getDisabledUserList();\n\n if (!disabledUsers) {\n return;\n }\n\n const user = disabledUsers.find((user: any) => user.id === Number(id));\n if (!user) {\n return;\n }\n\n if (user.isActive !== input.isActive) {\n const newDisabledUsersList = disabledUsers.filter((user: any) => user.id !== Number(id));\n await strapi.store.set({\n type: 'ee',\n key: 'disabled_users',\n value: newDisabledUsersList,\n });\n }\n};\n\nconst castNumberArray = (ids: unknown) => castArray(ids).map((id) => toNumber(id));\n\nconst removeFromEEDisabledUsersList = async (ids: unknown) => {\n let idsToCheck: any;\n if (typeof ids === 'object') {\n idsToCheck = castNumberArray(ids);\n } else {\n idsToCheck = [Number(ids)];\n }\n\n const disabledUsers = await getService('seat-enforcement').getDisabledUserList();\n\n if (!disabledUsers) {\n return;\n }\n\n const newDisabledUsersList = disabledUsers.filter((user: any) => !idsToCheck.includes(user.id));\n await strapi.store.set({\n type: 'ee',\n key: 'disabled_users',\n value: newDisabledUsersList,\n });\n};\n\n/**\n * Update a user in database\n * @param id query params to find the user to update\n * @param attributes A partial user object\n * @returns {Promise<user>}\n */\nconst updateById = async (id: any, attributes: any) => {\n // Check at least one super admin remains\n if (_.has(attributes, 'roles')) {\n const lastAdminUser = await isLastSuperAdminUser(id);\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n const willRemoveSuperAdminRole = !arrays.includesString(attributes.roles, superAdminRole.id);\n\n if (lastAdminUser && willRemoveSuperAdminRole) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n\n // cannot disable last super admin\n if (attributes.isActive === false) {\n const lastAdminUser = await isLastSuperAdminUser(id);\n if (lastAdminUser) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n\n // The audit log records what changed, so it needs the row before the write\n const previous = touchesTrackedFields(attributes)\n ? await strapi.db.query('admin::user').findOne({ where: { id }, populate: ['roles'] })\n : null;\n\n // hash password if a new one is sent\n if (_.has(attributes, 'password')) {\n const hashedPassword = await getService('auth').hashPassword(attributes.password);\n\n const updatedUser = await strapi.db.query('admin::user').update({\n where: { id },\n data: {\n ...attributes,\n password: hashedPassword,\n },\n populate: ['roles'],\n });\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.UPDATE, { user: sanitizeUser(updatedUser) });\n await emitAdminUserUpdateAudits({ strapi }, { previous, updated: updatedUser, attributes });\n\n return updatedUser;\n }\n\n const updatedUser = await strapi.db.query('admin::user').update({\n where: { id },\n data: attributes,\n populate: ['roles'],\n });\n\n await updateEEDisabledUsersList(id, attributes);\n\n if (updatedUser) {\n strapi.eventHub.emit(LEGACY_USER_EVENTS.UPDATE, { user: sanitizeUser(updatedUser) });\n await emitAdminUserUpdateAudits({ strapi }, { previous, updated: updatedUser, attributes });\n }\n\n return updatedUser;\n};\n\n/** Delete a user\n * @param id id of the user to delete\n * @returns {Promise<user>}\n */\nconst deleteById = async (id: unknown) => {\n // Check at least one super admin remains\n const userToDelete = await strapi.db.query('admin::user').findOne({\n where: { id },\n populate: ['roles'],\n });\n\n if (!userToDelete) {\n return null;\n }\n\n if (userToDelete) {\n if (userToDelete.roles.some((r: any) => r.code === SUPER_ADMIN_CODE)) {\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n if (superAdminRole.usersCount === 1) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n }\n\n const deletedUser = await strapi.db\n .query('admin::user')\n .delete({ where: { id }, populate: ['roles'] });\n\n // Invalidate all sessions for the deleted user\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('admin')) {\n await sessionManager('admin').invalidateRefreshToken(String(id));\n }\n\n await removeFromEEDisabledUsersList(id);\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.DELETE, { user: sanitizeUser(deletedUser) });\n await emitAdminUserDeleted({ strapi }, deletedUser);\n\n return deletedUser;\n};\n\n/** Delete a user\n * @param ids ids of the users to delete\n * @returns {Promise<user>}\n */\nconst deleteByIds = async (ids: any) => {\n // Check at least one super admin remains\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n const nbOfSuperAdminToDelete = await strapi.db.query('admin::user').count({\n where: {\n id: ids,\n roles: { id: superAdminRole.id },\n },\n });\n\n if (superAdminRole.usersCount === nbOfSuperAdminToDelete) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n\n const deletedUsers = [];\n for (const id of ids) {\n const deletedUser = await strapi.db.query('admin::user').delete({\n where: { id },\n populate: ['roles'],\n });\n\n // Invalidate all sessions for the deleted user\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('admin')) {\n await sessionManager('admin').invalidateRefreshToken(String(id));\n }\n\n deletedUsers.push(deletedUser);\n }\n\n await removeFromEEDisabledUsersList(ids);\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.DELETE, {\n users: deletedUsers.map((deletedUser) => sanitizeUser(deletedUser)),\n });\n\n for (const deletedUser of deletedUsers) {\n await emitAdminUserDeleted({ strapi }, deletedUser);\n }\n\n return deletedUsers;\n};\n\nconst sanitizeUserRoles = (role: unknown) => _.pick(role, ['id', 'name', 'description', 'code']);\n\n/**\n * Check if a user is the last super admin\n * @param {int|string} userId user's id to look for\n */\nconst isLastSuperAdminUser = async (userId: unknown) => {\n const user = (await findOne(userId)) as any;\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n\n return superAdminRole.usersCount === 1 && hasSuperAdminRole(user);\n};\n\n/**\n * Remove private user fields\n * @param {Object} user - user to sanitize\n */\nconst sanitizeUser = (user: any) => {\n return {\n ..._.omit(user, [\n 'password',\n 'resetPasswordToken',\n 'resetPasswordTokenExpiresAt',\n 'registrationToken',\n 'roles',\n ]),\n roles: user.roles && user.roles.map(sanitizeUserRoles),\n };\n};\n\n/**\n * Find one user\n */\nconst findOne = async (id: any, populate = ['roles']) => {\n return strapi.db.query('admin::user').findOne({ where: { id }, populate });\n};\n\nconst getCurrentActiveUserCount = async () => {\n return strapi.db.query('admin::user').count({ where: { isActive: true } });\n};\n\nexport default {\n updateEEDisabledUsersList,\n removeFromEEDisabledUsersList,\n getCurrentActiveUserCount,\n deleteByIds,\n deleteById,\n updateById,\n};\n"],"names":["ValidationError","errors","SUPER_ADMIN_CODE","constants","getSessionManager","manager","strapi","sessionManager","updateEEDisabledUsersList","id","input","disabledUsers","getService","getDisabledUserList","user","find","Number","isActive","newDisabledUsersList","filter","store","set","type","key","value","castNumberArray","ids","castArray","map","toNumber","removeFromEEDisabledUsersList","idsToCheck","includes","updateById","attributes","_","has","lastAdminUser","isLastSuperAdminUser","superAdminRole","getSuperAdminWithUsersCount","willRemoveSuperAdminRole","arrays","includesString","roles","previous","touchesTrackedFields","db","query","findOne","where","populate","hashedPassword","hashPassword","password","updatedUser","update","data","eventHub","emit","LEGACY_USER_EVENTS","UPDATE","sanitizeUser","emitAdminUserUpdateAudits","updated","deleteById","userToDelete","some","r","code","usersCount","deletedUser","delete","hasOrigin","invalidateRefreshToken","String","DELETE","emitAdminUserDeleted","deleteByIds","nbOfSuperAdminToDelete","count","deletedUsers","push","users","sanitizeUserRoles","role","pick","userId","hasSuperAdminRole","omit","getCurrentActiveUserCount"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
- import ___default from 'lodash';
2
- import { pipe, castArray, map, toNumber } from 'lodash/fp';
1
+ import ___default, { castArray, toNumber } from 'lodash';
3
2
  import { errors, arrays } from '@strapi/utils';
4
3
  import { hasSuperAdminRole } from '../../../../server/src/domain/user.mjs';
5
4
  import constants from '../../../../server/src/services/constants.mjs';
@@ -33,7 +32,7 @@ const getSessionManager = ()=>{
33
32
  });
34
33
  }
35
34
  };
36
- const castNumberArray = pipe(castArray, map(toNumber));
35
+ const castNumberArray = (ids)=>castArray(ids).map((id)=>toNumber(id));
37
36
  const removeFromEEDisabledUsersList = async (ids)=>{
38
37
  let idsToCheck;
39
38
  if (typeof ids === 'object') {
@@ -1 +1 @@
1
- {"version":3,"file":"user.mjs","sources":["../../../../../../ee/server/src/services/user.ts"],"sourcesContent":["import _ from 'lodash';\nimport { pipe, map, castArray, toNumber } from 'lodash/fp';\nimport { arrays, errors } from '@strapi/utils';\nimport { hasSuperAdminRole } from '../../../../server/src/domain/user';\nimport constants from '../../../../server/src/services/constants';\nimport {\n LEGACY_USER_EVENTS,\n emitAdminUserDeleted,\n emitAdminUserUpdateAudits,\n touchesTrackedFields,\n} from '../../../../server/src/audit-logs/admin-users';\nimport { getService } from '../utils';\n\nconst { ValidationError } = errors;\nconst { SUPER_ADMIN_CODE } = constants;\n\nconst getSessionManager = () => {\n const manager = strapi.sessionManager;\n return manager ?? null;\n};\n\n/** Checks if ee disabled users list needs to be updated\n * @param {string} id\n * @param {object} input\n */\nconst updateEEDisabledUsersList = async (id: string, input: any) => {\n const disabledUsers = await getService('seat-enforcement').getDisabledUserList();\n\n if (!disabledUsers) {\n return;\n }\n\n const user = disabledUsers.find((user: any) => user.id === Number(id));\n if (!user) {\n return;\n }\n\n if (user.isActive !== input.isActive) {\n const newDisabledUsersList = disabledUsers.filter((user: any) => user.id !== Number(id));\n await strapi.store.set({\n type: 'ee',\n key: 'disabled_users',\n value: newDisabledUsersList,\n });\n }\n};\n\nconst castNumberArray = pipe(castArray, map(toNumber));\n\nconst removeFromEEDisabledUsersList = async (ids: unknown) => {\n let idsToCheck: any;\n if (typeof ids === 'object') {\n idsToCheck = castNumberArray(ids);\n } else {\n idsToCheck = [Number(ids)];\n }\n\n const disabledUsers = await getService('seat-enforcement').getDisabledUserList();\n\n if (!disabledUsers) {\n return;\n }\n\n const newDisabledUsersList = disabledUsers.filter((user: any) => !idsToCheck.includes(user.id));\n await strapi.store.set({\n type: 'ee',\n key: 'disabled_users',\n value: newDisabledUsersList,\n });\n};\n\n/**\n * Update a user in database\n * @param id query params to find the user to update\n * @param attributes A partial user object\n * @returns {Promise<user>}\n */\nconst updateById = async (id: any, attributes: any) => {\n // Check at least one super admin remains\n if (_.has(attributes, 'roles')) {\n const lastAdminUser = await isLastSuperAdminUser(id);\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n const willRemoveSuperAdminRole = !arrays.includesString(attributes.roles, superAdminRole.id);\n\n if (lastAdminUser && willRemoveSuperAdminRole) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n\n // cannot disable last super admin\n if (attributes.isActive === false) {\n const lastAdminUser = await isLastSuperAdminUser(id);\n if (lastAdminUser) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n\n // The audit log records what changed, so it needs the row before the write\n const previous = touchesTrackedFields(attributes)\n ? await strapi.db.query('admin::user').findOne({ where: { id }, populate: ['roles'] })\n : null;\n\n // hash password if a new one is sent\n if (_.has(attributes, 'password')) {\n const hashedPassword = await getService('auth').hashPassword(attributes.password);\n\n const updatedUser = await strapi.db.query('admin::user').update({\n where: { id },\n data: {\n ...attributes,\n password: hashedPassword,\n },\n populate: ['roles'],\n });\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.UPDATE, { user: sanitizeUser(updatedUser) });\n await emitAdminUserUpdateAudits({ strapi }, { previous, updated: updatedUser, attributes });\n\n return updatedUser;\n }\n\n const updatedUser = await strapi.db.query('admin::user').update({\n where: { id },\n data: attributes,\n populate: ['roles'],\n });\n\n await updateEEDisabledUsersList(id, attributes);\n\n if (updatedUser) {\n strapi.eventHub.emit(LEGACY_USER_EVENTS.UPDATE, { user: sanitizeUser(updatedUser) });\n await emitAdminUserUpdateAudits({ strapi }, { previous, updated: updatedUser, attributes });\n }\n\n return updatedUser;\n};\n\n/** Delete a user\n * @param id id of the user to delete\n * @returns {Promise<user>}\n */\nconst deleteById = async (id: unknown) => {\n // Check at least one super admin remains\n const userToDelete = await strapi.db.query('admin::user').findOne({\n where: { id },\n populate: ['roles'],\n });\n\n if (!userToDelete) {\n return null;\n }\n\n if (userToDelete) {\n if (userToDelete.roles.some((r: any) => r.code === SUPER_ADMIN_CODE)) {\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n if (superAdminRole.usersCount === 1) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n }\n\n const deletedUser = await strapi.db\n .query('admin::user')\n .delete({ where: { id }, populate: ['roles'] });\n\n // Invalidate all sessions for the deleted user\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('admin')) {\n await sessionManager('admin').invalidateRefreshToken(String(id));\n }\n\n await removeFromEEDisabledUsersList(id);\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.DELETE, { user: sanitizeUser(deletedUser) });\n await emitAdminUserDeleted({ strapi }, deletedUser);\n\n return deletedUser;\n};\n\n/** Delete a user\n * @param ids ids of the users to delete\n * @returns {Promise<user>}\n */\nconst deleteByIds = async (ids: any) => {\n // Check at least one super admin remains\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n const nbOfSuperAdminToDelete = await strapi.db.query('admin::user').count({\n where: {\n id: ids,\n roles: { id: superAdminRole.id },\n },\n });\n\n if (superAdminRole.usersCount === nbOfSuperAdminToDelete) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n\n const deletedUsers = [];\n for (const id of ids) {\n const deletedUser = await strapi.db.query('admin::user').delete({\n where: { id },\n populate: ['roles'],\n });\n\n // Invalidate all sessions for the deleted user\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('admin')) {\n await sessionManager('admin').invalidateRefreshToken(String(id));\n }\n\n deletedUsers.push(deletedUser);\n }\n\n await removeFromEEDisabledUsersList(ids);\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.DELETE, {\n users: deletedUsers.map((deletedUser) => sanitizeUser(deletedUser)),\n });\n\n for (const deletedUser of deletedUsers) {\n await emitAdminUserDeleted({ strapi }, deletedUser);\n }\n\n return deletedUsers;\n};\n\nconst sanitizeUserRoles = (role: unknown) => _.pick(role, ['id', 'name', 'description', 'code']);\n\n/**\n * Check if a user is the last super admin\n * @param {int|string} userId user's id to look for\n */\nconst isLastSuperAdminUser = async (userId: unknown) => {\n const user = (await findOne(userId)) as any;\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n\n return superAdminRole.usersCount === 1 && hasSuperAdminRole(user);\n};\n\n/**\n * Remove private user fields\n * @param {Object} user - user to sanitize\n */\nconst sanitizeUser = (user: any) => {\n return {\n ..._.omit(user, [\n 'password',\n 'resetPasswordToken',\n 'resetPasswordTokenExpiresAt',\n 'registrationToken',\n 'roles',\n ]),\n roles: user.roles && user.roles.map(sanitizeUserRoles),\n };\n};\n\n/**\n * Find one user\n */\nconst findOne = async (id: any, populate = ['roles']) => {\n return strapi.db.query('admin::user').findOne({ where: { id }, populate });\n};\n\nconst getCurrentActiveUserCount = async () => {\n return strapi.db.query('admin::user').count({ where: { isActive: true } });\n};\n\nexport default {\n updateEEDisabledUsersList,\n removeFromEEDisabledUsersList,\n getCurrentActiveUserCount,\n deleteByIds,\n deleteById,\n updateById,\n};\n"],"names":["ValidationError","errors","SUPER_ADMIN_CODE","constants","getSessionManager","manager","strapi","sessionManager","updateEEDisabledUsersList","id","input","disabledUsers","getService","getDisabledUserList","user","find","Number","isActive","newDisabledUsersList","filter","store","set","type","key","value","castNumberArray","pipe","castArray","map","toNumber","removeFromEEDisabledUsersList","ids","idsToCheck","includes","updateById","attributes","_","has","lastAdminUser","isLastSuperAdminUser","superAdminRole","getSuperAdminWithUsersCount","willRemoveSuperAdminRole","arrays","includesString","roles","previous","touchesTrackedFields","db","query","findOne","where","populate","hashedPassword","hashPassword","password","updatedUser","update","data","eventHub","emit","LEGACY_USER_EVENTS","UPDATE","sanitizeUser","emitAdminUserUpdateAudits","updated","deleteById","userToDelete","some","r","code","usersCount","deletedUser","delete","hasOrigin","invalidateRefreshToken","String","DELETE","emitAdminUserDeleted","deleteByIds","nbOfSuperAdminToDelete","count","deletedUsers","push","users","sanitizeUserRoles","role","pick","userId","hasSuperAdminRole","omit","getCurrentActiveUserCount"],"mappings":"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"}
1
+ {"version":3,"file":"user.mjs","sources":["../../../../../../ee/server/src/services/user.ts"],"sourcesContent":["import _, { castArray, toNumber } from 'lodash';\n\nimport { arrays, errors } from '@strapi/utils';\nimport { hasSuperAdminRole } from '../../../../server/src/domain/user';\nimport constants from '../../../../server/src/services/constants';\nimport {\n LEGACY_USER_EVENTS,\n emitAdminUserDeleted,\n emitAdminUserUpdateAudits,\n touchesTrackedFields,\n} from '../../../../server/src/audit-logs/admin-users';\nimport { getService } from '../utils';\n\nconst { ValidationError } = errors;\nconst { SUPER_ADMIN_CODE } = constants;\n\nconst getSessionManager = () => {\n const manager = strapi.sessionManager;\n return manager ?? null;\n};\n\n/** Checks if ee disabled users list needs to be updated\n * @param {string} id\n * @param {object} input\n */\nconst updateEEDisabledUsersList = async (id: string, input: any) => {\n const disabledUsers = await getService('seat-enforcement').getDisabledUserList();\n\n if (!disabledUsers) {\n return;\n }\n\n const user = disabledUsers.find((user: any) => user.id === Number(id));\n if (!user) {\n return;\n }\n\n if (user.isActive !== input.isActive) {\n const newDisabledUsersList = disabledUsers.filter((user: any) => user.id !== Number(id));\n await strapi.store.set({\n type: 'ee',\n key: 'disabled_users',\n value: newDisabledUsersList,\n });\n }\n};\n\nconst castNumberArray = (ids: unknown) => castArray(ids).map((id) => toNumber(id));\n\nconst removeFromEEDisabledUsersList = async (ids: unknown) => {\n let idsToCheck: any;\n if (typeof ids === 'object') {\n idsToCheck = castNumberArray(ids);\n } else {\n idsToCheck = [Number(ids)];\n }\n\n const disabledUsers = await getService('seat-enforcement').getDisabledUserList();\n\n if (!disabledUsers) {\n return;\n }\n\n const newDisabledUsersList = disabledUsers.filter((user: any) => !idsToCheck.includes(user.id));\n await strapi.store.set({\n type: 'ee',\n key: 'disabled_users',\n value: newDisabledUsersList,\n });\n};\n\n/**\n * Update a user in database\n * @param id query params to find the user to update\n * @param attributes A partial user object\n * @returns {Promise<user>}\n */\nconst updateById = async (id: any, attributes: any) => {\n // Check at least one super admin remains\n if (_.has(attributes, 'roles')) {\n const lastAdminUser = await isLastSuperAdminUser(id);\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n const willRemoveSuperAdminRole = !arrays.includesString(attributes.roles, superAdminRole.id);\n\n if (lastAdminUser && willRemoveSuperAdminRole) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n\n // cannot disable last super admin\n if (attributes.isActive === false) {\n const lastAdminUser = await isLastSuperAdminUser(id);\n if (lastAdminUser) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n\n // The audit log records what changed, so it needs the row before the write\n const previous = touchesTrackedFields(attributes)\n ? await strapi.db.query('admin::user').findOne({ where: { id }, populate: ['roles'] })\n : null;\n\n // hash password if a new one is sent\n if (_.has(attributes, 'password')) {\n const hashedPassword = await getService('auth').hashPassword(attributes.password);\n\n const updatedUser = await strapi.db.query('admin::user').update({\n where: { id },\n data: {\n ...attributes,\n password: hashedPassword,\n },\n populate: ['roles'],\n });\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.UPDATE, { user: sanitizeUser(updatedUser) });\n await emitAdminUserUpdateAudits({ strapi }, { previous, updated: updatedUser, attributes });\n\n return updatedUser;\n }\n\n const updatedUser = await strapi.db.query('admin::user').update({\n where: { id },\n data: attributes,\n populate: ['roles'],\n });\n\n await updateEEDisabledUsersList(id, attributes);\n\n if (updatedUser) {\n strapi.eventHub.emit(LEGACY_USER_EVENTS.UPDATE, { user: sanitizeUser(updatedUser) });\n await emitAdminUserUpdateAudits({ strapi }, { previous, updated: updatedUser, attributes });\n }\n\n return updatedUser;\n};\n\n/** Delete a user\n * @param id id of the user to delete\n * @returns {Promise<user>}\n */\nconst deleteById = async (id: unknown) => {\n // Check at least one super admin remains\n const userToDelete = await strapi.db.query('admin::user').findOne({\n where: { id },\n populate: ['roles'],\n });\n\n if (!userToDelete) {\n return null;\n }\n\n if (userToDelete) {\n if (userToDelete.roles.some((r: any) => r.code === SUPER_ADMIN_CODE)) {\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n if (superAdminRole.usersCount === 1) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n }\n }\n\n const deletedUser = await strapi.db\n .query('admin::user')\n .delete({ where: { id }, populate: ['roles'] });\n\n // Invalidate all sessions for the deleted user\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('admin')) {\n await sessionManager('admin').invalidateRefreshToken(String(id));\n }\n\n await removeFromEEDisabledUsersList(id);\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.DELETE, { user: sanitizeUser(deletedUser) });\n await emitAdminUserDeleted({ strapi }, deletedUser);\n\n return deletedUser;\n};\n\n/** Delete a user\n * @param ids ids of the users to delete\n * @returns {Promise<user>}\n */\nconst deleteByIds = async (ids: any) => {\n // Check at least one super admin remains\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n const nbOfSuperAdminToDelete = await strapi.db.query('admin::user').count({\n where: {\n id: ids,\n roles: { id: superAdminRole.id },\n },\n });\n\n if (superAdminRole.usersCount === nbOfSuperAdminToDelete) {\n throw new ValidationError('You must have at least one user with super admin role.');\n }\n\n const deletedUsers = [];\n for (const id of ids) {\n const deletedUser = await strapi.db.query('admin::user').delete({\n where: { id },\n populate: ['roles'],\n });\n\n // Invalidate all sessions for the deleted user\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('admin')) {\n await sessionManager('admin').invalidateRefreshToken(String(id));\n }\n\n deletedUsers.push(deletedUser);\n }\n\n await removeFromEEDisabledUsersList(ids);\n\n strapi.eventHub.emit(LEGACY_USER_EVENTS.DELETE, {\n users: deletedUsers.map((deletedUser) => sanitizeUser(deletedUser)),\n });\n\n for (const deletedUser of deletedUsers) {\n await emitAdminUserDeleted({ strapi }, deletedUser);\n }\n\n return deletedUsers;\n};\n\nconst sanitizeUserRoles = (role: unknown) => _.pick(role, ['id', 'name', 'description', 'code']);\n\n/**\n * Check if a user is the last super admin\n * @param {int|string} userId user's id to look for\n */\nconst isLastSuperAdminUser = async (userId: unknown) => {\n const user = (await findOne(userId)) as any;\n const superAdminRole = await getService('role').getSuperAdminWithUsersCount();\n\n return superAdminRole.usersCount === 1 && hasSuperAdminRole(user);\n};\n\n/**\n * Remove private user fields\n * @param {Object} user - user to sanitize\n */\nconst sanitizeUser = (user: any) => {\n return {\n ..._.omit(user, [\n 'password',\n 'resetPasswordToken',\n 'resetPasswordTokenExpiresAt',\n 'registrationToken',\n 'roles',\n ]),\n roles: user.roles && user.roles.map(sanitizeUserRoles),\n };\n};\n\n/**\n * Find one user\n */\nconst findOne = async (id: any, populate = ['roles']) => {\n return strapi.db.query('admin::user').findOne({ where: { id }, populate });\n};\n\nconst getCurrentActiveUserCount = async () => {\n return strapi.db.query('admin::user').count({ where: { isActive: true } });\n};\n\nexport default {\n updateEEDisabledUsersList,\n removeFromEEDisabledUsersList,\n getCurrentActiveUserCount,\n deleteByIds,\n deleteById,\n updateById,\n};\n"],"names":["ValidationError","errors","SUPER_ADMIN_CODE","constants","getSessionManager","manager","strapi","sessionManager","updateEEDisabledUsersList","id","input","disabledUsers","getService","getDisabledUserList","user","find","Number","isActive","newDisabledUsersList","filter","store","set","type","key","value","castNumberArray","ids","castArray","map","toNumber","removeFromEEDisabledUsersList","idsToCheck","includes","updateById","attributes","_","has","lastAdminUser","isLastSuperAdminUser","superAdminRole","getSuperAdminWithUsersCount","willRemoveSuperAdminRole","arrays","includesString","roles","previous","touchesTrackedFields","db","query","findOne","where","populate","hashedPassword","hashPassword","password","updatedUser","update","data","eventHub","emit","LEGACY_USER_EVENTS","UPDATE","sanitizeUser","emitAdminUserUpdateAudits","updated","deleteById","userToDelete","some","r","code","usersCount","deletedUser","delete","hasOrigin","invalidateRefreshToken","String","DELETE","emitAdminUserDeleted","deleteByIds","nbOfSuperAdminToDelete","count","deletedUsers","push","users","sanitizeUserRoles","role","pick","userId","hasSuperAdminRole","omit","getCurrentActiveUserCount"],"mappings":";;;;;;;AAaA,MAAM,EAAEA,eAAe,EAAE,GAAGC,MAAAA;AAC5B,MAAM,EAAEC,gBAAgB,EAAE,GAAGC,SAAAA;AAE7B,MAAMC,iBAAAA,GAAoB,IAAA;IACxB,MAAMC,OAAAA,GAAUC,OAAOC,cAAc;AACrC,IAAA,OAAOF,OAAAA,IAAW,IAAA;AACpB,CAAA;AAEA;;;IAIA,MAAMG,yBAAAA,GAA4B,OAAOC,EAAAA,EAAYC,KAAAA,GAAAA;AACnD,IAAA,MAAMC,aAAAA,GAAgB,MAAMC,UAAAA,CAAW,kBAAA,CAAA,CAAoBC,mBAAmB,EAAA;AAE9E,IAAA,IAAI,CAACF,aAAAA,EAAe;AAClB,QAAA;AACF,IAAA;IAEA,MAAMG,IAAAA,GAAOH,cAAcI,IAAI,CAAC,CAACD,IAAAA,GAAcA,IAAAA,CAAKL,EAAE,KAAKO,MAAAA,CAAOP,EAAAA,CAAAA,CAAAA;AAClE,IAAA,IAAI,CAACK,IAAAA,EAAM;AACT,QAAA;AACF,IAAA;AAEA,IAAA,IAAIA,IAAAA,CAAKG,QAAQ,KAAKP,KAAAA,CAAMO,QAAQ,EAAE;QACpC,MAAMC,oBAAAA,GAAuBP,cAAcQ,MAAM,CAAC,CAACL,IAAAA,GAAcA,IAAAA,CAAKL,EAAE,KAAKO,MAAAA,CAAOP,EAAAA,CAAAA,CAAAA;AACpF,QAAA,MAAMH,MAAAA,CAAOc,KAAK,CAACC,GAAG,CAAC;YACrBC,IAAAA,EAAM,IAAA;YACNC,GAAAA,EAAK,gBAAA;YACLC,KAAAA,EAAON;AACT,SAAA,CAAA;AACF,IAAA;AACF,CAAA;AAEA,MAAMO,eAAAA,GAAkB,CAACC,GAAAA,GAAiBC,SAAAA,CAAUD,KAAKE,GAAG,CAAC,CAACnB,EAAAA,GAAOoB,QAAAA,CAASpB,EAAAA,CAAAA,CAAAA;AAE9E,MAAMqB,gCAAgC,OAAOJ,GAAAA,GAAAA;IAC3C,IAAIK,UAAAA;IACJ,IAAI,OAAOL,QAAQ,QAAA,EAAU;AAC3BK,QAAAA,UAAAA,GAAaN,eAAAA,CAAgBC,GAAAA,CAAAA;IAC/B,CAAA,MAAO;QACLK,UAAAA,GAAa;YAACf,MAAAA,CAAOU,GAAAA;AAAK,SAAA;AAC5B,IAAA;AAEA,IAAA,MAAMf,aAAAA,GAAgB,MAAMC,UAAAA,CAAW,kBAAA,CAAA,CAAoBC,mBAAmB,EAAA;AAE9E,IAAA,IAAI,CAACF,aAAAA,EAAe;AAClB,QAAA;AACF,IAAA;IAEA,MAAMO,oBAAAA,GAAuBP,aAAAA,CAAcQ,MAAM,CAAC,CAACL,IAAAA,GAAc,CAACiB,UAAAA,CAAWC,QAAQ,CAAClB,IAAAA,CAAKL,EAAE,CAAA,CAAA;AAC7F,IAAA,MAAMH,MAAAA,CAAOc,KAAK,CAACC,GAAG,CAAC;QACrBC,IAAAA,EAAM,IAAA;QACNC,GAAAA,EAAK,gBAAA;QACLC,KAAAA,EAAON;AACT,KAAA,CAAA;AACF,CAAA;AAEA;;;;;IAMA,MAAMe,UAAAA,GAAa,OAAOxB,EAAAA,EAASyB,UAAAA,GAAAA;;AAEjC,IAAA,IAAIC,UAAAA,CAAEC,GAAG,CAACF,UAAAA,EAAY,OAAA,CAAA,EAAU;QAC9B,MAAMG,aAAAA,GAAgB,MAAMC,oBAAAA,CAAqB7B,EAAAA,CAAAA;AACjD,QAAA,MAAM8B,cAAAA,GAAiB,MAAM3B,UAAAA,CAAW,MAAA,CAAA,CAAQ4B,2BAA2B,EAAA;QAC3E,MAAMC,wBAAAA,GAA2B,CAACC,MAAAA,CAAOC,cAAc,CAACT,UAAAA,CAAWU,KAAK,EAAEL,cAAAA,CAAe9B,EAAE,CAAA;AAE3F,QAAA,IAAI4B,iBAAiBI,wBAAAA,EAA0B;AAC7C,YAAA,MAAM,IAAIzC,eAAAA,CAAgB,wDAAA,CAAA;AAC5B,QAAA;AACF,IAAA;;IAGA,IAAIkC,UAAAA,CAAWjB,QAAQ,KAAK,KAAA,EAAO;QACjC,MAAMoB,aAAAA,GAAgB,MAAMC,oBAAAA,CAAqB7B,EAAAA,CAAAA;AACjD,QAAA,IAAI4B,aAAAA,EAAe;AACjB,YAAA,MAAM,IAAIrC,eAAAA,CAAgB,wDAAA,CAAA;AAC5B,QAAA;AACF,IAAA;;IAGA,MAAM6C,QAAAA,GAAWC,oBAAAA,CAAqBZ,UAAAA,CAAAA,GAClC,MAAM5B,MAAAA,CAAOyC,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAeC,OAAO,CAAC;QAAEC,KAAAA,EAAO;AAAEzC,YAAAA;AAAG,SAAA;QAAG0C,QAAAA,EAAU;AAAC,YAAA;AAAQ;KAAC,CAAA,GAClF,IAAA;;AAGJ,IAAA,IAAIhB,UAAAA,CAAEC,GAAG,CAACF,UAAAA,EAAY,UAAA,CAAA,EAAa;AACjC,QAAA,MAAMkB,iBAAiB,MAAMxC,UAAAA,CAAW,QAAQyC,YAAY,CAACnB,WAAWoB,QAAQ,CAAA;QAEhF,MAAMC,WAAAA,GAAc,MAAMjD,MAAAA,CAAOyC,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAeQ,MAAM,CAAC;YAC9DN,KAAAA,EAAO;AAAEzC,gBAAAA;AAAG,aAAA;YACZgD,IAAAA,EAAM;AACJ,gBAAA,GAAGvB,UAAU;gBACboB,QAAAA,EAAUF;AACZ,aAAA;YACAD,QAAAA,EAAU;AAAC,gBAAA;AAAQ;AACrB,SAAA,CAAA;AAEA7C,QAAAA,MAAAA,CAAOoD,QAAQ,CAACC,IAAI,CAACC,kBAAAA,CAAmBC,MAAM,EAAE;AAAE/C,YAAAA,IAAAA,EAAMgD,YAAAA,CAAaP,WAAAA;AAAa,SAAA,CAAA;AAClF,QAAA,MAAMQ,yBAAAA,CAA0B;AAAEzD,YAAAA;SAAO,EAAG;AAAEuC,YAAAA,QAAAA;YAAUmB,OAAAA,EAAST,WAAAA;AAAarB,YAAAA;AAAW,SAAA,CAAA;QAEzF,OAAOqB,WAAAA;AACT,IAAA;IAEA,MAAMA,WAAAA,GAAc,MAAMjD,MAAAA,CAAOyC,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAeQ,MAAM,CAAC;QAC9DN,KAAAA,EAAO;AAAEzC,YAAAA;AAAG,SAAA;QACZgD,IAAAA,EAAMvB,UAAAA;QACNiB,QAAAA,EAAU;AAAC,YAAA;AAAQ;AACrB,KAAA,CAAA;AAEA,IAAA,MAAM3C,0BAA0BC,EAAAA,EAAIyB,UAAAA,CAAAA;AAEpC,IAAA,IAAIqB,WAAAA,EAAa;AACfjD,QAAAA,MAAAA,CAAOoD,QAAQ,CAACC,IAAI,CAACC,kBAAAA,CAAmBC,MAAM,EAAE;AAAE/C,YAAAA,IAAAA,EAAMgD,YAAAA,CAAaP,WAAAA;AAAa,SAAA,CAAA;AAClF,QAAA,MAAMQ,yBAAAA,CAA0B;AAAEzD,YAAAA;SAAO,EAAG;AAAEuC,YAAAA,QAAAA;YAAUmB,OAAAA,EAAST,WAAAA;AAAarB,YAAAA;AAAW,SAAA,CAAA;AAC3F,IAAA;IAEA,OAAOqB,WAAAA;AACT,CAAA;AAEA;;;IAIA,MAAMU,aAAa,OAAOxD,EAAAA,GAAAA;;IAExB,MAAMyD,YAAAA,GAAe,MAAM5D,MAAAA,CAAOyC,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAeC,OAAO,CAAC;QAChEC,KAAAA,EAAO;AAAEzC,YAAAA;AAAG,SAAA;QACZ0C,QAAAA,EAAU;AAAC,YAAA;AAAQ;AACrB,KAAA,CAAA;AAEA,IAAA,IAAI,CAACe,YAAAA,EAAc;QACjB,OAAO,IAAA;AACT,IAAA;AAEA,IAAA,IAAIA,YAAAA,EAAc;QAChB,IAAIA,YAAAA,CAAatB,KAAK,CAACuB,IAAI,CAAC,CAACC,CAAAA,GAAWA,CAAAA,CAAEC,IAAI,KAAKnE,gBAAAA,CAAAA,EAAmB;AACpE,YAAA,MAAMqC,cAAAA,GAAiB,MAAM3B,UAAAA,CAAW,MAAA,CAAA,CAAQ4B,2BAA2B,EAAA;YAC3E,IAAID,cAAAA,CAAe+B,UAAU,KAAK,CAAA,EAAG;AACnC,gBAAA,MAAM,IAAItE,eAAAA,CAAgB,wDAAA,CAAA;AAC5B,YAAA;AACF,QAAA;AACF,IAAA;IAEA,MAAMuE,WAAAA,GAAc,MAAMjE,MAAAA,CAAOyC,EAAE,CAChCC,KAAK,CAAC,aAAA,CAAA,CACNwB,MAAM,CAAC;QAAEtB,KAAAA,EAAO;AAAEzC,YAAAA;AAAG,SAAA;QAAG0C,QAAAA,EAAU;AAAC,YAAA;AAAQ;AAAC,KAAA,CAAA;;AAG/C,IAAA,MAAM5C,cAAAA,GAAiBH,iBAAAA,EAAAA;AACvB,IAAA,IAAIG,cAAAA,IAAkBA,cAAAA,CAAekE,SAAS,CAAC,OAAA,CAAA,EAAU;AACvD,QAAA,MAAMlE,cAAAA,CAAe,OAAA,CAAA,CAASmE,sBAAsB,CAACC,MAAAA,CAAOlE,EAAAA,CAAAA,CAAAA;AAC9D,IAAA;AAEA,IAAA,MAAMqB,6BAAAA,CAA8BrB,EAAAA,CAAAA;AAEpCH,IAAAA,MAAAA,CAAOoD,QAAQ,CAACC,IAAI,CAACC,kBAAAA,CAAmBgB,MAAM,EAAE;AAAE9D,QAAAA,IAAAA,EAAMgD,YAAAA,CAAaS,WAAAA;AAAa,KAAA,CAAA;AAClF,IAAA,MAAMM,oBAAAA,CAAqB;AAAEvE,QAAAA;KAAO,EAAGiE,WAAAA,CAAAA;IAEvC,OAAOA,WAAAA;AACT,CAAA;AAEA;;;IAIA,MAAMO,cAAc,OAAOpD,GAAAA,GAAAA;;AAEzB,IAAA,MAAMa,cAAAA,GAAiB,MAAM3B,UAAAA,CAAW,MAAA,CAAA,CAAQ4B,2BAA2B,EAAA;IAC3E,MAAMuC,sBAAAA,GAAyB,MAAMzE,MAAAA,CAAOyC,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAegC,KAAK,CAAC;QACxE9B,KAAAA,EAAO;YACLzC,EAAAA,EAAIiB,GAAAA;YACJkB,KAAAA,EAAO;AAAEnC,gBAAAA,EAAAA,EAAI8B,eAAe9B;AAAG;AACjC;AACF,KAAA,CAAA;IAEA,IAAI8B,cAAAA,CAAe+B,UAAU,KAAKS,sBAAAA,EAAwB;AACxD,QAAA,MAAM,IAAI/E,eAAAA,CAAgB,wDAAA,CAAA;AAC5B,IAAA;AAEA,IAAA,MAAMiF,eAAe,EAAE;IACvB,KAAK,MAAMxE,MAAMiB,GAAAA,CAAK;QACpB,MAAM6C,WAAAA,GAAc,MAAMjE,MAAAA,CAAOyC,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAewB,MAAM,CAAC;YAC9DtB,KAAAA,EAAO;AAAEzC,gBAAAA;AAAG,aAAA;YACZ0C,QAAAA,EAAU;AAAC,gBAAA;AAAQ;AACrB,SAAA,CAAA;;AAGA,QAAA,MAAM5C,cAAAA,GAAiBH,iBAAAA,EAAAA;AACvB,QAAA,IAAIG,cAAAA,IAAkBA,cAAAA,CAAekE,SAAS,CAAC,OAAA,CAAA,EAAU;AACvD,YAAA,MAAMlE,cAAAA,CAAe,OAAA,CAAA,CAASmE,sBAAsB,CAACC,MAAAA,CAAOlE,EAAAA,CAAAA,CAAAA;AAC9D,QAAA;AAEAwE,QAAAA,YAAAA,CAAaC,IAAI,CAACX,WAAAA,CAAAA;AACpB,IAAA;AAEA,IAAA,MAAMzC,6BAAAA,CAA8BJ,GAAAA,CAAAA;AAEpCpB,IAAAA,MAAAA,CAAOoD,QAAQ,CAACC,IAAI,CAACC,kBAAAA,CAAmBgB,MAAM,EAAE;AAC9CO,QAAAA,KAAAA,EAAOF,YAAAA,CAAarD,GAAG,CAAC,CAAC2C,cAAgBT,YAAAA,CAAaS,WAAAA,CAAAA;AACxD,KAAA,CAAA;IAEA,KAAK,MAAMA,eAAeU,YAAAA,CAAc;AACtC,QAAA,MAAMJ,oBAAAA,CAAqB;AAAEvE,YAAAA;SAAO,EAAGiE,WAAAA,CAAAA;AACzC,IAAA;IAEA,OAAOU,YAAAA;AACT,CAAA;AAEA,MAAMG,oBAAoB,CAACC,IAAAA,GAAkBlD,UAAAA,CAAEmD,IAAI,CAACD,IAAAA,EAAM;AAAC,QAAA,IAAA;AAAM,QAAA,MAAA;AAAQ,QAAA,aAAA;AAAe,QAAA;AAAO,KAAA,CAAA;AAE/F;;;IAIA,MAAM/C,uBAAuB,OAAOiD,MAAAA,GAAAA;IAClC,MAAMzE,IAAAA,GAAQ,MAAMmC,OAAAA,CAAQsC,MAAAA,CAAAA;AAC5B,IAAA,MAAMhD,cAAAA,GAAiB,MAAM3B,UAAAA,CAAW,MAAA,CAAA,CAAQ4B,2BAA2B,EAAA;AAE3E,IAAA,OAAOD,cAAAA,CAAe+B,UAAU,KAAK,CAAA,IAAKkB,iBAAAA,CAAkB1E,IAAAA,CAAAA;AAC9D,CAAA;AAEA;;;IAIA,MAAMgD,eAAe,CAAChD,IAAAA,GAAAA;IACpB,OAAO;QACL,GAAGqB,UAAAA,CAAEsD,IAAI,CAAC3E,IAAAA,EAAM;AACd,YAAA,UAAA;AACA,YAAA,oBAAA;AACA,YAAA,6BAAA;AACA,YAAA,mBAAA;AACA,YAAA;SACD,CAAC;AACF8B,QAAAA,KAAAA,EAAO9B,KAAK8B,KAAK,IAAI9B,KAAK8B,KAAK,CAAChB,GAAG,CAACwD,iBAAAA;AACtC,KAAA;AACF,CAAA;AAEA;;AAEC,IACD,MAAMnC,OAAAA,GAAU,OAAOxC,EAAAA,EAAS0C,QAAAA,GAAW;AAAC,IAAA;AAAQ,CAAA,GAAA;AAClD,IAAA,OAAO7C,OAAOyC,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAeC,OAAO,CAAC;QAAEC,KAAAA,EAAO;AAAEzC,YAAAA;AAAG,SAAA;AAAG0C,QAAAA;AAAS,KAAA,CAAA;AAC1E,CAAA;AAEA,MAAMuC,yBAAAA,GAA4B,UAAA;AAChC,IAAA,OAAOpF,OAAOyC,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAegC,KAAK,CAAC;QAAE9B,KAAAA,EAAO;YAAEjC,QAAAA,EAAU;AAAK;AAAE,KAAA,CAAA;AAC1E,CAAA;AAEA,WAAe;AACbT,IAAAA,yBAAAA;AACAsB,IAAAA,6BAAAA;AACA4D,IAAAA,yBAAAA;AACAZ,IAAAA,WAAAA;AACAb,IAAAA,UAAAA;AACAhC,IAAAA;AACF,CAAA;;;;"}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var fp = require('lodash/fp');
3
+ var _ = require('lodash');
4
4
 
5
5
  const isSsoLocked = async (user)=>{
6
6
  if (!strapi.ee.features.isEnabled('sso')) {
@@ -18,7 +18,7 @@ const isSsoLocked = async (user)=>{
18
18
  key: 'auth'
19
19
  });
20
20
  const lockedRoles = providers.ssoLockedRoles ?? [];
21
- if (fp.isEmpty(lockedRoles)) {
21
+ if (_.isEmpty(lockedRoles)) {
22
22
  return false;
23
23
  }
24
24
  const roles = // If the roles are pre-loaded for the given user, then use them
@@ -1 +1 @@
1
- {"version":3,"file":"sso-lock.js","sources":["../../../../../../ee/server/src/utils/sso-lock.ts"],"sourcesContent":["import { isEmpty } from 'lodash/fp';\n\nexport const isSsoLocked = async (user: any) => {\n if (!strapi.ee.features.isEnabled('sso')) {\n return false;\n }\n\n if (!user) {\n throw new Error('Missing user object');\n }\n\n // check if any roles are locked\n const adminStore = await strapi.store({ type: 'core', name: 'admin' });\n const { providers } = (await adminStore.get({ key: 'auth' })) as any;\n const lockedRoles = providers.ssoLockedRoles ?? [];\n if (isEmpty(lockedRoles)) {\n return false;\n }\n\n const roles =\n // If the roles are pre-loaded for the given user, then use them\n user.roles ??\n // Otherwise, try to load the role based on the given user ID\n (await strapi.db.query('admin::user').load(user, 'roles', { roles: { fields: ['id'] } })) ??\n // If the query fails somehow, default to an empty array\n [];\n\n // Check if any of the user's roles are in lockedRoles\n const isLocked = lockedRoles.some((lockedId: string) =>\n // lockedRoles will be a string to avoid issues with frontend and bigints\n roles.some((role: any) => lockedId === role.id.toString())\n );\n\n return isLocked;\n};\n\nexport default {\n isSsoLocked,\n};\n"],"names":["isSsoLocked","user","strapi","ee","features","isEnabled","Error","adminStore","store","type","name","providers","get","key","lockedRoles","ssoLockedRoles","isEmpty","roles","db","query","load","fields","isLocked","some","lockedId","role","id","toString"],"mappings":";;;;AAEO,MAAMA,cAAc,OAAOC,IAAAA,GAAAA;IAChC,IAAI,CAACC,OAAOC,EAAE,CAACC,QAAQ,CAACC,SAAS,CAAC,KAAA,CAAA,EAAQ;QACxC,OAAO,KAAA;AACT,IAAA;AAEA,IAAA,IAAI,CAACJ,IAAAA,EAAM;AACT,QAAA,MAAM,IAAIK,KAAAA,CAAM,qBAAA,CAAA;AAClB,IAAA;;AAGA,IAAA,MAAMC,UAAAA,GAAa,MAAML,MAAAA,CAAOM,KAAK,CAAC;QAAEC,IAAAA,EAAM,MAAA;QAAQC,IAAAA,EAAM;AAAQ,KAAA,CAAA;AACpE,IAAA,MAAM,EAAEC,SAAS,EAAE,GAAI,MAAMJ,UAAAA,CAAWK,GAAG,CAAC;QAAEC,GAAAA,EAAK;AAAO,KAAA,CAAA;AAC1D,IAAA,MAAMC,WAAAA,GAAcH,SAAAA,CAAUI,cAAc,IAAI,EAAE;AAClD,IAAA,IAAIC,WAAQF,WAAAA,CAAAA,EAAc;QACxB,OAAO,KAAA;AACT,IAAA;AAEA,IAAA,MAAMG;IAEJhB,IAAAA,CAAKgB,KAAK;IAET,MAAMf,MAAAA,CAAOgB,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAeC,IAAI,CAACnB,IAAAA,EAAM,OAAA,EAAS;QAAEgB,KAAAA,EAAO;YAAEI,MAAAA,EAAQ;AAAC,gBAAA;AAAK;AAAC;AAAE,KAAA,CAAA;IAEtF,EAAE;;AAGJ,IAAA,MAAMC,WAAWR,WAAAA,CAAYS,IAAI,CAAC,CAACC;QAEjCP,KAAAA,CAAMM,IAAI,CAAC,CAACE,IAAAA,GAAcD,aAAaC,IAAAA,CAAKC,EAAE,CAACC,QAAQ,EAAA,CAAA,CAAA;IAGzD,OAAOL,QAAAA;AACT;;;;"}
1
+ {"version":3,"file":"sso-lock.js","sources":["../../../../../../ee/server/src/utils/sso-lock.ts"],"sourcesContent":["import { isEmpty } from 'lodash';\n\nexport const isSsoLocked = async (user: any) => {\n if (!strapi.ee.features.isEnabled('sso')) {\n return false;\n }\n\n if (!user) {\n throw new Error('Missing user object');\n }\n\n // check if any roles are locked\n const adminStore = await strapi.store({ type: 'core', name: 'admin' });\n const { providers } = (await adminStore.get({ key: 'auth' })) as any;\n const lockedRoles = providers.ssoLockedRoles ?? [];\n if (isEmpty(lockedRoles)) {\n return false;\n }\n\n const roles =\n // If the roles are pre-loaded for the given user, then use them\n user.roles ??\n // Otherwise, try to load the role based on the given user ID\n (await strapi.db.query('admin::user').load(user, 'roles', { roles: { fields: ['id'] } })) ??\n // If the query fails somehow, default to an empty array\n [];\n\n // Check if any of the user's roles are in lockedRoles\n const isLocked = lockedRoles.some((lockedId: string) =>\n // lockedRoles will be a string to avoid issues with frontend and bigints\n roles.some((role: any) => lockedId === role.id.toString())\n );\n\n return isLocked;\n};\n\nexport default {\n isSsoLocked,\n};\n"],"names":["isSsoLocked","user","strapi","ee","features","isEnabled","Error","adminStore","store","type","name","providers","get","key","lockedRoles","ssoLockedRoles","isEmpty","roles","db","query","load","fields","isLocked","some","lockedId","role","id","toString"],"mappings":";;;;AAEO,MAAMA,cAAc,OAAOC,IAAAA,GAAAA;IAChC,IAAI,CAACC,OAAOC,EAAE,CAACC,QAAQ,CAACC,SAAS,CAAC,KAAA,CAAA,EAAQ;QACxC,OAAO,KAAA;AACT,IAAA;AAEA,IAAA,IAAI,CAACJ,IAAAA,EAAM;AACT,QAAA,MAAM,IAAIK,KAAAA,CAAM,qBAAA,CAAA;AAClB,IAAA;;AAGA,IAAA,MAAMC,UAAAA,GAAa,MAAML,MAAAA,CAAOM,KAAK,CAAC;QAAEC,IAAAA,EAAM,MAAA;QAAQC,IAAAA,EAAM;AAAQ,KAAA,CAAA;AACpE,IAAA,MAAM,EAAEC,SAAS,EAAE,GAAI,MAAMJ,UAAAA,CAAWK,GAAG,CAAC;QAAEC,GAAAA,EAAK;AAAO,KAAA,CAAA;AAC1D,IAAA,MAAMC,WAAAA,GAAcH,SAAAA,CAAUI,cAAc,IAAI,EAAE;AAClD,IAAA,IAAIC,UAAQF,WAAAA,CAAAA,EAAc;QACxB,OAAO,KAAA;AACT,IAAA;AAEA,IAAA,MAAMG;IAEJhB,IAAAA,CAAKgB,KAAK;IAET,MAAMf,MAAAA,CAAOgB,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAeC,IAAI,CAACnB,IAAAA,EAAM,OAAA,EAAS;QAAEgB,KAAAA,EAAO;YAAEI,MAAAA,EAAQ;AAAC,gBAAA;AAAK;AAAC;AAAE,KAAA,CAAA;IAEtF,EAAE;;AAGJ,IAAA,MAAMC,WAAWR,WAAAA,CAAYS,IAAI,CAAC,CAACC;QAEjCP,KAAAA,CAAMM,IAAI,CAAC,CAACE,IAAAA,GAAcD,aAAaC,IAAAA,CAAKC,EAAE,CAACC,QAAQ,EAAA,CAAA,CAAA;IAGzD,OAAOL,QAAAA;AACT;;;;"}
@@ -1,4 +1,4 @@
1
- import { isEmpty } from 'lodash/fp';
1
+ import { isEmpty } from 'lodash';
2
2
 
3
3
  const isSsoLocked = async (user)=>{
4
4
  if (!strapi.ee.features.isEnabled('sso')) {
@@ -1 +1 @@
1
- {"version":3,"file":"sso-lock.mjs","sources":["../../../../../../ee/server/src/utils/sso-lock.ts"],"sourcesContent":["import { isEmpty } from 'lodash/fp';\n\nexport const isSsoLocked = async (user: any) => {\n if (!strapi.ee.features.isEnabled('sso')) {\n return false;\n }\n\n if (!user) {\n throw new Error('Missing user object');\n }\n\n // check if any roles are locked\n const adminStore = await strapi.store({ type: 'core', name: 'admin' });\n const { providers } = (await adminStore.get({ key: 'auth' })) as any;\n const lockedRoles = providers.ssoLockedRoles ?? [];\n if (isEmpty(lockedRoles)) {\n return false;\n }\n\n const roles =\n // If the roles are pre-loaded for the given user, then use them\n user.roles ??\n // Otherwise, try to load the role based on the given user ID\n (await strapi.db.query('admin::user').load(user, 'roles', { roles: { fields: ['id'] } })) ??\n // If the query fails somehow, default to an empty array\n [];\n\n // Check if any of the user's roles are in lockedRoles\n const isLocked = lockedRoles.some((lockedId: string) =>\n // lockedRoles will be a string to avoid issues with frontend and bigints\n roles.some((role: any) => lockedId === role.id.toString())\n );\n\n return isLocked;\n};\n\nexport default {\n isSsoLocked,\n};\n"],"names":["isSsoLocked","user","strapi","ee","features","isEnabled","Error","adminStore","store","type","name","providers","get","key","lockedRoles","ssoLockedRoles","isEmpty","roles","db","query","load","fields","isLocked","some","lockedId","role","id","toString"],"mappings":";;AAEO,MAAMA,cAAc,OAAOC,IAAAA,GAAAA;IAChC,IAAI,CAACC,OAAOC,EAAE,CAACC,QAAQ,CAACC,SAAS,CAAC,KAAA,CAAA,EAAQ;QACxC,OAAO,KAAA;AACT,IAAA;AAEA,IAAA,IAAI,CAACJ,IAAAA,EAAM;AACT,QAAA,MAAM,IAAIK,KAAAA,CAAM,qBAAA,CAAA;AAClB,IAAA;;AAGA,IAAA,MAAMC,UAAAA,GAAa,MAAML,MAAAA,CAAOM,KAAK,CAAC;QAAEC,IAAAA,EAAM,MAAA;QAAQC,IAAAA,EAAM;AAAQ,KAAA,CAAA;AACpE,IAAA,MAAM,EAAEC,SAAS,EAAE,GAAI,MAAMJ,UAAAA,CAAWK,GAAG,CAAC;QAAEC,GAAAA,EAAK;AAAO,KAAA,CAAA;AAC1D,IAAA,MAAMC,WAAAA,GAAcH,SAAAA,CAAUI,cAAc,IAAI,EAAE;AAClD,IAAA,IAAIC,QAAQF,WAAAA,CAAAA,EAAc;QACxB,OAAO,KAAA;AACT,IAAA;AAEA,IAAA,MAAMG;IAEJhB,IAAAA,CAAKgB,KAAK;IAET,MAAMf,MAAAA,CAAOgB,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAeC,IAAI,CAACnB,IAAAA,EAAM,OAAA,EAAS;QAAEgB,KAAAA,EAAO;YAAEI,MAAAA,EAAQ;AAAC,gBAAA;AAAK;AAAC;AAAE,KAAA,CAAA;IAEtF,EAAE;;AAGJ,IAAA,MAAMC,WAAWR,WAAAA,CAAYS,IAAI,CAAC,CAACC;QAEjCP,KAAAA,CAAMM,IAAI,CAAC,CAACE,IAAAA,GAAcD,aAAaC,IAAAA,CAAKC,EAAE,CAACC,QAAQ,EAAA,CAAA,CAAA;IAGzD,OAAOL,QAAAA;AACT;;;;"}
1
+ {"version":3,"file":"sso-lock.mjs","sources":["../../../../../../ee/server/src/utils/sso-lock.ts"],"sourcesContent":["import { isEmpty } from 'lodash';\n\nexport const isSsoLocked = async (user: any) => {\n if (!strapi.ee.features.isEnabled('sso')) {\n return false;\n }\n\n if (!user) {\n throw new Error('Missing user object');\n }\n\n // check if any roles are locked\n const adminStore = await strapi.store({ type: 'core', name: 'admin' });\n const { providers } = (await adminStore.get({ key: 'auth' })) as any;\n const lockedRoles = providers.ssoLockedRoles ?? [];\n if (isEmpty(lockedRoles)) {\n return false;\n }\n\n const roles =\n // If the roles are pre-loaded for the given user, then use them\n user.roles ??\n // Otherwise, try to load the role based on the given user ID\n (await strapi.db.query('admin::user').load(user, 'roles', { roles: { fields: ['id'] } })) ??\n // If the query fails somehow, default to an empty array\n [];\n\n // Check if any of the user's roles are in lockedRoles\n const isLocked = lockedRoles.some((lockedId: string) =>\n // lockedRoles will be a string to avoid issues with frontend and bigints\n roles.some((role: any) => lockedId === role.id.toString())\n );\n\n return isLocked;\n};\n\nexport default {\n isSsoLocked,\n};\n"],"names":["isSsoLocked","user","strapi","ee","features","isEnabled","Error","adminStore","store","type","name","providers","get","key","lockedRoles","ssoLockedRoles","isEmpty","roles","db","query","load","fields","isLocked","some","lockedId","role","id","toString"],"mappings":";;AAEO,MAAMA,cAAc,OAAOC,IAAAA,GAAAA;IAChC,IAAI,CAACC,OAAOC,EAAE,CAACC,QAAQ,CAACC,SAAS,CAAC,KAAA,CAAA,EAAQ;QACxC,OAAO,KAAA;AACT,IAAA;AAEA,IAAA,IAAI,CAACJ,IAAAA,EAAM;AACT,QAAA,MAAM,IAAIK,KAAAA,CAAM,qBAAA,CAAA;AAClB,IAAA;;AAGA,IAAA,MAAMC,UAAAA,GAAa,MAAML,MAAAA,CAAOM,KAAK,CAAC;QAAEC,IAAAA,EAAM,MAAA;QAAQC,IAAAA,EAAM;AAAQ,KAAA,CAAA;AACpE,IAAA,MAAM,EAAEC,SAAS,EAAE,GAAI,MAAMJ,UAAAA,CAAWK,GAAG,CAAC;QAAEC,GAAAA,EAAK;AAAO,KAAA,CAAA;AAC1D,IAAA,MAAMC,WAAAA,GAAcH,SAAAA,CAAUI,cAAc,IAAI,EAAE;AAClD,IAAA,IAAIC,QAAQF,WAAAA,CAAAA,EAAc;QACxB,OAAO,KAAA;AACT,IAAA;AAEA,IAAA,MAAMG;IAEJhB,IAAAA,CAAKgB,KAAK;IAET,MAAMf,MAAAA,CAAOgB,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAeC,IAAI,CAACnB,IAAAA,EAAM,OAAA,EAAS;QAAEgB,KAAAA,EAAO;YAAEI,MAAAA,EAAQ;AAAC,gBAAA;AAAK;AAAC;AAAE,KAAA,CAAA;IAEtF,EAAE;;AAGJ,IAAA,MAAMC,WAAWR,WAAAA,CAAYS,IAAI,CAAC,CAACC;QAEjCP,KAAAA,CAAMM,IAAI,CAAC,CAACE,IAAAA,GAAcD,aAAaC,IAAAA,CAAKC,EAAE,CAACC,QAAQ,EAAA,CAAA,CAAA;IAGzD,OAAOL,QAAAA;AACT;;;;"}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var fp = require('lodash/fp');
3
+ var _ = require('lodash');
4
4
  var utils = require('@strapi/utils');
5
5
 
6
6
  const AUDITED_EVENTS = {
@@ -34,7 +34,7 @@ const AUDITED_EVENTS = {
34
34
  'preferedLanguage',
35
35
  'isActive'
36
36
  ];
37
- /** Sorted, so order alone is not a change. */ const toRoleIds = (roles)=>fp.sortBy((id)=>String(id), (roles ?? []).map((role)=>typeof role === 'object' ? role.id : role));
37
+ /** Sorted, so order alone is not a change. */ const toRoleIds = (roles)=>_.sortBy((roles ?? []).map((role)=>typeof role === 'object' ? role.id : role), (id)=>String(id));
38
38
  const getAdminUserChanges = (previous, next)=>{
39
39
  const changes = {};
40
40
  for (const field of ADMIN_USER_TRACKED_FIELDS){
@@ -51,7 +51,7 @@ const getAdminUserChanges = (previous, next)=>{
51
51
  if (previous.roles != null || next.roles != null) {
52
52
  const before = toRoleIds(previous.roles);
53
53
  const after = toRoleIds(next.roles);
54
- if (!fp.isEqual(before, after)) {
54
+ if (!_.isEqual(before, after)) {
55
55
  changes.roles = {
56
56
  before,
57
57
  after
@@ -1 +1 @@
1
- {"version":3,"file":"admin-users.js","sources":["../../../../../server/src/audit-logs/admin-users.ts"],"sourcesContent":["import { isEqual, sortBy } from 'lodash/fp';\nimport type { Data, Modules } from '@strapi/types';\nimport { emitAudit } from '@strapi/utils';\n\nexport const AUDITED_EVENTS = {\n USER_CREATE: 'admin-user.create',\n USER_UPDATE: 'admin-user.update',\n USER_DELETE: 'admin-user.delete',\n PASSWORD_RESET_CREATE: 'admin-user.password-reset.create',\n PASSWORD_RESET_CONFIRM: 'admin-user.password-reset.confirm',\n PASSWORD_UPDATE: 'admin-user.password.update',\n INVITE_ACCEPT: 'admin-user.invite.accept',\n} as const;\n\n/**\n * Event hub events kept for custom listeners. The audit log no longer records them:\n * it records the AUDITED_EVENTS above, built from the row with before/after values.\n *\n * @deprecated Removed in the next major. Listen to the audit log events, or to the\n * database lifecycles, instead.\n */\nexport const LEGACY_USER_EVENTS = {\n CREATE: 'user.create',\n UPDATE: 'user.update',\n DELETE: 'user.delete',\n} as const;\n\nexport interface AdminUserResource extends Modules.AuditLogs.Resource {\n type: 'admin-user';\n id: Data.ID;\n email: string;\n}\n\n/**\n * The affected account, as read from the `admin::user` row after the write. Never the\n * row itself: it carries the password hash and the reset and registration tokens.\n */\nexport interface AdminUserEvent {\n userId: Data.ID;\n email: string;\n}\n\n/**\n * The fields an audit reader needs to identify the account and its access. Never\n * `password`, the tokens, or the timestamps: the row has its own date.\n */\nexport const ADMIN_USER_TRACKED_FIELDS = [\n 'firstname',\n 'lastname',\n 'email',\n 'username',\n 'preferedLanguage',\n 'isActive',\n] as const;\n\ntype TrackedField = (typeof ADMIN_USER_TRACKED_FIELDS)[number];\n\n/** A user row, or the attributes of an update: roles come as rows or as ids. */\nexport interface AdminUserSnapshot {\n firstname?: string | null;\n lastname?: string | null;\n email?: string | null;\n username?: string | null;\n preferedLanguage?: string | null;\n isActive?: boolean | null;\n roles?: Array<Data.ID | { id: Data.ID }> | null;\n}\n\nexport type AdminUserChanges = Partial<\n Record<TrackedField, Modules.AuditLogs.FieldChange<string | boolean | null>> & {\n roles: Modules.AuditLogs.FieldChange<Data.ID[]>;\n }\n>;\n\nexport interface CreateDetails {\n email: string;\n firstname: string | null;\n lastname: string | null;\n roles: Data.ID[];\n isActive: boolean;\n}\n\nexport type CreateEvent = AdminUserEvent & Omit<CreateDetails, 'email'>;\nexport type UpdateEvent = AdminUserEvent & { changes: AdminUserChanges };\nexport type PasswordResetCreateEvent = AdminUserEvent & { expiresAt: string | Date };\n\n/** Sorted, so order alone is not a change. */\nexport const toRoleIds = (roles: AdminUserSnapshot['roles']): Data.ID[] =>\n sortBy(\n (id: Data.ID) => String(id),\n (roles ?? []).map((role) => (typeof role === 'object' ? role.id : role))\n );\n\nexport const getAdminUserChanges = (\n previous: AdminUserSnapshot,\n next: AdminUserSnapshot\n): AdminUserChanges => {\n const changes: AdminUserChanges = {};\n\n for (const field of ADMIN_USER_TRACKED_FIELDS) {\n // isActive is a boolean column that older rows may hold as null\n const before = field === 'isActive' ? previous.isActive === true : (previous[field] ?? null);\n const after = field === 'isActive' ? next.isActive === true : (next[field] ?? null);\n\n if (before !== after) {\n changes[field] = { before, after };\n }\n }\n\n if (previous.roles != null || next.roles != null) {\n const before = toRoleIds(previous.roles);\n const after = toRoleIds(next.roles);\n\n if (!isEqual(before, after)) {\n changes.roles = { before, after };\n }\n }\n\n return changes;\n};\n\n/**\n * `email` is required by the admin::user schema; the contract type marks it optional\n * because it also describes creation payloads.\n */\nexport const toAdminUserEvent = (user: { id: Data.ID; email?: string | null }): AdminUserEvent => ({\n userId: user.id,\n email: user.email as string,\n});\n\ntype AuditStrapi = Parameters<typeof emitAudit>[0]['strapi'];\n\ninterface AdminUserRow extends AdminUserSnapshot {\n id: Data.ID;\n}\n\nexport const emitAdminUserCreated = ({ strapi }: { strapi: AuditStrapi }, user: AdminUserRow) =>\n emitAudit({ strapi }, AUDITED_EVENTS.USER_CREATE, {\n ...toAdminUserEvent(user),\n firstname: user.firstname ?? null,\n lastname: user.lastname ?? null,\n roles: toRoleIds(user.roles),\n isActive: user.isActive === true,\n } satisfies CreateEvent);\n\nexport const emitAdminUserDeleted = ({ strapi }: { strapi: AuditStrapi }, user: AdminUserRow) =>\n emitAudit({ strapi }, AUDITED_EVENTS.USER_DELETE, toAdminUserEvent(user));\n\n/** Whether an update touches a field the audit log compares, so the previous row is needed. */\nexport const touchesTrackedFields = (attributes: Record<string, unknown>) =>\n [...ADMIN_USER_TRACKED_FIELDS, 'roles'].some((field) => field in attributes);\n\n/**\n * The account events an update can produce, emitted by updateById after the write:\n * `admin-user.update` with the fields that changed, `admin-user.password.update` when a\n * password was set. Both run through the request context, so a public flow (reset,\n * invitation) with no session emits them too and the subscriber drops them.\n */\nexport const emitAdminUserUpdateAudits = async (\n { strapi }: { strapi: AuditStrapi },\n {\n previous,\n updated,\n attributes,\n }: {\n previous: AdminUserSnapshot | null | undefined;\n updated: AdminUserRow | null | undefined;\n attributes: Record<string, unknown>;\n }\n) => {\n if (!updated) {\n return;\n }\n\n if (previous) {\n const changes = getAdminUserChanges(previous, updated);\n\n if (Object.keys(changes).length > 0) {\n await emitAudit({ strapi }, AUDITED_EVENTS.USER_UPDATE, {\n ...toAdminUserEvent(updated),\n changes,\n } satisfies UpdateEvent);\n }\n }\n\n if ('password' in attributes) {\n await emitAudit({ strapi }, AUDITED_EVENTS.PASSWORD_UPDATE, toAdminUserEvent(updated));\n }\n};\n\n/**\n * The part of the audit-logs lifecycle service used here.\n * The full service type lives in the Admin EE package.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>,\n options?: { allowUnknownActor?: boolean }\n ): void;\n}\n\nexport const registerAdminUserAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n const resource = (event: AdminUserEvent): AdminUserResource => ({\n type: 'admin-user',\n id: event.userId,\n email: event.email,\n });\n\n const withoutSession = { allowUnknownActor: true };\n\n // The first super admin registers from a public form too\n auditLogsLifecycle.registerEvent<CreateDetails>(\n AUDITED_EVENTS.USER_CREATE,\n (event: CreateEvent) => ({\n resource: resource(event),\n details: {\n email: event.email,\n firstname: event.firstname,\n lastname: event.lastname,\n roles: event.roles,\n isActive: event.isActive,\n },\n }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<{ changes: AdminUserChanges }>(\n AUDITED_EVENTS.USER_UPDATE,\n (event: UpdateEvent) => ({\n resource: resource(event),\n details: { changes: event.changes },\n })\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.USER_DELETE,\n (event: AdminUserEvent) => ({ resource: resource(event) })\n );\n\n auditLogsLifecycle.registerEvent<{ expiresAt: string }>(\n AUDITED_EVENTS.PASSWORD_RESET_CREATE,\n (event: PasswordResetCreateEvent) => ({\n resource: resource(event),\n details: { expiresAt: new Date(event.expiresAt).toISOString() },\n }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.PASSWORD_RESET_CONFIRM,\n (event: AdminUserEvent) => ({ resource: resource(event) }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.INVITE_ACCEPT,\n (event: AdminUserEvent) => ({ resource: resource(event) }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.PASSWORD_UPDATE,\n (event: AdminUserEvent) => ({ resource: resource(event) })\n );\n};\n"],"names":["AUDITED_EVENTS","USER_CREATE","USER_UPDATE","USER_DELETE","PASSWORD_RESET_CREATE","PASSWORD_RESET_CONFIRM","PASSWORD_UPDATE","INVITE_ACCEPT","LEGACY_USER_EVENTS","CREATE","UPDATE","DELETE","ADMIN_USER_TRACKED_FIELDS","toRoleIds","roles","sortBy","id","String","map","role","getAdminUserChanges","previous","next","changes","field","before","isActive","after","isEqual","toAdminUserEvent","user","userId","email","emitAdminUserCreated","strapi","emitAudit","firstname","lastname","emitAdminUserDeleted","touchesTrackedFields","attributes","some","emitAdminUserUpdateAudits","updated","Object","keys","length","registerAdminUserAuditEvents","auditLogsLifecycle","resource","event","type","withoutSession","allowUnknownActor","registerEvent","details","expiresAt","Date","toISOString"],"mappings":"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"}
1
+ {"version":3,"file":"admin-users.js","sources":["../../../../../server/src/audit-logs/admin-users.ts"],"sourcesContent":["import { isEqual, sortBy } from 'lodash';\nimport type { Data, Modules } from '@strapi/types';\nimport { emitAudit } from '@strapi/utils';\n\nexport const AUDITED_EVENTS = {\n USER_CREATE: 'admin-user.create',\n USER_UPDATE: 'admin-user.update',\n USER_DELETE: 'admin-user.delete',\n PASSWORD_RESET_CREATE: 'admin-user.password-reset.create',\n PASSWORD_RESET_CONFIRM: 'admin-user.password-reset.confirm',\n PASSWORD_UPDATE: 'admin-user.password.update',\n INVITE_ACCEPT: 'admin-user.invite.accept',\n} as const;\n\n/**\n * Event hub events kept for custom listeners. The audit log no longer records them:\n * it records the AUDITED_EVENTS above, built from the row with before/after values.\n *\n * @deprecated Removed in the next major. Listen to the audit log events, or to the\n * database lifecycles, instead.\n */\nexport const LEGACY_USER_EVENTS = {\n CREATE: 'user.create',\n UPDATE: 'user.update',\n DELETE: 'user.delete',\n} as const;\n\nexport interface AdminUserResource extends Modules.AuditLogs.Resource {\n type: 'admin-user';\n id: Data.ID;\n email: string;\n}\n\n/**\n * The affected account, as read from the `admin::user` row after the write. Never the\n * row itself: it carries the password hash and the reset and registration tokens.\n */\nexport interface AdminUserEvent {\n userId: Data.ID;\n email: string;\n}\n\n/**\n * The fields an audit reader needs to identify the account and its access. Never\n * `password`, the tokens, or the timestamps: the row has its own date.\n */\nexport const ADMIN_USER_TRACKED_FIELDS = [\n 'firstname',\n 'lastname',\n 'email',\n 'username',\n 'preferedLanguage',\n 'isActive',\n] as const;\n\ntype TrackedField = (typeof ADMIN_USER_TRACKED_FIELDS)[number];\n\n/** A user row, or the attributes of an update: roles come as rows or as ids. */\nexport interface AdminUserSnapshot {\n firstname?: string | null;\n lastname?: string | null;\n email?: string | null;\n username?: string | null;\n preferedLanguage?: string | null;\n isActive?: boolean | null;\n roles?: Array<Data.ID | { id: Data.ID }> | null;\n}\n\nexport type AdminUserChanges = Partial<\n Record<TrackedField, Modules.AuditLogs.FieldChange<string | boolean | null>> & {\n roles: Modules.AuditLogs.FieldChange<Data.ID[]>;\n }\n>;\n\nexport interface CreateDetails {\n email: string;\n firstname: string | null;\n lastname: string | null;\n roles: Data.ID[];\n isActive: boolean;\n}\n\nexport type CreateEvent = AdminUserEvent & Omit<CreateDetails, 'email'>;\nexport type UpdateEvent = AdminUserEvent & { changes: AdminUserChanges };\nexport type PasswordResetCreateEvent = AdminUserEvent & { expiresAt: string | Date };\n\n/** Sorted, so order alone is not a change. */\nexport const toRoleIds = (roles: AdminUserSnapshot['roles']): Data.ID[] =>\n sortBy(\n (roles ?? []).map((role) => (typeof role === 'object' ? role.id : role)),\n (id: Data.ID) => String(id)\n );\n\nexport const getAdminUserChanges = (\n previous: AdminUserSnapshot,\n next: AdminUserSnapshot\n): AdminUserChanges => {\n const changes: AdminUserChanges = {};\n\n for (const field of ADMIN_USER_TRACKED_FIELDS) {\n // isActive is a boolean column that older rows may hold as null\n const before = field === 'isActive' ? previous.isActive === true : (previous[field] ?? null);\n const after = field === 'isActive' ? next.isActive === true : (next[field] ?? null);\n\n if (before !== after) {\n changes[field] = { before, after };\n }\n }\n\n if (previous.roles != null || next.roles != null) {\n const before = toRoleIds(previous.roles);\n const after = toRoleIds(next.roles);\n\n if (!isEqual(before, after)) {\n changes.roles = { before, after };\n }\n }\n\n return changes;\n};\n\n/**\n * `email` is required by the admin::user schema; the contract type marks it optional\n * because it also describes creation payloads.\n */\nexport const toAdminUserEvent = (user: { id: Data.ID; email?: string | null }): AdminUserEvent => ({\n userId: user.id,\n email: user.email as string,\n});\n\ntype AuditStrapi = Parameters<typeof emitAudit>[0]['strapi'];\n\ninterface AdminUserRow extends AdminUserSnapshot {\n id: Data.ID;\n}\n\nexport const emitAdminUserCreated = ({ strapi }: { strapi: AuditStrapi }, user: AdminUserRow) =>\n emitAudit({ strapi }, AUDITED_EVENTS.USER_CREATE, {\n ...toAdminUserEvent(user),\n firstname: user.firstname ?? null,\n lastname: user.lastname ?? null,\n roles: toRoleIds(user.roles),\n isActive: user.isActive === true,\n } satisfies CreateEvent);\n\nexport const emitAdminUserDeleted = ({ strapi }: { strapi: AuditStrapi }, user: AdminUserRow) =>\n emitAudit({ strapi }, AUDITED_EVENTS.USER_DELETE, toAdminUserEvent(user));\n\n/** Whether an update touches a field the audit log compares, so the previous row is needed. */\nexport const touchesTrackedFields = (attributes: Record<string, unknown>) =>\n [...ADMIN_USER_TRACKED_FIELDS, 'roles'].some((field) => field in attributes);\n\n/**\n * The account events an update can produce, emitted by updateById after the write:\n * `admin-user.update` with the fields that changed, `admin-user.password.update` when a\n * password was set. Both run through the request context, so a public flow (reset,\n * invitation) with no session emits them too and the subscriber drops them.\n */\nexport const emitAdminUserUpdateAudits = async (\n { strapi }: { strapi: AuditStrapi },\n {\n previous,\n updated,\n attributes,\n }: {\n previous: AdminUserSnapshot | null | undefined;\n updated: AdminUserRow | null | undefined;\n attributes: Record<string, unknown>;\n }\n) => {\n if (!updated) {\n return;\n }\n\n if (previous) {\n const changes = getAdminUserChanges(previous, updated);\n\n if (Object.keys(changes).length > 0) {\n await emitAudit({ strapi }, AUDITED_EVENTS.USER_UPDATE, {\n ...toAdminUserEvent(updated),\n changes,\n } satisfies UpdateEvent);\n }\n }\n\n if ('password' in attributes) {\n await emitAudit({ strapi }, AUDITED_EVENTS.PASSWORD_UPDATE, toAdminUserEvent(updated));\n }\n};\n\n/**\n * The part of the audit-logs lifecycle service used here.\n * The full service type lives in the Admin EE package.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>,\n options?: { allowUnknownActor?: boolean }\n ): void;\n}\n\nexport const registerAdminUserAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n const resource = (event: AdminUserEvent): AdminUserResource => ({\n type: 'admin-user',\n id: event.userId,\n email: event.email,\n });\n\n const withoutSession = { allowUnknownActor: true };\n\n // The first super admin registers from a public form too\n auditLogsLifecycle.registerEvent<CreateDetails>(\n AUDITED_EVENTS.USER_CREATE,\n (event: CreateEvent) => ({\n resource: resource(event),\n details: {\n email: event.email,\n firstname: event.firstname,\n lastname: event.lastname,\n roles: event.roles,\n isActive: event.isActive,\n },\n }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<{ changes: AdminUserChanges }>(\n AUDITED_EVENTS.USER_UPDATE,\n (event: UpdateEvent) => ({\n resource: resource(event),\n details: { changes: event.changes },\n })\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.USER_DELETE,\n (event: AdminUserEvent) => ({ resource: resource(event) })\n );\n\n auditLogsLifecycle.registerEvent<{ expiresAt: string }>(\n AUDITED_EVENTS.PASSWORD_RESET_CREATE,\n (event: PasswordResetCreateEvent) => ({\n resource: resource(event),\n details: { expiresAt: new Date(event.expiresAt).toISOString() },\n }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.PASSWORD_RESET_CONFIRM,\n (event: AdminUserEvent) => ({ resource: resource(event) }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.INVITE_ACCEPT,\n (event: AdminUserEvent) => ({ resource: resource(event) }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.PASSWORD_UPDATE,\n (event: AdminUserEvent) => ({ resource: resource(event) })\n );\n};\n"],"names":["AUDITED_EVENTS","USER_CREATE","USER_UPDATE","USER_DELETE","PASSWORD_RESET_CREATE","PASSWORD_RESET_CONFIRM","PASSWORD_UPDATE","INVITE_ACCEPT","LEGACY_USER_EVENTS","CREATE","UPDATE","DELETE","ADMIN_USER_TRACKED_FIELDS","toRoleIds","roles","sortBy","map","role","id","String","getAdminUserChanges","previous","next","changes","field","before","isActive","after","isEqual","toAdminUserEvent","user","userId","email","emitAdminUserCreated","strapi","emitAudit","firstname","lastname","emitAdminUserDeleted","touchesTrackedFields","attributes","some","emitAdminUserUpdateAudits","updated","Object","keys","length","registerAdminUserAuditEvents","auditLogsLifecycle","resource","event","type","withoutSession","allowUnknownActor","registerEvent","details","expiresAt","Date","toISOString"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { isEqual, sortBy } from 'lodash/fp';
1
+ import { isEqual, sortBy } from 'lodash';
2
2
  import { emitAudit } from '@strapi/utils';
3
3
 
4
4
  const AUDITED_EVENTS = {
@@ -32,7 +32,7 @@ const AUDITED_EVENTS = {
32
32
  'preferedLanguage',
33
33
  'isActive'
34
34
  ];
35
- /** Sorted, so order alone is not a change. */ const toRoleIds = (roles)=>sortBy((id)=>String(id), (roles ?? []).map((role)=>typeof role === 'object' ? role.id : role));
35
+ /** Sorted, so order alone is not a change. */ const toRoleIds = (roles)=>sortBy((roles ?? []).map((role)=>typeof role === 'object' ? role.id : role), (id)=>String(id));
36
36
  const getAdminUserChanges = (previous, next)=>{
37
37
  const changes = {};
38
38
  for (const field of ADMIN_USER_TRACKED_FIELDS){
@@ -1 +1 @@
1
- {"version":3,"file":"admin-users.mjs","sources":["../../../../../server/src/audit-logs/admin-users.ts"],"sourcesContent":["import { isEqual, sortBy } from 'lodash/fp';\nimport type { Data, Modules } from '@strapi/types';\nimport { emitAudit } from '@strapi/utils';\n\nexport const AUDITED_EVENTS = {\n USER_CREATE: 'admin-user.create',\n USER_UPDATE: 'admin-user.update',\n USER_DELETE: 'admin-user.delete',\n PASSWORD_RESET_CREATE: 'admin-user.password-reset.create',\n PASSWORD_RESET_CONFIRM: 'admin-user.password-reset.confirm',\n PASSWORD_UPDATE: 'admin-user.password.update',\n INVITE_ACCEPT: 'admin-user.invite.accept',\n} as const;\n\n/**\n * Event hub events kept for custom listeners. The audit log no longer records them:\n * it records the AUDITED_EVENTS above, built from the row with before/after values.\n *\n * @deprecated Removed in the next major. Listen to the audit log events, or to the\n * database lifecycles, instead.\n */\nexport const LEGACY_USER_EVENTS = {\n CREATE: 'user.create',\n UPDATE: 'user.update',\n DELETE: 'user.delete',\n} as const;\n\nexport interface AdminUserResource extends Modules.AuditLogs.Resource {\n type: 'admin-user';\n id: Data.ID;\n email: string;\n}\n\n/**\n * The affected account, as read from the `admin::user` row after the write. Never the\n * row itself: it carries the password hash and the reset and registration tokens.\n */\nexport interface AdminUserEvent {\n userId: Data.ID;\n email: string;\n}\n\n/**\n * The fields an audit reader needs to identify the account and its access. Never\n * `password`, the tokens, or the timestamps: the row has its own date.\n */\nexport const ADMIN_USER_TRACKED_FIELDS = [\n 'firstname',\n 'lastname',\n 'email',\n 'username',\n 'preferedLanguage',\n 'isActive',\n] as const;\n\ntype TrackedField = (typeof ADMIN_USER_TRACKED_FIELDS)[number];\n\n/** A user row, or the attributes of an update: roles come as rows or as ids. */\nexport interface AdminUserSnapshot {\n firstname?: string | null;\n lastname?: string | null;\n email?: string | null;\n username?: string | null;\n preferedLanguage?: string | null;\n isActive?: boolean | null;\n roles?: Array<Data.ID | { id: Data.ID }> | null;\n}\n\nexport type AdminUserChanges = Partial<\n Record<TrackedField, Modules.AuditLogs.FieldChange<string | boolean | null>> & {\n roles: Modules.AuditLogs.FieldChange<Data.ID[]>;\n }\n>;\n\nexport interface CreateDetails {\n email: string;\n firstname: string | null;\n lastname: string | null;\n roles: Data.ID[];\n isActive: boolean;\n}\n\nexport type CreateEvent = AdminUserEvent & Omit<CreateDetails, 'email'>;\nexport type UpdateEvent = AdminUserEvent & { changes: AdminUserChanges };\nexport type PasswordResetCreateEvent = AdminUserEvent & { expiresAt: string | Date };\n\n/** Sorted, so order alone is not a change. */\nexport const toRoleIds = (roles: AdminUserSnapshot['roles']): Data.ID[] =>\n sortBy(\n (id: Data.ID) => String(id),\n (roles ?? []).map((role) => (typeof role === 'object' ? role.id : role))\n );\n\nexport const getAdminUserChanges = (\n previous: AdminUserSnapshot,\n next: AdminUserSnapshot\n): AdminUserChanges => {\n const changes: AdminUserChanges = {};\n\n for (const field of ADMIN_USER_TRACKED_FIELDS) {\n // isActive is a boolean column that older rows may hold as null\n const before = field === 'isActive' ? previous.isActive === true : (previous[field] ?? null);\n const after = field === 'isActive' ? next.isActive === true : (next[field] ?? null);\n\n if (before !== after) {\n changes[field] = { before, after };\n }\n }\n\n if (previous.roles != null || next.roles != null) {\n const before = toRoleIds(previous.roles);\n const after = toRoleIds(next.roles);\n\n if (!isEqual(before, after)) {\n changes.roles = { before, after };\n }\n }\n\n return changes;\n};\n\n/**\n * `email` is required by the admin::user schema; the contract type marks it optional\n * because it also describes creation payloads.\n */\nexport const toAdminUserEvent = (user: { id: Data.ID; email?: string | null }): AdminUserEvent => ({\n userId: user.id,\n email: user.email as string,\n});\n\ntype AuditStrapi = Parameters<typeof emitAudit>[0]['strapi'];\n\ninterface AdminUserRow extends AdminUserSnapshot {\n id: Data.ID;\n}\n\nexport const emitAdminUserCreated = ({ strapi }: { strapi: AuditStrapi }, user: AdminUserRow) =>\n emitAudit({ strapi }, AUDITED_EVENTS.USER_CREATE, {\n ...toAdminUserEvent(user),\n firstname: user.firstname ?? null,\n lastname: user.lastname ?? null,\n roles: toRoleIds(user.roles),\n isActive: user.isActive === true,\n } satisfies CreateEvent);\n\nexport const emitAdminUserDeleted = ({ strapi }: { strapi: AuditStrapi }, user: AdminUserRow) =>\n emitAudit({ strapi }, AUDITED_EVENTS.USER_DELETE, toAdminUserEvent(user));\n\n/** Whether an update touches a field the audit log compares, so the previous row is needed. */\nexport const touchesTrackedFields = (attributes: Record<string, unknown>) =>\n [...ADMIN_USER_TRACKED_FIELDS, 'roles'].some((field) => field in attributes);\n\n/**\n * The account events an update can produce, emitted by updateById after the write:\n * `admin-user.update` with the fields that changed, `admin-user.password.update` when a\n * password was set. Both run through the request context, so a public flow (reset,\n * invitation) with no session emits them too and the subscriber drops them.\n */\nexport const emitAdminUserUpdateAudits = async (\n { strapi }: { strapi: AuditStrapi },\n {\n previous,\n updated,\n attributes,\n }: {\n previous: AdminUserSnapshot | null | undefined;\n updated: AdminUserRow | null | undefined;\n attributes: Record<string, unknown>;\n }\n) => {\n if (!updated) {\n return;\n }\n\n if (previous) {\n const changes = getAdminUserChanges(previous, updated);\n\n if (Object.keys(changes).length > 0) {\n await emitAudit({ strapi }, AUDITED_EVENTS.USER_UPDATE, {\n ...toAdminUserEvent(updated),\n changes,\n } satisfies UpdateEvent);\n }\n }\n\n if ('password' in attributes) {\n await emitAudit({ strapi }, AUDITED_EVENTS.PASSWORD_UPDATE, toAdminUserEvent(updated));\n }\n};\n\n/**\n * The part of the audit-logs lifecycle service used here.\n * The full service type lives in the Admin EE package.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>,\n options?: { allowUnknownActor?: boolean }\n ): void;\n}\n\nexport const registerAdminUserAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n const resource = (event: AdminUserEvent): AdminUserResource => ({\n type: 'admin-user',\n id: event.userId,\n email: event.email,\n });\n\n const withoutSession = { allowUnknownActor: true };\n\n // The first super admin registers from a public form too\n auditLogsLifecycle.registerEvent<CreateDetails>(\n AUDITED_EVENTS.USER_CREATE,\n (event: CreateEvent) => ({\n resource: resource(event),\n details: {\n email: event.email,\n firstname: event.firstname,\n lastname: event.lastname,\n roles: event.roles,\n isActive: event.isActive,\n },\n }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<{ changes: AdminUserChanges }>(\n AUDITED_EVENTS.USER_UPDATE,\n (event: UpdateEvent) => ({\n resource: resource(event),\n details: { changes: event.changes },\n })\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.USER_DELETE,\n (event: AdminUserEvent) => ({ resource: resource(event) })\n );\n\n auditLogsLifecycle.registerEvent<{ expiresAt: string }>(\n AUDITED_EVENTS.PASSWORD_RESET_CREATE,\n (event: PasswordResetCreateEvent) => ({\n resource: resource(event),\n details: { expiresAt: new Date(event.expiresAt).toISOString() },\n }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.PASSWORD_RESET_CONFIRM,\n (event: AdminUserEvent) => ({ resource: resource(event) }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.INVITE_ACCEPT,\n (event: AdminUserEvent) => ({ resource: resource(event) }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.PASSWORD_UPDATE,\n (event: AdminUserEvent) => ({ resource: resource(event) })\n );\n};\n"],"names":["AUDITED_EVENTS","USER_CREATE","USER_UPDATE","USER_DELETE","PASSWORD_RESET_CREATE","PASSWORD_RESET_CONFIRM","PASSWORD_UPDATE","INVITE_ACCEPT","LEGACY_USER_EVENTS","CREATE","UPDATE","DELETE","ADMIN_USER_TRACKED_FIELDS","toRoleIds","roles","sortBy","id","String","map","role","getAdminUserChanges","previous","next","changes","field","before","isActive","after","isEqual","toAdminUserEvent","user","userId","email","emitAdminUserCreated","strapi","emitAudit","firstname","lastname","emitAdminUserDeleted","touchesTrackedFields","attributes","some","emitAdminUserUpdateAudits","updated","Object","keys","length","registerAdminUserAuditEvents","auditLogsLifecycle","resource","event","type","withoutSession","allowUnknownActor","registerEvent","details","expiresAt","Date","toISOString"],"mappings":"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"}
1
+ {"version":3,"file":"admin-users.mjs","sources":["../../../../../server/src/audit-logs/admin-users.ts"],"sourcesContent":["import { isEqual, sortBy } from 'lodash';\nimport type { Data, Modules } from '@strapi/types';\nimport { emitAudit } from '@strapi/utils';\n\nexport const AUDITED_EVENTS = {\n USER_CREATE: 'admin-user.create',\n USER_UPDATE: 'admin-user.update',\n USER_DELETE: 'admin-user.delete',\n PASSWORD_RESET_CREATE: 'admin-user.password-reset.create',\n PASSWORD_RESET_CONFIRM: 'admin-user.password-reset.confirm',\n PASSWORD_UPDATE: 'admin-user.password.update',\n INVITE_ACCEPT: 'admin-user.invite.accept',\n} as const;\n\n/**\n * Event hub events kept for custom listeners. The audit log no longer records them:\n * it records the AUDITED_EVENTS above, built from the row with before/after values.\n *\n * @deprecated Removed in the next major. Listen to the audit log events, or to the\n * database lifecycles, instead.\n */\nexport const LEGACY_USER_EVENTS = {\n CREATE: 'user.create',\n UPDATE: 'user.update',\n DELETE: 'user.delete',\n} as const;\n\nexport interface AdminUserResource extends Modules.AuditLogs.Resource {\n type: 'admin-user';\n id: Data.ID;\n email: string;\n}\n\n/**\n * The affected account, as read from the `admin::user` row after the write. Never the\n * row itself: it carries the password hash and the reset and registration tokens.\n */\nexport interface AdminUserEvent {\n userId: Data.ID;\n email: string;\n}\n\n/**\n * The fields an audit reader needs to identify the account and its access. Never\n * `password`, the tokens, or the timestamps: the row has its own date.\n */\nexport const ADMIN_USER_TRACKED_FIELDS = [\n 'firstname',\n 'lastname',\n 'email',\n 'username',\n 'preferedLanguage',\n 'isActive',\n] as const;\n\ntype TrackedField = (typeof ADMIN_USER_TRACKED_FIELDS)[number];\n\n/** A user row, or the attributes of an update: roles come as rows or as ids. */\nexport interface AdminUserSnapshot {\n firstname?: string | null;\n lastname?: string | null;\n email?: string | null;\n username?: string | null;\n preferedLanguage?: string | null;\n isActive?: boolean | null;\n roles?: Array<Data.ID | { id: Data.ID }> | null;\n}\n\nexport type AdminUserChanges = Partial<\n Record<TrackedField, Modules.AuditLogs.FieldChange<string | boolean | null>> & {\n roles: Modules.AuditLogs.FieldChange<Data.ID[]>;\n }\n>;\n\nexport interface CreateDetails {\n email: string;\n firstname: string | null;\n lastname: string | null;\n roles: Data.ID[];\n isActive: boolean;\n}\n\nexport type CreateEvent = AdminUserEvent & Omit<CreateDetails, 'email'>;\nexport type UpdateEvent = AdminUserEvent & { changes: AdminUserChanges };\nexport type PasswordResetCreateEvent = AdminUserEvent & { expiresAt: string | Date };\n\n/** Sorted, so order alone is not a change. */\nexport const toRoleIds = (roles: AdminUserSnapshot['roles']): Data.ID[] =>\n sortBy(\n (roles ?? []).map((role) => (typeof role === 'object' ? role.id : role)),\n (id: Data.ID) => String(id)\n );\n\nexport const getAdminUserChanges = (\n previous: AdminUserSnapshot,\n next: AdminUserSnapshot\n): AdminUserChanges => {\n const changes: AdminUserChanges = {};\n\n for (const field of ADMIN_USER_TRACKED_FIELDS) {\n // isActive is a boolean column that older rows may hold as null\n const before = field === 'isActive' ? previous.isActive === true : (previous[field] ?? null);\n const after = field === 'isActive' ? next.isActive === true : (next[field] ?? null);\n\n if (before !== after) {\n changes[field] = { before, after };\n }\n }\n\n if (previous.roles != null || next.roles != null) {\n const before = toRoleIds(previous.roles);\n const after = toRoleIds(next.roles);\n\n if (!isEqual(before, after)) {\n changes.roles = { before, after };\n }\n }\n\n return changes;\n};\n\n/**\n * `email` is required by the admin::user schema; the contract type marks it optional\n * because it also describes creation payloads.\n */\nexport const toAdminUserEvent = (user: { id: Data.ID; email?: string | null }): AdminUserEvent => ({\n userId: user.id,\n email: user.email as string,\n});\n\ntype AuditStrapi = Parameters<typeof emitAudit>[0]['strapi'];\n\ninterface AdminUserRow extends AdminUserSnapshot {\n id: Data.ID;\n}\n\nexport const emitAdminUserCreated = ({ strapi }: { strapi: AuditStrapi }, user: AdminUserRow) =>\n emitAudit({ strapi }, AUDITED_EVENTS.USER_CREATE, {\n ...toAdminUserEvent(user),\n firstname: user.firstname ?? null,\n lastname: user.lastname ?? null,\n roles: toRoleIds(user.roles),\n isActive: user.isActive === true,\n } satisfies CreateEvent);\n\nexport const emitAdminUserDeleted = ({ strapi }: { strapi: AuditStrapi }, user: AdminUserRow) =>\n emitAudit({ strapi }, AUDITED_EVENTS.USER_DELETE, toAdminUserEvent(user));\n\n/** Whether an update touches a field the audit log compares, so the previous row is needed. */\nexport const touchesTrackedFields = (attributes: Record<string, unknown>) =>\n [...ADMIN_USER_TRACKED_FIELDS, 'roles'].some((field) => field in attributes);\n\n/**\n * The account events an update can produce, emitted by updateById after the write:\n * `admin-user.update` with the fields that changed, `admin-user.password.update` when a\n * password was set. Both run through the request context, so a public flow (reset,\n * invitation) with no session emits them too and the subscriber drops them.\n */\nexport const emitAdminUserUpdateAudits = async (\n { strapi }: { strapi: AuditStrapi },\n {\n previous,\n updated,\n attributes,\n }: {\n previous: AdminUserSnapshot | null | undefined;\n updated: AdminUserRow | null | undefined;\n attributes: Record<string, unknown>;\n }\n) => {\n if (!updated) {\n return;\n }\n\n if (previous) {\n const changes = getAdminUserChanges(previous, updated);\n\n if (Object.keys(changes).length > 0) {\n await emitAudit({ strapi }, AUDITED_EVENTS.USER_UPDATE, {\n ...toAdminUserEvent(updated),\n changes,\n } satisfies UpdateEvent);\n }\n }\n\n if ('password' in attributes) {\n await emitAudit({ strapi }, AUDITED_EVENTS.PASSWORD_UPDATE, toAdminUserEvent(updated));\n }\n};\n\n/**\n * The part of the audit-logs lifecycle service used here.\n * The full service type lives in the Admin EE package.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>,\n options?: { allowUnknownActor?: boolean }\n ): void;\n}\n\nexport const registerAdminUserAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n const resource = (event: AdminUserEvent): AdminUserResource => ({\n type: 'admin-user',\n id: event.userId,\n email: event.email,\n });\n\n const withoutSession = { allowUnknownActor: true };\n\n // The first super admin registers from a public form too\n auditLogsLifecycle.registerEvent<CreateDetails>(\n AUDITED_EVENTS.USER_CREATE,\n (event: CreateEvent) => ({\n resource: resource(event),\n details: {\n email: event.email,\n firstname: event.firstname,\n lastname: event.lastname,\n roles: event.roles,\n isActive: event.isActive,\n },\n }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<{ changes: AdminUserChanges }>(\n AUDITED_EVENTS.USER_UPDATE,\n (event: UpdateEvent) => ({\n resource: resource(event),\n details: { changes: event.changes },\n })\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.USER_DELETE,\n (event: AdminUserEvent) => ({ resource: resource(event) })\n );\n\n auditLogsLifecycle.registerEvent<{ expiresAt: string }>(\n AUDITED_EVENTS.PASSWORD_RESET_CREATE,\n (event: PasswordResetCreateEvent) => ({\n resource: resource(event),\n details: { expiresAt: new Date(event.expiresAt).toISOString() },\n }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.PASSWORD_RESET_CONFIRM,\n (event: AdminUserEvent) => ({ resource: resource(event) }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.INVITE_ACCEPT,\n (event: AdminUserEvent) => ({ resource: resource(event) }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.PASSWORD_UPDATE,\n (event: AdminUserEvent) => ({ resource: resource(event) })\n );\n};\n"],"names":["AUDITED_EVENTS","USER_CREATE","USER_UPDATE","USER_DELETE","PASSWORD_RESET_CREATE","PASSWORD_RESET_CONFIRM","PASSWORD_UPDATE","INVITE_ACCEPT","LEGACY_USER_EVENTS","CREATE","UPDATE","DELETE","ADMIN_USER_TRACKED_FIELDS","toRoleIds","roles","sortBy","map","role","id","String","getAdminUserChanges","previous","next","changes","field","before","isActive","after","isEqual","toAdminUserEvent","user","userId","email","emitAdminUserCreated","strapi","emitAudit","firstname","lastname","emitAdminUserDeleted","touchesTrackedFields","attributes","some","emitAdminUserUpdateAudits","updated","Object","keys","length","registerAdminUserAuditEvents","auditLogsLifecycle","resource","event","type","withoutSession","allowUnknownActor","registerEvent","details","expiresAt","Date","toISOString"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var fp = require('lodash/fp');
3
+ var _ = require('lodash');
4
4
 
5
5
  const AUDITED_EVENTS = {
6
6
  TOKEN_CREATE: 'token.create',
@@ -22,7 +22,7 @@ const TOKEN_EDITABLE_FIELDS = [
22
22
  /**
23
23
  * Sorted, and passed through JSON so undefined fields drop: neither order nor an absent
24
24
  * field counts as a change.
25
- */ const sortRefs = (refs)=>fp.sortBy((ref)=>JSON.stringify(ref), JSON.parse(JSON.stringify(refs)));
25
+ */ const sortRefs = (refs)=>_.sortBy(JSON.parse(JSON.stringify(refs)), (ref)=>JSON.stringify(ref));
26
26
  const getTokenChanges = (previous, next)=>{
27
27
  const changes = {};
28
28
  for (const field of TOKEN_EDITABLE_FIELDS){
@@ -38,7 +38,7 @@ const getTokenChanges = (previous, next)=>{
38
38
  if (previous.permissions !== undefined || next.permissions !== undefined) {
39
39
  const before = sortRefs(previous.permissions ?? []);
40
40
  const after = sortRefs(next.permissions ?? []);
41
- if (!fp.isEqual(before, after)) {
41
+ if (!_.isEqual(before, after)) {
42
42
  changes.permissions = {
43
43
  before,
44
44
  after
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","sources":["../../../../../server/src/audit-logs/tokens.ts"],"sourcesContent":["import { isEqual, sortBy } from 'lodash/fp';\nimport type { Data, Modules } from '@strapi/types';\n\nimport type { Permission } from '../../../shared/contracts/shared';\n\nexport const AUDITED_EVENTS = {\n TOKEN_CREATE: 'token.create',\n TOKEN_UPDATE: 'token.update',\n TOKEN_DELETE: 'token.delete',\n TOKEN_REGENERATE: 'token.regenerate',\n} as const;\n\nexport type TokenKind = 'content-api' | 'admin' | 'transfer';\n\n/**\n * A token permission as recorded in the audit log: action, subject and properties.\n * The row id says nothing to an auditor, and conditions are not part of the token:\n * they are copied from the owner's role and cannot be set per token.\n */\nexport interface AdminPermissionRef {\n action: string;\n subject: string | null;\n properties: Permission['properties'];\n}\n\nexport type PermissionRef = string | AdminPermissionRef;\n\nexport const toAdminPermissionRefs = (\n permissions: Array<Pick<Permission, 'action' | 'subject' | 'properties'>> | null | undefined\n): AdminPermissionRef[] =>\n (permissions ?? []).map((permission) => ({\n action: permission.action,\n subject: permission.subject ?? null,\n properties: permission.properties ?? {},\n }));\n\nexport const toActionRefs = (\n permissions: Array<string | { action: string }> | null | undefined\n): string[] =>\n (permissions ?? []).map((permission) =>\n typeof permission === 'string' ? permission : permission.action\n );\n\n/**\n * The owner is recorded as an id: the user object carries the email, which has no place\n * in the log.\n */\nexport interface TokenEvent {\n tokenId: Data.ID;\n name: string;\n kind: TokenKind;\n adminUserOwner?: Data.ID;\n}\n\nexport interface TokenResource extends Modules.AuditLogs.Resource {\n type: TokenKind;\n}\n\nexport interface CreateDetails {\n description: string | null;\n /** Milliseconds. The column is a biginteger and comes back as a string. */\n lifespan: number | null;\n expiresAt: string | null;\n /** content-api only: read-only | full-access | custom */\n type?: string;\n /** content-api (custom), transfer and admin tokens */\n permissions?: PermissionRef[];\n adminUserOwner?: Data.ID;\n}\n\nexport type CreateEvent = TokenEvent & {\n description?: string | null;\n lifespan?: string | number | null;\n expiresAt?: string | number | Date | null;\n type?: string;\n permissions?: PermissionRef[];\n};\n\nexport const TOKEN_EDITABLE_FIELDS = ['name', 'description', 'type'] as const;\n\nexport type TokenChanges = Partial<{\n name: Modules.AuditLogs.FieldChange<string | null>;\n description: Modules.AuditLogs.FieldChange<string | null>;\n type: Modules.AuditLogs.FieldChange<string | null>;\n permissions: Modules.AuditLogs.FieldChange<PermissionRef[]>;\n}>;\n\nexport interface UpdateDetails {\n changes: TokenChanges;\n adminUserOwner?: Data.ID;\n}\n\nexport type UpdateEvent = TokenEvent & { changes: TokenChanges };\n\nexport interface TokenSnapshot {\n name?: string | null;\n description?: string | null;\n type?: string | null;\n permissions?: PermissionRef[];\n}\n\n/**\n * Sorted, and passed through JSON so undefined fields drop: neither order nor an absent\n * field counts as a change.\n */\nconst sortRefs = (refs: PermissionRef[]): PermissionRef[] =>\n sortBy((ref: PermissionRef) => JSON.stringify(ref), JSON.parse(JSON.stringify(refs)));\n\nexport const getTokenChanges = (previous: TokenSnapshot, next: TokenSnapshot): TokenChanges => {\n const changes: TokenChanges = {};\n\n for (const field of TOKEN_EDITABLE_FIELDS) {\n const before = previous[field] ?? null;\n const after = next[field] ?? null;\n\n if (before !== after) {\n changes[field] = { before, after };\n }\n }\n\n if (previous.permissions !== undefined || next.permissions !== undefined) {\n const before = sortRefs(previous.permissions ?? []);\n const after = sortRefs(next.permissions ?? []);\n\n if (!isEqual(before, after)) {\n changes.permissions = { before, after };\n }\n }\n\n return changes;\n};\n\nconst toIso = (value: string | number | Date | null | undefined): string | null =>\n value == null ? null : new Date(value).toISOString();\n\n/**\n * The part of the audit-logs lifecycle service used here.\n * The full service type lives in the Admin EE package.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>\n ): void;\n}\n\nexport const registerTokenAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n const tokenResource = (event: TokenEvent): TokenResource => ({\n type: event.kind,\n id: event.tokenId,\n name: event.name,\n });\n\n const owner = (event: TokenEvent) =>\n event.adminUserOwner != null ? { adminUserOwner: event.adminUserOwner } : {};\n\n auditLogsLifecycle.registerEvent<CreateDetails>(\n AUDITED_EVENTS.TOKEN_CREATE,\n (event: CreateEvent) => ({\n resource: tokenResource(event),\n details: {\n description: event.description ?? null,\n lifespan: event.lifespan == null ? null : Number(event.lifespan),\n expiresAt: toIso(event.expiresAt),\n ...(event.type !== undefined && { type: event.type }),\n ...(event.permissions !== undefined && { permissions: sortRefs(event.permissions) }),\n ...owner(event),\n },\n })\n );\n\n auditLogsLifecycle.registerEvent<UpdateDetails>(\n AUDITED_EVENTS.TOKEN_UPDATE,\n (event: UpdateEvent) => ({\n resource: tokenResource(event),\n details: { changes: event.changes, ...owner(event) },\n })\n );\n\n auditLogsLifecycle.registerEvent<{ adminUserOwner: Data.ID } | undefined>(\n AUDITED_EVENTS.TOKEN_DELETE,\n (event: TokenEvent) => ({\n resource: tokenResource(event),\n ...(event.adminUserOwner != null && { details: { adminUserOwner: event.adminUserOwner } }),\n })\n );\n\n auditLogsLifecycle.registerEvent<{ adminUserOwner: Data.ID } | undefined>(\n AUDITED_EVENTS.TOKEN_REGENERATE,\n (event: TokenEvent) => ({\n resource: tokenResource(event),\n ...(event.adminUserOwner != null && { details: { adminUserOwner: event.adminUserOwner } }),\n })\n );\n};\n"],"names":["AUDITED_EVENTS","TOKEN_CREATE","TOKEN_UPDATE","TOKEN_DELETE","TOKEN_REGENERATE","toAdminPermissionRefs","permissions","map","permission","action","subject","properties","toActionRefs","TOKEN_EDITABLE_FIELDS","sortRefs","refs","sortBy","ref","JSON","stringify","parse","getTokenChanges","previous","next","changes","field","before","after","undefined","isEqual","toIso","value","Date","toISOString","registerTokenAuditEvents","auditLogsLifecycle","tokenResource","event","type","kind","id","tokenId","name","owner","adminUserOwner","registerEvent","resource","details","description","lifespan","Number","expiresAt"],"mappings":"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"}
1
+ {"version":3,"file":"tokens.js","sources":["../../../../../server/src/audit-logs/tokens.ts"],"sourcesContent":["import { isEqual, sortBy } from 'lodash';\n\nimport type { Data, Modules } from '@strapi/types';\n\nimport type { Permission } from '../../../shared/contracts/shared';\n\nexport const AUDITED_EVENTS = {\n TOKEN_CREATE: 'token.create',\n TOKEN_UPDATE: 'token.update',\n TOKEN_DELETE: 'token.delete',\n TOKEN_REGENERATE: 'token.regenerate',\n} as const;\n\nexport type TokenKind = 'content-api' | 'admin' | 'transfer';\n\n/**\n * A token permission as recorded in the audit log: action, subject and properties.\n * The row id says nothing to an auditor, and conditions are not part of the token:\n * they are copied from the owner's role and cannot be set per token.\n */\nexport interface AdminPermissionRef {\n action: string;\n subject: string | null;\n properties: Permission['properties'];\n}\n\nexport type PermissionRef = string | AdminPermissionRef;\n\nexport const toAdminPermissionRefs = (\n permissions: Array<Pick<Permission, 'action' | 'subject' | 'properties'>> | null | undefined\n): AdminPermissionRef[] =>\n (permissions ?? []).map((permission) => ({\n action: permission.action,\n subject: permission.subject ?? null,\n properties: permission.properties ?? {},\n }));\n\nexport const toActionRefs = (\n permissions: Array<string | { action: string }> | null | undefined\n): string[] =>\n (permissions ?? []).map((permission) =>\n typeof permission === 'string' ? permission : permission.action\n );\n\n/**\n * The owner is recorded as an id: the user object carries the email, which has no place\n * in the log.\n */\nexport interface TokenEvent {\n tokenId: Data.ID;\n name: string;\n kind: TokenKind;\n adminUserOwner?: Data.ID;\n}\n\nexport interface TokenResource extends Modules.AuditLogs.Resource {\n type: TokenKind;\n}\n\nexport interface CreateDetails {\n description: string | null;\n /** Milliseconds. The column is a biginteger and comes back as a string. */\n lifespan: number | null;\n expiresAt: string | null;\n /** content-api only: read-only | full-access | custom */\n type?: string;\n /** content-api (custom), transfer and admin tokens */\n permissions?: PermissionRef[];\n adminUserOwner?: Data.ID;\n}\n\nexport type CreateEvent = TokenEvent & {\n description?: string | null;\n lifespan?: string | number | null;\n expiresAt?: string | number | Date | null;\n type?: string;\n permissions?: PermissionRef[];\n};\n\nexport const TOKEN_EDITABLE_FIELDS = ['name', 'description', 'type'] as const;\n\nexport type TokenChanges = Partial<{\n name: Modules.AuditLogs.FieldChange<string | null>;\n description: Modules.AuditLogs.FieldChange<string | null>;\n type: Modules.AuditLogs.FieldChange<string | null>;\n permissions: Modules.AuditLogs.FieldChange<PermissionRef[]>;\n}>;\n\nexport interface UpdateDetails {\n changes: TokenChanges;\n adminUserOwner?: Data.ID;\n}\n\nexport type UpdateEvent = TokenEvent & { changes: TokenChanges };\n\nexport interface TokenSnapshot {\n name?: string | null;\n description?: string | null;\n type?: string | null;\n permissions?: PermissionRef[];\n}\n\n/**\n * Sorted, and passed through JSON so undefined fields drop: neither order nor an absent\n * field counts as a change.\n */\nconst sortRefs = (refs: PermissionRef[]): PermissionRef[] =>\n sortBy(JSON.parse(JSON.stringify(refs)), (ref: PermissionRef) => JSON.stringify(ref));\n\nexport const getTokenChanges = (previous: TokenSnapshot, next: TokenSnapshot): TokenChanges => {\n const changes: TokenChanges = {};\n\n for (const field of TOKEN_EDITABLE_FIELDS) {\n const before = previous[field] ?? null;\n const after = next[field] ?? null;\n\n if (before !== after) {\n changes[field] = { before, after };\n }\n }\n\n if (previous.permissions !== undefined || next.permissions !== undefined) {\n const before = sortRefs(previous.permissions ?? []);\n const after = sortRefs(next.permissions ?? []);\n\n if (!isEqual(before, after)) {\n changes.permissions = { before, after };\n }\n }\n\n return changes;\n};\n\nconst toIso = (value: string | number | Date | null | undefined): string | null =>\n value == null ? null : new Date(value).toISOString();\n\n/**\n * The part of the audit-logs lifecycle service used here.\n * The full service type lives in the Admin EE package.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>\n ): void;\n}\n\nexport const registerTokenAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n const tokenResource = (event: TokenEvent): TokenResource => ({\n type: event.kind,\n id: event.tokenId,\n name: event.name,\n });\n\n const owner = (event: TokenEvent) =>\n event.adminUserOwner != null ? { adminUserOwner: event.adminUserOwner } : {};\n\n auditLogsLifecycle.registerEvent<CreateDetails>(\n AUDITED_EVENTS.TOKEN_CREATE,\n (event: CreateEvent) => ({\n resource: tokenResource(event),\n details: {\n description: event.description ?? null,\n lifespan: event.lifespan == null ? null : Number(event.lifespan),\n expiresAt: toIso(event.expiresAt),\n ...(event.type !== undefined && { type: event.type }),\n ...(event.permissions !== undefined && { permissions: sortRefs(event.permissions) }),\n ...owner(event),\n },\n })\n );\n\n auditLogsLifecycle.registerEvent<UpdateDetails>(\n AUDITED_EVENTS.TOKEN_UPDATE,\n (event: UpdateEvent) => ({\n resource: tokenResource(event),\n details: { changes: event.changes, ...owner(event) },\n })\n );\n\n auditLogsLifecycle.registerEvent<{ adminUserOwner: Data.ID } | undefined>(\n AUDITED_EVENTS.TOKEN_DELETE,\n (event: TokenEvent) => ({\n resource: tokenResource(event),\n ...(event.adminUserOwner != null && { details: { adminUserOwner: event.adminUserOwner } }),\n })\n );\n\n auditLogsLifecycle.registerEvent<{ adminUserOwner: Data.ID } | undefined>(\n AUDITED_EVENTS.TOKEN_REGENERATE,\n (event: TokenEvent) => ({\n resource: tokenResource(event),\n ...(event.adminUserOwner != null && { details: { adminUserOwner: event.adminUserOwner } }),\n })\n );\n};\n"],"names":["AUDITED_EVENTS","TOKEN_CREATE","TOKEN_UPDATE","TOKEN_DELETE","TOKEN_REGENERATE","toAdminPermissionRefs","permissions","map","permission","action","subject","properties","toActionRefs","TOKEN_EDITABLE_FIELDS","sortRefs","refs","sortBy","JSON","parse","stringify","ref","getTokenChanges","previous","next","changes","field","before","after","undefined","isEqual","toIso","value","Date","toISOString","registerTokenAuditEvents","auditLogsLifecycle","tokenResource","event","type","kind","id","tokenId","name","owner","adminUserOwner","registerEvent","resource","details","description","lifespan","Number","expiresAt"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { isEqual, sortBy } from 'lodash/fp';
1
+ import { isEqual, sortBy } from 'lodash';
2
2
 
3
3
  const AUDITED_EVENTS = {
4
4
  TOKEN_CREATE: 'token.create',
@@ -20,7 +20,7 @@ const TOKEN_EDITABLE_FIELDS = [
20
20
  /**
21
21
  * Sorted, and passed through JSON so undefined fields drop: neither order nor an absent
22
22
  * field counts as a change.
23
- */ const sortRefs = (refs)=>sortBy((ref)=>JSON.stringify(ref), JSON.parse(JSON.stringify(refs)));
23
+ */ const sortRefs = (refs)=>sortBy(JSON.parse(JSON.stringify(refs)), (ref)=>JSON.stringify(ref));
24
24
  const getTokenChanges = (previous, next)=>{
25
25
  const changes = {};
26
26
  for (const field of TOKEN_EDITABLE_FIELDS){
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.mjs","sources":["../../../../../server/src/audit-logs/tokens.ts"],"sourcesContent":["import { isEqual, sortBy } from 'lodash/fp';\nimport type { Data, Modules } from '@strapi/types';\n\nimport type { Permission } from '../../../shared/contracts/shared';\n\nexport const AUDITED_EVENTS = {\n TOKEN_CREATE: 'token.create',\n TOKEN_UPDATE: 'token.update',\n TOKEN_DELETE: 'token.delete',\n TOKEN_REGENERATE: 'token.regenerate',\n} as const;\n\nexport type TokenKind = 'content-api' | 'admin' | 'transfer';\n\n/**\n * A token permission as recorded in the audit log: action, subject and properties.\n * The row id says nothing to an auditor, and conditions are not part of the token:\n * they are copied from the owner's role and cannot be set per token.\n */\nexport interface AdminPermissionRef {\n action: string;\n subject: string | null;\n properties: Permission['properties'];\n}\n\nexport type PermissionRef = string | AdminPermissionRef;\n\nexport const toAdminPermissionRefs = (\n permissions: Array<Pick<Permission, 'action' | 'subject' | 'properties'>> | null | undefined\n): AdminPermissionRef[] =>\n (permissions ?? []).map((permission) => ({\n action: permission.action,\n subject: permission.subject ?? null,\n properties: permission.properties ?? {},\n }));\n\nexport const toActionRefs = (\n permissions: Array<string | { action: string }> | null | undefined\n): string[] =>\n (permissions ?? []).map((permission) =>\n typeof permission === 'string' ? permission : permission.action\n );\n\n/**\n * The owner is recorded as an id: the user object carries the email, which has no place\n * in the log.\n */\nexport interface TokenEvent {\n tokenId: Data.ID;\n name: string;\n kind: TokenKind;\n adminUserOwner?: Data.ID;\n}\n\nexport interface TokenResource extends Modules.AuditLogs.Resource {\n type: TokenKind;\n}\n\nexport interface CreateDetails {\n description: string | null;\n /** Milliseconds. The column is a biginteger and comes back as a string. */\n lifespan: number | null;\n expiresAt: string | null;\n /** content-api only: read-only | full-access | custom */\n type?: string;\n /** content-api (custom), transfer and admin tokens */\n permissions?: PermissionRef[];\n adminUserOwner?: Data.ID;\n}\n\nexport type CreateEvent = TokenEvent & {\n description?: string | null;\n lifespan?: string | number | null;\n expiresAt?: string | number | Date | null;\n type?: string;\n permissions?: PermissionRef[];\n};\n\nexport const TOKEN_EDITABLE_FIELDS = ['name', 'description', 'type'] as const;\n\nexport type TokenChanges = Partial<{\n name: Modules.AuditLogs.FieldChange<string | null>;\n description: Modules.AuditLogs.FieldChange<string | null>;\n type: Modules.AuditLogs.FieldChange<string | null>;\n permissions: Modules.AuditLogs.FieldChange<PermissionRef[]>;\n}>;\n\nexport interface UpdateDetails {\n changes: TokenChanges;\n adminUserOwner?: Data.ID;\n}\n\nexport type UpdateEvent = TokenEvent & { changes: TokenChanges };\n\nexport interface TokenSnapshot {\n name?: string | null;\n description?: string | null;\n type?: string | null;\n permissions?: PermissionRef[];\n}\n\n/**\n * Sorted, and passed through JSON so undefined fields drop: neither order nor an absent\n * field counts as a change.\n */\nconst sortRefs = (refs: PermissionRef[]): PermissionRef[] =>\n sortBy((ref: PermissionRef) => JSON.stringify(ref), JSON.parse(JSON.stringify(refs)));\n\nexport const getTokenChanges = (previous: TokenSnapshot, next: TokenSnapshot): TokenChanges => {\n const changes: TokenChanges = {};\n\n for (const field of TOKEN_EDITABLE_FIELDS) {\n const before = previous[field] ?? null;\n const after = next[field] ?? null;\n\n if (before !== after) {\n changes[field] = { before, after };\n }\n }\n\n if (previous.permissions !== undefined || next.permissions !== undefined) {\n const before = sortRefs(previous.permissions ?? []);\n const after = sortRefs(next.permissions ?? []);\n\n if (!isEqual(before, after)) {\n changes.permissions = { before, after };\n }\n }\n\n return changes;\n};\n\nconst toIso = (value: string | number | Date | null | undefined): string | null =>\n value == null ? null : new Date(value).toISOString();\n\n/**\n * The part of the audit-logs lifecycle service used here.\n * The full service type lives in the Admin EE package.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>\n ): void;\n}\n\nexport const registerTokenAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n const tokenResource = (event: TokenEvent): TokenResource => ({\n type: event.kind,\n id: event.tokenId,\n name: event.name,\n });\n\n const owner = (event: TokenEvent) =>\n event.adminUserOwner != null ? { adminUserOwner: event.adminUserOwner } : {};\n\n auditLogsLifecycle.registerEvent<CreateDetails>(\n AUDITED_EVENTS.TOKEN_CREATE,\n (event: CreateEvent) => ({\n resource: tokenResource(event),\n details: {\n description: event.description ?? null,\n lifespan: event.lifespan == null ? null : Number(event.lifespan),\n expiresAt: toIso(event.expiresAt),\n ...(event.type !== undefined && { type: event.type }),\n ...(event.permissions !== undefined && { permissions: sortRefs(event.permissions) }),\n ...owner(event),\n },\n })\n );\n\n auditLogsLifecycle.registerEvent<UpdateDetails>(\n AUDITED_EVENTS.TOKEN_UPDATE,\n (event: UpdateEvent) => ({\n resource: tokenResource(event),\n details: { changes: event.changes, ...owner(event) },\n })\n );\n\n auditLogsLifecycle.registerEvent<{ adminUserOwner: Data.ID } | undefined>(\n AUDITED_EVENTS.TOKEN_DELETE,\n (event: TokenEvent) => ({\n resource: tokenResource(event),\n ...(event.adminUserOwner != null && { details: { adminUserOwner: event.adminUserOwner } }),\n })\n );\n\n auditLogsLifecycle.registerEvent<{ adminUserOwner: Data.ID } | undefined>(\n AUDITED_EVENTS.TOKEN_REGENERATE,\n (event: TokenEvent) => ({\n resource: tokenResource(event),\n ...(event.adminUserOwner != null && { details: { adminUserOwner: event.adminUserOwner } }),\n })\n );\n};\n"],"names":["AUDITED_EVENTS","TOKEN_CREATE","TOKEN_UPDATE","TOKEN_DELETE","TOKEN_REGENERATE","toAdminPermissionRefs","permissions","map","permission","action","subject","properties","toActionRefs","TOKEN_EDITABLE_FIELDS","sortRefs","refs","sortBy","ref","JSON","stringify","parse","getTokenChanges","previous","next","changes","field","before","after","undefined","isEqual","toIso","value","Date","toISOString","registerTokenAuditEvents","auditLogsLifecycle","tokenResource","event","type","kind","id","tokenId","name","owner","adminUserOwner","registerEvent","resource","details","description","lifespan","Number","expiresAt"],"mappings":"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"}
1
+ {"version":3,"file":"tokens.mjs","sources":["../../../../../server/src/audit-logs/tokens.ts"],"sourcesContent":["import { isEqual, sortBy } from 'lodash';\n\nimport type { Data, Modules } from '@strapi/types';\n\nimport type { Permission } from '../../../shared/contracts/shared';\n\nexport const AUDITED_EVENTS = {\n TOKEN_CREATE: 'token.create',\n TOKEN_UPDATE: 'token.update',\n TOKEN_DELETE: 'token.delete',\n TOKEN_REGENERATE: 'token.regenerate',\n} as const;\n\nexport type TokenKind = 'content-api' | 'admin' | 'transfer';\n\n/**\n * A token permission as recorded in the audit log: action, subject and properties.\n * The row id says nothing to an auditor, and conditions are not part of the token:\n * they are copied from the owner's role and cannot be set per token.\n */\nexport interface AdminPermissionRef {\n action: string;\n subject: string | null;\n properties: Permission['properties'];\n}\n\nexport type PermissionRef = string | AdminPermissionRef;\n\nexport const toAdminPermissionRefs = (\n permissions: Array<Pick<Permission, 'action' | 'subject' | 'properties'>> | null | undefined\n): AdminPermissionRef[] =>\n (permissions ?? []).map((permission) => ({\n action: permission.action,\n subject: permission.subject ?? null,\n properties: permission.properties ?? {},\n }));\n\nexport const toActionRefs = (\n permissions: Array<string | { action: string }> | null | undefined\n): string[] =>\n (permissions ?? []).map((permission) =>\n typeof permission === 'string' ? permission : permission.action\n );\n\n/**\n * The owner is recorded as an id: the user object carries the email, which has no place\n * in the log.\n */\nexport interface TokenEvent {\n tokenId: Data.ID;\n name: string;\n kind: TokenKind;\n adminUserOwner?: Data.ID;\n}\n\nexport interface TokenResource extends Modules.AuditLogs.Resource {\n type: TokenKind;\n}\n\nexport interface CreateDetails {\n description: string | null;\n /** Milliseconds. The column is a biginteger and comes back as a string. */\n lifespan: number | null;\n expiresAt: string | null;\n /** content-api only: read-only | full-access | custom */\n type?: string;\n /** content-api (custom), transfer and admin tokens */\n permissions?: PermissionRef[];\n adminUserOwner?: Data.ID;\n}\n\nexport type CreateEvent = TokenEvent & {\n description?: string | null;\n lifespan?: string | number | null;\n expiresAt?: string | number | Date | null;\n type?: string;\n permissions?: PermissionRef[];\n};\n\nexport const TOKEN_EDITABLE_FIELDS = ['name', 'description', 'type'] as const;\n\nexport type TokenChanges = Partial<{\n name: Modules.AuditLogs.FieldChange<string | null>;\n description: Modules.AuditLogs.FieldChange<string | null>;\n type: Modules.AuditLogs.FieldChange<string | null>;\n permissions: Modules.AuditLogs.FieldChange<PermissionRef[]>;\n}>;\n\nexport interface UpdateDetails {\n changes: TokenChanges;\n adminUserOwner?: Data.ID;\n}\n\nexport type UpdateEvent = TokenEvent & { changes: TokenChanges };\n\nexport interface TokenSnapshot {\n name?: string | null;\n description?: string | null;\n type?: string | null;\n permissions?: PermissionRef[];\n}\n\n/**\n * Sorted, and passed through JSON so undefined fields drop: neither order nor an absent\n * field counts as a change.\n */\nconst sortRefs = (refs: PermissionRef[]): PermissionRef[] =>\n sortBy(JSON.parse(JSON.stringify(refs)), (ref: PermissionRef) => JSON.stringify(ref));\n\nexport const getTokenChanges = (previous: TokenSnapshot, next: TokenSnapshot): TokenChanges => {\n const changes: TokenChanges = {};\n\n for (const field of TOKEN_EDITABLE_FIELDS) {\n const before = previous[field] ?? null;\n const after = next[field] ?? null;\n\n if (before !== after) {\n changes[field] = { before, after };\n }\n }\n\n if (previous.permissions !== undefined || next.permissions !== undefined) {\n const before = sortRefs(previous.permissions ?? []);\n const after = sortRefs(next.permissions ?? []);\n\n if (!isEqual(before, after)) {\n changes.permissions = { before, after };\n }\n }\n\n return changes;\n};\n\nconst toIso = (value: string | number | Date | null | undefined): string | null =>\n value == null ? null : new Date(value).toISOString();\n\n/**\n * The part of the audit-logs lifecycle service used here.\n * The full service type lives in the Admin EE package.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>\n ): void;\n}\n\nexport const registerTokenAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n const tokenResource = (event: TokenEvent): TokenResource => ({\n type: event.kind,\n id: event.tokenId,\n name: event.name,\n });\n\n const owner = (event: TokenEvent) =>\n event.adminUserOwner != null ? { adminUserOwner: event.adminUserOwner } : {};\n\n auditLogsLifecycle.registerEvent<CreateDetails>(\n AUDITED_EVENTS.TOKEN_CREATE,\n (event: CreateEvent) => ({\n resource: tokenResource(event),\n details: {\n description: event.description ?? null,\n lifespan: event.lifespan == null ? null : Number(event.lifespan),\n expiresAt: toIso(event.expiresAt),\n ...(event.type !== undefined && { type: event.type }),\n ...(event.permissions !== undefined && { permissions: sortRefs(event.permissions) }),\n ...owner(event),\n },\n })\n );\n\n auditLogsLifecycle.registerEvent<UpdateDetails>(\n AUDITED_EVENTS.TOKEN_UPDATE,\n (event: UpdateEvent) => ({\n resource: tokenResource(event),\n details: { changes: event.changes, ...owner(event) },\n })\n );\n\n auditLogsLifecycle.registerEvent<{ adminUserOwner: Data.ID } | undefined>(\n AUDITED_EVENTS.TOKEN_DELETE,\n (event: TokenEvent) => ({\n resource: tokenResource(event),\n ...(event.adminUserOwner != null && { details: { adminUserOwner: event.adminUserOwner } }),\n })\n );\n\n auditLogsLifecycle.registerEvent<{ adminUserOwner: Data.ID } | undefined>(\n AUDITED_EVENTS.TOKEN_REGENERATE,\n (event: TokenEvent) => ({\n resource: tokenResource(event),\n ...(event.adminUserOwner != null && { details: { adminUserOwner: event.adminUserOwner } }),\n })\n );\n};\n"],"names":["AUDITED_EVENTS","TOKEN_CREATE","TOKEN_UPDATE","TOKEN_DELETE","TOKEN_REGENERATE","toAdminPermissionRefs","permissions","map","permission","action","subject","properties","toActionRefs","TOKEN_EDITABLE_FIELDS","sortRefs","refs","sortBy","JSON","parse","stringify","ref","getTokenChanges","previous","next","changes","field","before","after","undefined","isEqual","toIso","value","Date","toISOString","registerTokenAuditEvents","auditLogsLifecycle","tokenResource","event","type","kind","id","tokenId","name","owner","adminUserOwner","registerEvent","resource","details","description","lifespan","Number","expiresAt"],"mappings":"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"}