Search Apps Documentation Source Content File Folder Download Copy Actions Download

assignments.gno

12.48 Kb · 453 lines
  1package rbac
  2
  3import (
  4	"gno.land/p/g1nqnrt3aldzhu6zzeg75yw97wvavqy7wr77g56q/deploy-test/v2/ds/btree"
  5	"gno.land/p/g1nqnrt3aldzhu6zzeg75yw97wvavqy7wr77g56q/deploy-test/v2/ds/btreeset"
  6)
  7
  8type assignments struct {
  9	degree              int
 10	entityUserRoleIndex *btree.StringBTree
 11	entityRoleUserIndex *btree.StringBTree
 12	userRoleEntityIndex *btree.StringBTree
 13}
 14
 15func newAssignments(degree int) *assignments {
 16	return &assignments{
 17		degree:              degree,
 18		entityUserRoleIndex: btree.NewStringBTree(degree),
 19		entityRoleUserIndex: btree.NewStringBTree(degree),
 20		userRoleEntityIndex: btree.NewStringBTree(degree),
 21	}
 22}
 23
 24func (as *assignments) Add(entityID string, user address, roleID uint32) {
 25	as.validateEntityID(entityID)
 26
 27	roles := as.getOrCreateEntityUserRoleSet(entityID, user)
 28	if roles.Has(roleID) {
 29		panic("assignment already exists: entityID=" + entityID + ", user=" + user.String() + ", roleID=" + formatRoleID(roleID))
 30	}
 31	roles.Set(roleID)
 32
 33	users := as.getOrCreateEntityRoleUserSet(entityID, roleID)
 34	users.Set(user.String())
 35
 36	entities := as.getOrCreateUserRoleEntitySet(user, roleID)
 37	entities.Set(entityID)
 38}
 39
 40func (as *assignments) Delete(entityID string, user address, roleID uint32) {
 41	as.validateEntityID(entityID)
 42
 43	roles, found := as.findEntityUserRoleSet(entityID, user)
 44	if !found || !roles.Has(roleID) {
 45		panic("assignment not found: entityID=" + entityID + ", user=" + user.String() + ", roleID=" + formatRoleID(roleID))
 46	}
 47	roles.Remove(roleID)
 48	as.cleanupEntityUserRoleSet(entityID, user, roles)
 49
 50	users, found := as.findEntityRoleUserSet(entityID, roleID)
 51	if found {
 52		users.Remove(user.String())
 53		as.cleanupEntityRoleUserSet(entityID, roleID, users)
 54	}
 55
 56	entities, found := as.findUserRoleEntitySet(user, roleID)
 57	if found {
 58		entities.Remove(entityID)
 59		as.cleanupUserRoleEntitySet(user, roleID, entities)
 60	}
 61}
 62
 63func (as *assignments) Has(entityID string, user address, roleID uint32) bool {
 64	as.validateEntityID(entityID)
 65
 66	roles, found := as.findEntityUserRoleSet(entityID, user)
 67	if !found {
 68		return false
 69	}
 70	return roles.Has(roleID)
 71}
 72
 73func (as *assignments) DeleteRole(roleID uint32) {
 74	emptyEntityRoleKeys := []string{}
 75	as.entityRoleUserIndex.Iterate(nil, nil, func(entityID string, roleUsersValue any) bool {
 76		roleUsers := castEntityRoleUserTree(entityID, roleUsersValue)
 77		usersValue, found := roleUsers.Get(roleID)
 78		if !found {
 79			return false
 80		}
 81
 82		users := castAssignmentUserSet(roleID, usersValue)
 83		users.Iterate(nil, nil, func(userKey string) bool {
 84			user := address(userKey)
 85			if roles, found := as.findEntityUserRoleSet(entityID, user); found {
 86				roles.Remove(roleID)
 87				as.cleanupEntityUserRoleSet(entityID, user, roles)
 88			}
 89			if entities, found := as.findUserRoleEntitySet(user, roleID); found {
 90				entities.Remove(entityID)
 91				as.cleanupUserRoleEntitySet(user, roleID, entities)
 92			}
 93			return false
 94		})
 95
 96		roleUsers.Remove(roleID)
 97		if roleUsers.Size() == 0 {
 98			emptyEntityRoleKeys = append(emptyEntityRoleKeys, entityID)
 99		}
100		return false
101	})
102	for _, entityID := range emptyEntityRoleKeys {
103		as.entityRoleUserIndex.Remove(entityID)
104	}
105}
106
107func (as *assignments) DeleteEntity(entityID string) {
108	as.validateEntityID(entityID)
109
110	userRoles, found := as.findEntityUserRoleTree(entityID)
111	if !found {
112		as.entityRoleUserIndex.Remove(entityID)
113		return
114	}
115
116	userRoles.Iterate(nil, nil, func(userKey string, rolesValue any) bool {
117		user := address(userKey)
118		roles := castAssignmentRoleSet(entityID, rolesValue)
119		roles.Iterate(nil, nil, func(roleID uint32) bool {
120			if entities, found := as.findUserRoleEntitySet(user, roleID); found {
121				entities.Remove(entityID)
122				as.cleanupUserRoleEntitySet(user, roleID, entities)
123			}
124			return false
125		})
126		return false
127	})
128
129	as.entityUserRoleIndex.Remove(entityID)
130	as.entityRoleUserIndex.Remove(entityID)
131}
132
133func (as *assignments) ListRoles(entityID string, user address, page int, count int) []uint32 {
134	as.validateEntityID(entityID)
135	offset := pageOffset(page, count)
136
137	roles, found := as.findEntityUserRoleSet(entityID, user)
138	if !found {
139		return []uint32{}
140	}
141	return listUint32SetByOffset(roles, offset, count)
142}
143
144func (as *assignments) ListUsers(entityID string, roleID uint32, page int, count int) []address {
145	as.validateEntityID(entityID)
146	offset := pageOffset(page, count)
147
148	users, found := as.findEntityRoleUserSet(entityID, roleID)
149	if !found {
150		return []address{}
151	}
152
153	result := make([]address, 0, count)
154	users.IterateByOffset(offset, count, func(userKey string) bool {
155		result = append(result, address(userKey))
156		return false
157	})
158	return result
159}
160
161func (as *assignments) ListEntities(user address, roleID uint32, page int, count int) []string {
162	offset := pageOffset(page, count)
163
164	entities, found := as.findUserRoleEntitySet(user, roleID)
165	if !found {
166		return []string{}
167	}
168	return listStringSetByOffset(entities, offset, count)
169}
170
171func (as *assignments) Size() int {
172	size := 0
173	as.entityUserRoleIndex.Iterate(nil, nil, func(entityID string, userRolesValue any) bool {
174		userRoles := castEntityUserRoleTree(entityID, userRolesValue)
175		userRoles.Iterate(nil, nil, func(_ string, rolesValue any) bool {
176			size += castAssignmentRoleSet(entityID, rolesValue).Size()
177			return false
178		})
179		return false
180	})
181	return size
182}
183
184func (as *assignments) UserSize(entityID string, user address) int {
185	as.validateEntityID(entityID)
186
187	roles, found := as.findEntityUserRoleSet(entityID, user)
188	if !found {
189		return 0
190	}
191	return roles.Size()
192}
193
194func (as *assignments) RoleSize(entityID string, roleID uint32) int {
195	as.validateEntityID(entityID)
196
197	users, found := as.findEntityRoleUserSet(entityID, roleID)
198	if !found {
199		return 0
200	}
201	return users.Size()
202}
203
204func (as *assignments) EntitySize(user address, roleID uint32) int {
205	entities, found := as.findUserRoleEntitySet(user, roleID)
206	if !found {
207		return 0
208	}
209	return entities.Size()
210}
211
212func (as *assignments) findEntityUserRoleSet(entityID string, user address) (*btreeset.Uint32BTreeSet, bool) {
213	userRoles, found := as.findEntityUserRoleTree(entityID)
214	if !found {
215		return nil, false
216	}
217	rolesValue, found := userRoles.Get(user.String())
218	if !found {
219		return nil, false
220	}
221	return castAssignmentRoleSet(entityID, rolesValue), true
222}
223
224func (as *assignments) getOrCreateEntityUserRoleSet(entityID string, user address) *btreeset.Uint32BTreeSet {
225	userRoles := as.getOrCreateEntityUserRoleTree(entityID)
226	rolesValue, found := userRoles.Get(user.String())
227	if found {
228		return castAssignmentRoleSet(entityID, rolesValue)
229	}
230
231	roles := btreeset.NewUint32BTreeSet(as.degree)
232	userRoles.Set(user.String(), roles)
233	return roles
234}
235
236func (as *assignments) findEntityUserRoleTree(entityID string) (*btree.StringBTree, bool) {
237	userRolesValue, found := as.entityUserRoleIndex.Get(entityID)
238	if !found {
239		return nil, false
240	}
241	return castEntityUserRoleTree(entityID, userRolesValue), true
242}
243
244func (as *assignments) getOrCreateEntityUserRoleTree(entityID string) *btree.StringBTree {
245	userRoles, found := as.findEntityUserRoleTree(entityID)
246	if found {
247		return userRoles
248	}
249
250	userRoles = btree.NewStringBTree(as.degree)
251	as.entityUserRoleIndex.Set(entityID, userRoles)
252	return userRoles
253}
254
255func (as *assignments) findEntityRoleUserSet(entityID string, roleID uint32) (*btreeset.StringBTreeSet, bool) {
256	roleUsers, found := as.findEntityRoleUserTree(entityID)
257	if !found {
258		return nil, false
259	}
260	usersValue, found := roleUsers.Get(roleID)
261	if !found {
262		return nil, false
263	}
264	return castAssignmentUserSet(roleID, usersValue), true
265}
266
267func (as *assignments) getOrCreateEntityRoleUserSet(entityID string, roleID uint32) *btreeset.StringBTreeSet {
268	roleUsers := as.getOrCreateEntityRoleUserTree(entityID)
269	usersValue, found := roleUsers.Get(roleID)
270	if found {
271		return castAssignmentUserSet(roleID, usersValue)
272	}
273
274	users := btreeset.NewStringBTreeSet(as.degree)
275	roleUsers.Set(roleID, users)
276	return users
277}
278
279func (as *assignments) findEntityRoleUserTree(entityID string) (*btree.Uint32BTree, bool) {
280	roleUsersValue, found := as.entityRoleUserIndex.Get(entityID)
281	if !found {
282		return nil, false
283	}
284	return castEntityRoleUserTree(entityID, roleUsersValue), true
285}
286
287func (as *assignments) getOrCreateEntityRoleUserTree(entityID string) *btree.Uint32BTree {
288	roleUsers, found := as.findEntityRoleUserTree(entityID)
289	if found {
290		return roleUsers
291	}
292
293	roleUsers = btree.NewUint32BTree(as.degree)
294	as.entityRoleUserIndex.Set(entityID, roleUsers)
295	return roleUsers
296}
297
298func (as *assignments) findUserRoleEntitySet(user address, roleID uint32) (*btreeset.StringBTreeSet, bool) {
299	roleEntities, found := as.findUserRoleEntityTree(user)
300	if !found {
301		return nil, false
302	}
303	entitiesValue, found := roleEntities.Get(roleID)
304	if !found {
305		return nil, false
306	}
307	return castAssignmentEntitySet(roleID, entitiesValue), true
308}
309
310func (as *assignments) getOrCreateUserRoleEntitySet(user address, roleID uint32) *btreeset.StringBTreeSet {
311	roleEntities := as.getOrCreateUserRoleEntityTree(user)
312	entitiesValue, found := roleEntities.Get(roleID)
313	if found {
314		return castAssignmentEntitySet(roleID, entitiesValue)
315	}
316
317	entities := btreeset.NewStringBTreeSet(as.degree)
318	roleEntities.Set(roleID, entities)
319	return entities
320}
321
322func (as *assignments) findUserRoleEntityTree(user address) (*btree.Uint32BTree, bool) {
323	roleEntitiesValue, found := as.userRoleEntityIndex.Get(user.String())
324	if !found {
325		return nil, false
326	}
327	return castUserRoleEntityTree(user, roleEntitiesValue), true
328}
329
330func (as *assignments) getOrCreateUserRoleEntityTree(user address) *btree.Uint32BTree {
331	roleEntities, found := as.findUserRoleEntityTree(user)
332	if found {
333		return roleEntities
334	}
335
336	roleEntities = btree.NewUint32BTree(as.degree)
337	as.userRoleEntityIndex.Set(user.String(), roleEntities)
338	return roleEntities
339}
340
341func (as *assignments) cleanupEntityUserRoleSet(entityID string, user address, roles *btreeset.Uint32BTreeSet) {
342	if roles.Size() > 0 {
343		return
344	}
345	userRoles, found := as.findEntityUserRoleTree(entityID)
346	if !found {
347		return
348	}
349	userRoles.Remove(user.String())
350	if userRoles.Size() == 0 {
351		as.entityUserRoleIndex.Remove(entityID)
352	}
353}
354
355func (as *assignments) cleanupEntityRoleUserSet(entityID string, roleID uint32, users *btreeset.StringBTreeSet) {
356	if users.Size() > 0 {
357		return
358	}
359	roleUsers, found := as.findEntityRoleUserTree(entityID)
360	if !found {
361		return
362	}
363	roleUsers.Remove(roleID)
364	if roleUsers.Size() == 0 {
365		as.entityRoleUserIndex.Remove(entityID)
366	}
367}
368
369func (as *assignments) cleanupUserRoleEntitySet(user address, roleID uint32, entities *btreeset.StringBTreeSet) {
370	if entities.Size() > 0 {
371		return
372	}
373	roleEntities, found := as.findUserRoleEntityTree(user)
374	if !found {
375		return
376	}
377	roleEntities.Remove(roleID)
378	if roleEntities.Size() == 0 {
379		as.userRoleEntityIndex.Remove(user.String())
380	}
381}
382
383func (as *assignments) validateEntityID(entityID string) {
384	if entityID == "" {
385		panic("entityID required")
386	}
387}
388
389func listUint32SetByOffset(set *btreeset.Uint32BTreeSet, offset int, count int) []uint32 {
390	result := make([]uint32, 0, count)
391	set.IterateByOffset(offset, count, func(id uint32) bool {
392		result = append(result, id)
393		return false
394	})
395	return result
396}
397
398func listStringSetByOffset(set *btreeset.StringBTreeSet, offset int, count int) []string {
399	result := make([]string, 0, count)
400	set.IterateByOffset(offset, count, func(id string) bool {
401		result = append(result, id)
402		return false
403	})
404	return result
405}
406
407func castEntityUserRoleTree(entityID string, userRolesValue any) *btree.StringBTree {
408	userRoles, ok := userRolesValue.(*btree.StringBTree)
409	if !ok {
410		panic("invalid entity user role index: " + entityID)
411	}
412	return userRoles
413}
414
415func castEntityRoleUserTree(entityID string, roleUsersValue any) *btree.Uint32BTree {
416	roleUsers, ok := roleUsersValue.(*btree.Uint32BTree)
417	if !ok {
418		panic("invalid entity role user index: " + entityID)
419	}
420	return roleUsers
421}
422
423func castUserRoleEntityTree(user address, roleEntitiesValue any) *btree.Uint32BTree {
424	roleEntities, ok := roleEntitiesValue.(*btree.Uint32BTree)
425	if !ok {
426		panic("invalid user role entity index: " + user.String())
427	}
428	return roleEntities
429}
430
431func castAssignmentRoleSet(entityID string, rolesValue any) *btreeset.Uint32BTreeSet {
432	roles, ok := rolesValue.(*btreeset.Uint32BTreeSet)
433	if !ok {
434		panic("invalid user role set: " + entityID)
435	}
436	return roles
437}
438
439func castAssignmentUserSet(roleID uint32, usersValue any) *btreeset.StringBTreeSet {
440	users, ok := usersValue.(*btreeset.StringBTreeSet)
441	if !ok {
442		panic("invalid role user set: " + formatRoleID(roleID))
443	}
444	return users
445}
446
447func castAssignmentEntitySet(roleID uint32, entitiesValue any) *btreeset.StringBTreeSet {
448	entities, ok := entitiesValue.(*btreeset.StringBTreeSet)
449	if !ok {
450		panic("invalid user role entity set: " + formatRoleID(roleID))
451	}
452	return entities
453}