4
4
5
5
from codegen .cli .auth .constants import AUTH_FILE , CONFIG_DIR
6
6
7
+ # Simple cache to avoid repeated file I/O
8
+ _token_cache = None
9
+ _cache_mtime = None
10
+
7
11
8
12
class TokenManager :
9
13
# Simple token manager to store and retrieve tokens.
@@ -20,17 +24,79 @@ def _ensure_config_dir(self):
20
24
Path (self .config_dir ).mkdir (parents = True , exist_ok = True )
21
25
22
26
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
25
86
26
87
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
28
90
try :
29
91
with open (self .token_file , "w" ) as f :
30
92
json .dump ({"token" : token }, f )
31
93
32
94
# Secure the file permissions (read/write for owner only)
33
95
os .chmod (self .token_file , 0o600 )
96
+
97
+ # Invalidate cache
98
+ _token_cache = None
99
+ _cache_mtime = None
34
100
except Exception as e :
35
101
print (f"Error saving token: { e !s} " )
36
102
raise
@@ -58,20 +124,120 @@ def get_token(self) -> str | None:
58
124
59
125
def clear_token (self ) -> None :
60
126
"""Remove stored token."""
127
+ global _token_cache , _cache_mtime
61
128
if os .path .exists (self .token_file ):
62
129
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
63
173
64
174
65
175
def get_current_token () -> str | None :
66
176
"""Get the current authentication token if one exists.
67
177
68
178
This is a helper function that creates a TokenManager instance and retrieves
69
179
the stored token. The token is validated before being returned.
180
+ Uses a simple cache to avoid repeated file I/O.
70
181
71
182
Returns:
72
183
Optional[str]: The current valid api token if one exists.
73
184
Returns None if no token exists.
74
185
75
186
"""
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
+ """
76
242
token_manager = TokenManager ()
77
- return token_manager .get_token ()
243
+ return token_manager .get_user_info ()
0 commit comments