github.com/openfga/openfga@v1.5.4-rc1/pkg/server/commands/listusers/list_users.go (about) 1 package listusers 2 3 import ( 4 "maps" 5 "sync/atomic" 6 7 openfgav1 "github.com/openfga/api/proto/openfga/v1" 8 "google.golang.org/protobuf/types/known/structpb" 9 ) 10 11 type listUsersRequest interface { 12 GetStoreId() string 13 GetAuthorizationModelId() string 14 GetObject() *openfgav1.Object 15 GetRelation() string 16 GetUserFilters() []*openfgav1.UserTypeFilter 17 GetContextualTuples() []*openfgav1.TupleKey 18 GetContext() *structpb.Struct 19 } 20 21 type internalListUsersRequest struct { 22 *openfgav1.ListUsersRequest 23 24 // visitedUsersetsMap keeps track of the "path" we've made so far. 25 // It prevents stack overflows by preventing visiting the same userset twice. 26 visitedUsersetsMap map[string]struct{} 27 28 // depth is the current depths of the traversal expressed as a positive, incrementing integer. 29 // When expansion of list users recursively traverses one level, we increment by one. If this 30 // counter hits the limit, we throw ErrResolutionDepthExceeded. This protects against a potentially deep 31 // or endless cycle of recursion. 32 depth uint32 33 34 datastoreQueryCount *atomic.Uint32 35 } 36 37 var _ listUsersRequest = (*internalListUsersRequest)(nil) 38 39 // nolint // it should be GetStoreID, but we want to satisfy the interface listUsersRequest 40 func (r *internalListUsersRequest) GetStoreId() string { 41 if r == nil { 42 return "" 43 } 44 return r.StoreId 45 } 46 47 // nolint // it should be GetAuthorizationModelID, but we want to satisfy the interface listUsersRequest 48 func (r *internalListUsersRequest) GetAuthorizationModelId() string { 49 if r == nil { 50 return "" 51 } 52 return r.AuthorizationModelId 53 } 54 55 func (r *internalListUsersRequest) GetObject() *openfgav1.Object { 56 if r == nil { 57 return nil 58 } 59 return r.Object 60 } 61 62 func (r *internalListUsersRequest) GetRelation() string { 63 if r == nil { 64 return "" 65 } 66 return r.Relation 67 } 68 69 func (r *internalListUsersRequest) GetUserFilters() []*openfgav1.UserTypeFilter { 70 if r == nil { 71 return nil 72 } 73 return r.UserFilters 74 } 75 76 func (r *internalListUsersRequest) GetContextualTuples() []*openfgav1.TupleKey { 77 if r == nil { 78 return nil 79 } 80 return r.ContextualTuples 81 } 82 83 func (r *internalListUsersRequest) GetDatastoreQueryCount() uint32 { 84 if r == nil { 85 return uint32(0) 86 } 87 return r.datastoreQueryCount.Load() 88 } 89 90 func (r *internalListUsersRequest) GetContext() *structpb.Struct { 91 if r == nil { 92 return nil 93 } 94 return r.Context 95 } 96 97 type listUsersResponse struct { 98 Users []*openfgav1.User 99 Metadata listUsersResponseMetadata 100 } 101 102 type listUsersResponseMetadata struct { 103 DatastoreQueryCount uint32 104 } 105 106 func (r *listUsersResponse) GetUsers() []*openfgav1.User { 107 if r == nil { 108 return []*openfgav1.User{} 109 } 110 return r.Users 111 } 112 113 func (r *listUsersResponse) GetMetadata() listUsersResponseMetadata { 114 if r == nil { 115 return listUsersResponseMetadata{} 116 } 117 return r.Metadata 118 } 119 120 func fromListUsersRequest(o listUsersRequest, datastoreQueryCount *atomic.Uint32) *internalListUsersRequest { 121 if datastoreQueryCount == nil { 122 datastoreQueryCount = new(atomic.Uint32) 123 } 124 return &internalListUsersRequest{ 125 ListUsersRequest: &openfgav1.ListUsersRequest{ 126 StoreId: o.GetStoreId(), 127 AuthorizationModelId: o.GetAuthorizationModelId(), 128 Object: o.GetObject(), 129 Relation: o.GetRelation(), 130 UserFilters: o.GetUserFilters(), 131 ContextualTuples: o.GetContextualTuples(), 132 Context: o.GetContext(), 133 }, 134 visitedUsersetsMap: make(map[string]struct{}), 135 depth: 0, 136 datastoreQueryCount: datastoreQueryCount, 137 } 138 } 139 140 // clone creates a copy of the request. Note that some fields are not deep-cloned. 141 func (r *internalListUsersRequest) clone() *internalListUsersRequest { 142 v := fromListUsersRequest(r, r.datastoreQueryCount) 143 v.visitedUsersetsMap = maps.Clone(r.visitedUsersetsMap) 144 v.depth = r.depth 145 return v 146 }