44
55from codegen .cli .auth .constants import AUTH_FILE , CONFIG_DIR
66
7+ # Simple cache to avoid repeated file I/O
8+ _token_cache = None
9+ _cache_mtime = None
10+
711
812class TokenManager :
913 # Simple token manager to store and retrieve tokens.
@@ -20,17 +24,79 @@ def _ensure_config_dir(self):
2024 Path (self .config_dir ).mkdir (parents = True , exist_ok = True )
2125
2226 def authenticate_token (self , token : str ) -> None :
23- """Store the token locally."""
24- self .save_token (token )
27+ """Store the token locally and fetch organization info."""
28+ self .save_token_with_org_info (token )
29+
30+ def save_token_with_org_info (self , token : str ) -> None :
31+ """Save api token to disk along with organization info."""
32+ global _token_cache , _cache_mtime
33+
34+ # First fetch organization info using the token
35+ try :
36+ import requests
37+
38+ from codegen .cli .api .endpoints import API_ENDPOINT
39+
40+ headers = {"Authorization" : f"Bearer { token } " }
41+
42+ # Test token by getting user info
43+ user_response = requests .get (f"{ API_ENDPOINT .rstrip ('/' )} /v1/users/me" , headers = headers , timeout = 10 )
44+ user_response .raise_for_status ()
45+ user_data = user_response .json ()
46+
47+ # Get organizations
48+ org_response = requests .get (f"{ API_ENDPOINT .rstrip ('/' )} /v1/organizations" , headers = headers , timeout = 10 )
49+ org_response .raise_for_status ()
50+ org_data = org_response .json ()
51+
52+ # Prepare auth data with org info
53+ auth_data = {
54+ "token" : token ,
55+ "user" : {"id" : user_data .get ("id" ), "email" : user_data .get ("email" ), "full_name" : user_data .get ("full_name" ), "github_username" : user_data .get ("github_username" )},
56+ }
57+
58+ # Add organization info if available
59+ orgs = org_data .get ("items" , [])
60+ if orgs and len (orgs ) > 0 :
61+ primary_org = orgs [0 ] # Use first org as primary
62+ auth_data ["organization" ] = {"id" : primary_org .get ("id" ), "name" : primary_org .get ("name" ), "all_orgs" : [{"id" : org .get ("id" ), "name" : org .get ("name" )} for org in orgs ]}
63+
64+ except requests .RequestException as e :
65+ # If we can't fetch org info, still save the token but without org data
66+ print (f"Warning: Could not fetch organization info: { e } " )
67+ auth_data = {"token" : token }
68+ except Exception as e :
69+ print (f"Warning: Error fetching user/org info: { e } " )
70+ auth_data = {"token" : token }
71+
72+ # Save to file
73+ try :
74+ with open (self .token_file , "w" ) as f :
75+ json .dump (auth_data , f , indent = 2 )
76+
77+ # Secure the file permissions (read/write for owner only)
78+ os .chmod (self .token_file , 0o600 )
79+
80+ # Invalidate cache
81+ _token_cache = None
82+ _cache_mtime = None
83+ except Exception as e :
84+ print (f"Error saving token: { e !s} " )
85+ raise
2586
2687 def save_token (self , token : str ) -> None :
27- """Save api token to disk."""
88+ """Save api token to disk (legacy method - just saves token)."""
89+ global _token_cache , _cache_mtime
2890 try :
2991 with open (self .token_file , "w" ) as f :
3092 json .dump ({"token" : token }, f )
3193
3294 # Secure the file permissions (read/write for owner only)
3395 os .chmod (self .token_file , 0o600 )
96+
97+ # Invalidate cache
98+ _token_cache = None
99+ _cache_mtime = None
34100 except Exception as e :
35101 print (f"Error saving token: { e !s} " )
36102 raise
@@ -58,20 +124,120 @@ def get_token(self) -> str | None:
58124
59125 def clear_token (self ) -> None :
60126 """Remove stored token."""
127+ global _token_cache , _cache_mtime
61128 if os .path .exists (self .token_file ):
62129 os .remove (self .token_file )
130+ # Invalidate cache
131+ _token_cache = None
132+ _cache_mtime = None
133+
134+ def get_auth_data (self ) -> dict | None :
135+ """Retrieve complete auth data from disk."""
136+ try :
137+ if not os .access (self .config_dir , os .R_OK ):
138+ return None
139+
140+ if not os .path .exists (self .token_file ):
141+ return None
142+
143+ with open (self .token_file ) as f :
144+ return json .load (f )
145+ except Exception :
146+ return None
147+
148+ def get_org_id (self ) -> int | None :
149+ """Get the stored organization ID."""
150+ auth_data = self .get_auth_data ()
151+ if auth_data and "organization" in auth_data :
152+ org_id = auth_data ["organization" ].get ("id" )
153+ if org_id :
154+ try :
155+ return int (org_id )
156+ except (ValueError , TypeError ):
157+ return None
158+ return None
159+
160+ def get_org_name (self ) -> str | None :
161+ """Get the stored organization name."""
162+ auth_data = self .get_auth_data ()
163+ if auth_data and "organization" in auth_data :
164+ return auth_data ["organization" ].get ("name" )
165+ return None
166+
167+ def get_user_info (self ) -> dict | None :
168+ """Get the stored user info."""
169+ auth_data = self .get_auth_data ()
170+ if auth_data and "user" in auth_data :
171+ return auth_data ["user" ]
172+ return None
63173
64174
65175def get_current_token () -> str | None :
66176 """Get the current authentication token if one exists.
67177
68178 This is a helper function that creates a TokenManager instance and retrieves
69179 the stored token. The token is validated before being returned.
180+ Uses a simple cache to avoid repeated file I/O.
70181
71182 Returns:
72183 Optional[str]: The current valid api token if one exists.
73184 Returns None if no token exists.
74185
75186 """
187+ global _token_cache , _cache_mtime
188+
189+ try :
190+ # Check if token file exists
191+ if not os .path .exists (AUTH_FILE ):
192+ return None
193+
194+ # Get file modification time
195+ current_mtime = os .path .getmtime (AUTH_FILE )
196+
197+ # Use cache if file hasn't changed
198+ if _token_cache is not None and _cache_mtime == current_mtime :
199+ return _token_cache
200+
201+ # Read token from file
202+ token_manager = TokenManager ()
203+ token = token_manager .get_token ()
204+
205+ # Update cache
206+ _token_cache = token
207+ _cache_mtime = current_mtime
208+
209+ return token
210+ except Exception :
211+ # Fall back to uncached version on any error
212+ token_manager = TokenManager ()
213+ return token_manager .get_token ()
214+
215+
216+ def get_current_org_id () -> int | None :
217+ """Get the stored organization ID if available.
218+
219+ Returns:
220+ Optional[int]: The organization ID if stored, None otherwise.
221+ """
222+ token_manager = TokenManager ()
223+ return token_manager .get_org_id ()
224+
225+
226+ def get_current_org_name () -> str | None :
227+ """Get the stored organization name if available.
228+
229+ Returns:
230+ Optional[str]: The organization name if stored, None otherwise.
231+ """
232+ token_manager = TokenManager ()
233+ return token_manager .get_org_name ()
234+
235+
236+ def get_current_user_info () -> dict | None :
237+ """Get the stored user info if available.
238+
239+ Returns:
240+ Optional[dict]: The user info if stored, None otherwise.
241+ """
76242 token_manager = TokenManager ()
77- return token_manager .get_token ()
243+ return token_manager .get_user_info ()
0 commit comments