1+ import { getUserInfoByToken } from '@tap/api/src/core/users'
12import Cookie from '@tap/shared/src/cookie'
23import dayjs from 'dayjs'
34import i18n from '@/i18n'
45
6+ type PermissionResource = { code ?: string } & Record < string , any >
7+
8+ const PERMISSIONS_STORAGE_KEY = 'tapdata_permissions'
9+
10+ let cachedPermissions : PermissionResource [ ] | null = null
11+ let permissionsRequest : Promise < PermissionResource [ ] > | null = null
12+
13+ function getPermissionDebugContext ( ) {
14+ const navigation = performance . getEntriesByType ?.( 'navigation' ) ?. [ 0 ] as
15+ | PerformanceNavigationTiming
16+ | undefined
17+
18+ return {
19+ href : location . href ,
20+ navigationType : navigation ?. type ,
21+ visibilityState : document . visibilityState ,
22+ wasDiscarded : ( document as Document & { wasDiscarded ?: boolean } )
23+ . wasDiscarded ,
24+ }
25+ }
26+
27+ function debugPermissions ( message : string , details : Record < string , any > = { } ) {
28+ // eslint-disable-next-line no-console
29+ console . debug ( '[tapdata_permissions]' , message , {
30+ ...getPermissionDebugContext ( ) ,
31+ ...details ,
32+ } )
33+ }
34+
35+ function flattenPermissions ( user : Record < string , any > = { } ) {
36+ const permissions : PermissionResource [ ] = [ ]
37+ const list = user ?. permissions || [ ]
38+
39+ list . forEach ( ( permission : Record < string , any > ) => {
40+ if ( permission . resources && permission . resources . length > 0 ) {
41+ permission . resources . forEach ( ( res : PermissionResource ) => {
42+ permissions . push ( res )
43+ } )
44+ }
45+ } )
46+
47+ return permissions
48+ }
49+
50+ function setPermissions ( permissions : PermissionResource [ ] ) {
51+ cachedPermissions = permissions
52+ sessionStorage . setItem ( PERMISSIONS_STORAGE_KEY , JSON . stringify ( permissions ) )
53+
54+ if ( ! permissions . length ) {
55+ debugPermissions ( 'wrote empty permissions cache' )
56+ }
57+ }
58+
59+ export function clearPermissions ( ) {
60+ cachedPermissions = null
61+ permissionsRequest = null
62+ sessionStorage . removeItem ( PERMISSIONS_STORAGE_KEY )
63+ debugPermissions ( 'cleared permissions cache' )
64+ }
65+
66+ export function getCachedPermissions ( ) {
67+ const permissionsStr = sessionStorage . getItem ( PERMISSIONS_STORAGE_KEY )
68+
69+ if ( permissionsStr !== null ) {
70+ try {
71+ const permissions = JSON . parse ( permissionsStr )
72+
73+ if ( Array . isArray ( permissions ) ) {
74+ cachedPermissions = permissions
75+ return permissions as PermissionResource [ ]
76+ }
77+ debugPermissions ( 'removed invalid permissions cache' , {
78+ valueType : typeof permissions ,
79+ } )
80+ sessionStorage . removeItem ( PERMISSIONS_STORAGE_KEY )
81+ } catch ( error ) {
82+ debugPermissions ( 'removed unparsable permissions cache' , {
83+ errorMessage : error ?. message ,
84+ valueLength : permissionsStr . length ,
85+ } )
86+ sessionStorage . removeItem ( PERMISSIONS_STORAGE_KEY )
87+ }
88+ }
89+
90+ if ( cachedPermissions ) {
91+ debugPermissions ( 'using in-memory permissions cache' , {
92+ permissionsCount : cachedPermissions . length ,
93+ } )
94+ return cachedPermissions
95+ }
96+
97+ return null
98+ }
99+
5100export function configUser ( user : Record < string , any > = { } ) {
6101 Cookie . set ( 'email' , user . email )
7102 Cookie . set ( 'username' , user . username || '' )
8103 Cookie . set ( 'isAdmin' , String ( Number . parseInt ( user . role ) || 0 ) )
9104 Cookie . set ( 'user_id' , user . id )
10- const permissions : string [ ] = [ ]
11- const list = user ?. permissions || [ ]
12- if ( list . length ) {
13- list . forEach ( ( permission : Record < string , any > ) => {
14- if ( permission . resources && permission . resources . length > 0 ) {
15- permission . resources . forEach ( ( res : string ) => {
16- permissions . push ( res )
105+ const permissions = flattenPermissions ( user )
106+
107+ setPermissions ( permissions )
108+
109+ return permissions
110+ }
111+
112+ export function ensurePermissions ( ) {
113+ const permissions = getCachedPermissions ( )
114+
115+ if ( permissions ) {
116+ return Promise . resolve ( permissions )
117+ }
118+
119+ debugPermissions ( 'permissions cache missing, refetching user permissions' )
120+
121+ if ( ! permissionsRequest ) {
122+ permissionsRequest = getUserInfoByToken ( )
123+ . then ( ( user ) => {
124+ const nextPermissions = configUser ( user || { } )
125+
126+ debugPermissions ( 'refetched user permissions' , {
127+ hasUser : Boolean ( user ) ,
128+ permissionsCount : nextPermissions . length ,
129+ userId : user ?. id ,
17130 } )
18- }
19- } )
20- sessionStorage . setItem ( 'tapdata_permissions' , JSON . stringify ( permissions ) )
131+
132+ return nextPermissions
133+ } )
134+ . catch ( ( error ) => {
135+ debugPermissions ( 'failed to refetch user permissions' , {
136+ errorMessage : error ?. message ,
137+ status : error ?. response ?. status ,
138+ } )
139+
140+ throw error
141+ } )
142+ . finally ( ( ) => {
143+ permissionsRequest = null
144+ } )
21145 }
22- return permissions
146+
147+ return permissionsRequest
23148}
24149
25150export function signOut ( ) {
@@ -29,7 +154,7 @@ export function signOut() {
29154 Cookie . remove ( 'isAdmin' )
30155 Cookie . remove ( 'user_id' )
31156 sessionStorage . setItem ( 'lastLocationHref' , location . href )
32- sessionStorage . removeItem ( 'tapdata_permissions' )
157+ clearPermissions ( )
33158 location . href = `${ location . href . split ( '#' ) [ 0 ] } #/login`
34159 return null
35160}
0 commit comments