1
1
import uuid
2
2
import secrets
3
+ import logging
3
4
from sqlmodel import Session , select
4
5
from app .core .security import (
5
6
get_password_hash ,
11
12
from app .core .exception_handlers import HTTPException
12
13
from app .models .api_key import APIKey , APIKeyPublic
13
14
15
+ logger = logging .getLogger (__name__ )
16
+
14
17
15
18
def generate_api_key () -> tuple [str , str ]:
16
19
"""Generate a new API key and its hash."""
20
+ logger .info (
21
+ f"[generate_api_key] Generating new API key | {{'action': 'generate'}}"
22
+ )
17
23
raw_key = "ApiKey " + secrets .token_urlsafe (32 )
18
24
hashed_key = get_password_hash (raw_key )
25
+ logger .info (
26
+ f"[generate_api_key] API key generated successfully | {{'action': 'generated'}}"
27
+ )
19
28
return raw_key , hashed_key
20
29
21
30
@@ -26,11 +35,15 @@ def create_api_key(
26
35
Generates a new API key for an organization and associates it with a user.
27
36
Returns the API key details with the raw key (shown only once).
28
37
"""
38
+ logger .info (
39
+ f"[create_api_key] Starting API key creation | {{'organization_id': { organization_id } , 'user_id': { user_id } , 'project_id': { project_id } }}"
40
+ )
29
41
# Generate raw key and its hash using the helper function
30
42
raw_key , hashed_key = generate_api_key ()
31
- encrypted_key = encrypt_api_key (
32
- raw_key
33
- ) # Encrypt the raw key instead of hashed key
43
+ encrypted_key = encrypt_api_key (raw_key ) # Encrypt the raw key instead of hashed key
44
+ logger .info (
45
+ f"[create_api_key] API key encrypted | {{'user_id': { user_id } , 'project_id': { project_id } }}"
46
+ )
34
47
35
48
# Create API key record with encrypted raw key
36
49
api_key = APIKey (
@@ -43,11 +56,17 @@ def create_api_key(
43
56
session .add (api_key )
44
57
session .commit ()
45
58
session .refresh (api_key )
59
+ logger .info (
60
+ f"[create_api_key] API key created and stored | {{'api_key_id': { api_key .id } , 'user_id': { user_id } , 'project_id': { project_id } }}"
61
+ )
46
62
47
63
# Set the raw key in the response (shown only once)
48
64
api_key_dict = api_key .model_dump ()
49
65
api_key_dict ["key" ] = raw_key # Return the raw key to the user
50
66
67
+ logger .info (
68
+ f"[create_api_key] API key creation completed | {{'api_key_id': { api_key .id } , 'user_id': { user_id } , 'project_id': { project_id } }}"
69
+ )
51
70
return APIKeyPublic .model_validate (api_key_dict )
52
71
53
72
@@ -56,6 +75,9 @@ def get_api_key(session: Session, api_key_id: int) -> APIKeyPublic | None:
56
75
Retrieves an API key by its ID if it exists and is not deleted.
57
76
Returns the API key in its original format.
58
77
"""
78
+ logger .info (
79
+ f"[get_api_key] Retrieving API key | {{'api_key_id': { api_key_id } }}"
80
+ )
59
81
api_key = session .exec (
60
82
select (APIKey ).where (APIKey .id == api_key_id , APIKey .is_deleted == False )
61
83
).first ()
@@ -66,41 +88,67 @@ def get_api_key(session: Session, api_key_id: int) -> APIKeyPublic | None:
66
88
# Decrypt the key
67
89
decrypted_key = decrypt_api_key (api_key .key )
68
90
api_key_dict ["key" ] = decrypted_key
69
-
91
+ logger .info (
92
+ f"[get_api_key] API key retrieved successfully | {{'api_key_id': { api_key_id } }}"
93
+ )
70
94
return APIKeyPublic .model_validate (api_key_dict )
95
+
96
+ logger .warning (
97
+ f"[get_api_key] API key not found | {{'api_key_id': { api_key_id } }}"
98
+ )
71
99
return None
72
100
73
101
74
102
def delete_api_key (session : Session , api_key_id : int ) -> None :
75
103
"""
76
104
Soft deletes (revokes) an API key by marking it as deleted.
77
105
"""
106
+ logger .info (
107
+ f"[delete_api_key] Starting API key deletion | {{'api_key_id': { api_key_id } }}"
108
+ )
78
109
api_key = session .get (APIKey , api_key_id )
79
110
111
+ if not api_key :
112
+ logger .error (
113
+ f"[delete_api_key] API key not found | {{'api_key_id': { api_key_id } }}"
114
+ )
115
+ return
116
+
80
117
api_key .is_deleted = True
81
118
api_key .deleted_at = now ()
82
119
api_key .updated_at = now ()
83
120
84
121
session .add (api_key )
85
122
session .commit ()
123
+ logger .info (
124
+ f"[delete_api_key] API key soft deleted successfully | {{'api_key_id': { api_key_id } }}"
125
+ )
86
126
87
127
88
128
def get_api_key_by_value (session : Session , api_key_value : str ) -> APIKeyPublic | None :
89
129
"""
90
130
Retrieve an API Key record by verifying the provided key against stored hashes.
91
131
Returns the API key in its original format.
92
132
"""
133
+ logger .info (
134
+ f"[get_api_key_by_value] Retrieving API key by value | {{'action': 'lookup'}}"
135
+ )
93
136
# Get all active API keys
94
137
api_keys = session .exec (select (APIKey ).where (APIKey .is_deleted == False )).all ()
95
138
96
139
for api_key in api_keys :
97
140
decrypted_key = decrypt_api_key (api_key .key )
98
141
if api_key_value == decrypted_key :
99
142
api_key_dict = api_key .model_dump ()
100
-
101
143
api_key_dict ["key" ] = decrypted_key
102
-
144
+ logger .info (
145
+ f"[get_api_key_by_value] API key found | {{'api_key_id': { api_key .id } }}"
146
+ )
103
147
return APIKeyPublic .model_validate (api_key_dict )
148
+
149
+ logger .warning (
150
+ f"[get_api_key_by_value] API key not found | {{'action': 'not_found'}}"
151
+ )
104
152
return None
105
153
106
154
@@ -110,6 +158,9 @@ def get_api_key_by_project_user(
110
158
"""
111
159
Retrieves the single API key associated with a project.
112
160
"""
161
+ logger .info (
162
+ f"[get_api_key_by_project_user] Retrieving API key | {{'project_id': { project_id } , 'user_id': '{ user_id } '}}"
163
+ )
113
164
statement = select (APIKey ).where (
114
165
APIKey .user_id == user_id ,
115
166
APIKey .project_id == project_id ,
@@ -120,15 +171,24 @@ def get_api_key_by_project_user(
120
171
if api_key :
121
172
api_key_dict = api_key .model_dump ()
122
173
api_key_dict ["key" ] = decrypt_api_key (api_key .key )
174
+ logger .info (
175
+ f"[get_api_key_by_project_user] API key retrieved successfully | {{'api_key_id': { api_key .id } , 'project_id': { project_id } , 'user_id': '{ user_id } '}}"
176
+ )
123
177
return APIKeyPublic .model_validate (api_key_dict )
124
178
179
+ logger .warning (
180
+ f"[get_api_key_by_project_user] API key not found | {{'project_id': { project_id } , 'user_id': '{ user_id } '}}"
181
+ )
125
182
return None
126
183
127
184
128
185
def get_api_keys_by_project (session : Session , project_id : int ) -> list [APIKeyPublic ]:
129
186
"""
130
187
Retrieves all API keys associated with a project.
131
188
"""
189
+ logger .info (
190
+ f"[get_api_keys_by_project] Retrieving API keys for project | {{'project_id': { project_id } }}"
191
+ )
132
192
statement = select (APIKey ).where (
133
193
APIKey .project_id == project_id , APIKey .is_deleted == False
134
194
)
@@ -139,5 +199,8 @@ def get_api_keys_by_project(session: Session, project_id: int) -> list[APIKeyPub
139
199
key_dict = key .model_dump ()
140
200
key_dict ["key" ] = decrypt_api_key (key .key )
141
201
result .append (APIKeyPublic .model_validate (key_dict ))
142
-
143
- return result
202
+
203
+ logger .info (
204
+ f"[get_api_keys_by_project] API keys retrieved successfully | {{'project_id': { project_id } , 'key_count': { len (result )} }}"
205
+ )
206
+ return result
0 commit comments