1- import asyncio
1+ import logging
2+ from typing import Any
23from app .core .config import settings
3- from fastapi import logger
4- from openfga_sdk .client import ClientConfiguration , OpenFgaClient , ClientCheckRequest
5- from openfga_sdk .client .models import ClientBatchCheckRequest , ClientWriteRequest , ClientBatchCheckItem
4+ from openfga_sdk import (
5+ Condition ,
6+ ConditionParamTypeRef ,
7+ CreateStoreRequest ,
8+ Metadata ,
9+ ObjectRelation ,
10+ OpenFgaClient ,
11+ ReadRequestTupleKey ,
12+ RelationMetadata ,
13+ RelationReference ,
14+ RelationshipCondition ,
15+ TypeDefinition ,
16+ Userset ,
17+ Usersets ,
18+ UserTypeFilter ,
19+ WriteAuthorizationModelRequest ,
20+ )
21+ from openfga_sdk .client .models import (
22+ ClientAssertion ,
23+ ClientBatchCheckItem ,
24+ ClientBatchCheckRequest ,
25+ ClientCheckRequest ,
26+ ClientListObjectsRequest ,
27+ ClientListRelationsRequest ,
28+ ClientReadChangesRequest ,
29+ ClientTuple ,
30+ ClientWriteRequest ,
31+ WriteTransactionOpts ,
32+ )
33+ from openfga_sdk .client .models .list_users_request import ClientListUsersRequest
34+ from openfga_sdk .credentials import CredentialConfiguration , Credentials
35+ from openfga_sdk .models .fga_object import FgaObject
636from openfga_sdk .client .models .tuple import ClientTuple
37+ from openfga_sdk .client import ClientConfiguration
38+ from openfga_sdk .sync import OpenFgaClient
739
8- # We default fga_client to None until it is initialized
9- fga_client = None
1040
11- async def initialize_fga_client ():
12- # This function is called to initialize our FGA Client instance if it is not already available
13- print ("Initializing OpenFGA Client SDK" )
14- configuration = ClientConfiguration (
15- api_url = settings .OPENFGA_API_URL ,
16- store_id = settings .OPENFGA_STORE_ID ,
17- authorization_model_id = settings .OPENFGA_AUTHORIZATION_MODEL_ID ,
18- )
41+ import traceback
1942
20- global fga_client
43+ logging .basicConfig (level = logging .INFO )
44+ logger = logging .getLogger (__name__ )
2145
46+ def initialize_fga_client ():
47+ configuration = ClientConfiguration (
48+ api_url = settings .OPENFGA_API_URL , # required
49+ store_id = settings .OPENFGA_STORE_ID , # optional, not needed when calling `CreateStore` or `ListStores`
50+ authorization_model_id = settings .OPENFGA_AUTHORIZATION_MODEL_ID , # optional, can be overridden per request
51+ )
2252 # Enter a context with an instance of the OpenFgaClient
23- async with OpenFgaClient (configuration ) as fga_client :
24- fga_client = OpenFgaClient (configuration )
25- await fga_client .read_authorization_models () # type: ignore
26- print ("FGA Client initialized." )
27- return True
53+ with OpenFgaClient (configuration ) as fga_client :
54+ return fga_client
2855
29- async def close_fga_client (fga_client : OpenFgaClient ):
30- await fga_client .close ()
56+ def close_fga_client (fga_client : OpenFgaClient ):
57+ fga_client .close ()
3158
3259# Check if a user has a permission on an object
33- async def check_user_has_permission (tuple : ClientTuple ) -> bool :
34- if fga_client is None :
35- await initialize_fga_client ()
60+ def check_user_has_permission (fga_client : OpenFgaClient , tuple : ClientTuple ) -> bool :
61+ if fga_client is None : # type: ignore
62+ fga_client = initialize_fga_client ()
3663
3764 if fga_client is None :
3865 logger .info ("FGA client not initialized" ) # type: ignore
3966 return False
4067
4168 try :
42- response = await fga_client .check (
69+ response = fga_client .check (
4370 ClientCheckRequest (
4471 user = tuple .user ,
4572 relation = tuple .relation ,
@@ -65,16 +92,19 @@ async def check_user_has_permission(tuple: ClientTuple) -> bool:
6592# "object": "document:123"
6693# }
6794# ]
68- async def check_user_has_permission_batch (tuples : list [ClientBatchCheckItem ]) -> bool :
69- if fga_client is None :
70- await initialize_fga_client ()
95+ def check_user_has_permission_batch (fga_client : OpenFgaClient , tuples : list [ClientBatchCheckItem ]) -> bool :
96+ if fga_client is None : # type: ignore
97+ fga_client = initialize_fga_client ()
7198
7299 if fga_client is None :
73100 logger .info ("FGA client not initialized" ) # type: ignore
74101 return False
75102
103+ logger .info (f"Check fga_client: { fga_client } " )
104+ logger .info (f"Check fga status: { fga_client .get_store_id ()} " )
105+
76106 try :
77- response = await fga_client .batch_check (
107+ response = fga_client .batch_check (
78108 ClientBatchCheckRequest (
79109 checks = tuples
80110 )
@@ -93,37 +123,37 @@ async def check_user_has_permission_batch(tuples: list[ClientBatchCheckItem]) ->
93123# "object": "document:123"
94124# }
95125# ]
96- async def create_fga_tuple (tuples : list [ClientTuple ]) -> bool :
97- if fga_client is None :
98- await initialize_fga_client ()
126+ def create_fga_tuple (fga_client : OpenFgaClient , tuples : list [ClientTuple ]) -> bool :
127+ if fga_client is None : # type: ignore
128+ fga_client = initialize_fga_client ()
99129
100130 if fga_client is None :
101131 logger .info ("FGA client not initialized" ) # type: ignore
102132 return False
103133
134+ logger .info (f"Creating FGA tuple: { tuples } " )
135+ logger .info (f"So is this even working lol: { fga_client .get_store_id ()} " )
136+
104137 try :
105- response = await fga_client .write (
106- ClientWriteRequest (
107- writes = tuples
108- )
109- )
110- return response .allowed # type: ignore
138+ response = fga_client .write_tuples (tuples )
139+ logger .info (f"Response vars: { vars (response )} " )
140+ return True
111141 except Exception as e :
112142 logger .info (f"Error creating FGA tuple: { e } " ) # type: ignore
113143 return False
114144
115145# Delete a tuple
116- async def delete_fga_tuple (tuples : list [ClientTuple ]) -> bool :
146+ def delete_fga_tuple (fga_client : OpenFgaClient , tuples : list [ClientTuple ]) -> bool :
117147 # This is the opposite of the create_fga_tuple function
118- if fga_client is None :
119- await initialize_fga_client ()
148+ if fga_client is None : # type: ignore
149+ fga_client = initialize_fga_client ()
120150
121151 if fga_client is None :
122152 logger .info ("FGA client not initialized" ) # type: ignore
123153 return False
124154
125155 try :
126- response = await fga_client .write (
156+ response = fga_client .write (
127157 ClientWriteRequest (
128158 deletes = tuples
129159 )
@@ -132,3 +162,32 @@ async def delete_fga_tuple(tuples: list[ClientTuple]) -> bool:
132162 except Exception as e :
133163 logger .info (f"Error deleting FGA tuple: { e } " ) # type: ignore
134164 return False
165+
166+
167+ def check_user_has_relation (fga_client : OpenFgaClient , relation : str , user : str ) -> list [str ]:
168+
169+ if fga_client is None : # type: ignore
170+ fga_client = initialize_fga_client ()
171+
172+ if fga_client is None :
173+ logger .info ("FGA client not initialized" ) # type: ignore
174+ return []
175+
176+ body = ClientListObjectsRequest (
177+ user = f"user:{ user } " ,
178+ relation = f"{ relation } " ,
179+ type = "item"
180+ )
181+
182+ try :
183+ response = fga_client .list_objects (body )
184+ # response.objects = ["document:otherdoc", "document:planning"]
185+ # we need to return a list of objects
186+ if len (response .objects ) > 0 :
187+ return [item .split (":" )[1 ] for item in response .objects ] # type: ignore
188+ else :
189+ return []
190+ except Exception as e :
191+ logger .info (f"Error checking user relation: { e } " )
192+ logger .info (traceback .format_exc ())
193+ return []
0 commit comments