kamau1 commited on
Commit
82bb0a3
·
verified ·
1 Parent(s): 20dd904

Upload 11 files

Browse files
Files changed (2) hide show
  1. direct_sql.py +238 -0
  2. main.py +229 -44
direct_sql.py ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Direct SQL Script for Turso Database
4
+
5
+ This script uses the HTTP API directly to interact with the Turso database.
6
+ It's designed to work around issues with the libsql-experimental driver.
7
+ """
8
+
9
+ import os
10
+ import sys
11
+ import json
12
+ import requests
13
+ import logging
14
+ import time
15
+ from dotenv import load_dotenv
16
+
17
+ # Configure logging
18
+ logging.basicConfig(
19
+ level=logging.INFO,
20
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
21
+ )
22
+ logger = logging.getLogger("direct-sql")
23
+
24
+ # Load environment variables
25
+ load_dotenv()
26
+
27
+ # Get Turso database connection details
28
+ DATABASE_URL = os.getenv("TURSO_DATABASE_URL")
29
+ AUTH_TOKEN = os.getenv("TURSO_AUTH_TOKEN")
30
+
31
+ if not DATABASE_URL or not AUTH_TOKEN:
32
+ logger.error("Missing Turso credentials. TURSO_DATABASE_URL and TURSO_AUTH_TOKEN must be set.")
33
+ sys.exit(1)
34
+
35
+ # Clean the auth token
36
+ AUTH_TOKEN = AUTH_TOKEN.strip()
37
+
38
+ # Convert URL from libsql:// to https://
39
+ if DATABASE_URL.startswith("libsql://"):
40
+ HTTP_URL = DATABASE_URL.replace("libsql://", "https://")
41
+ else:
42
+ HTTP_URL = DATABASE_URL
43
+
44
+ # Ensure the URL doesn't have a trailing slash
45
+ HTTP_URL = HTTP_URL.rstrip('/')
46
+
47
+ # Verify the URL format
48
+ if not HTTP_URL.startswith("https://"):
49
+ logger.warning(f"HTTP URL does not start with https://: {HTTP_URL}")
50
+ # Try to fix the URL
51
+ if "://" not in HTTP_URL:
52
+ HTTP_URL = f"https://{HTTP_URL}"
53
+ logger.info(f"Added https:// prefix to URL: {HTTP_URL}")
54
+
55
+ logger.info(f"Using HTTP URL: {HTTP_URL}")
56
+
57
+ def execute_sql(sql, params=None):
58
+ """Execute SQL using the HTTP API directly."""
59
+ # Format the request according to the v2/pipeline specification
60
+ requests_data = []
61
+
62
+ # Prepare the statement
63
+ stmt = {"sql": sql}
64
+
65
+ # Add parameters if provided
66
+ if params:
67
+ # Convert parameters to the expected format
68
+ args = []
69
+ for param in params:
70
+ if param is None:
71
+ args.append({"type": "null", "value": None})
72
+ elif isinstance(param, int):
73
+ args.append({"type": "integer", "value": str(param)})
74
+ elif isinstance(param, float):
75
+ args.append({"type": "float", "value": str(param)})
76
+ else:
77
+ args.append({"type": "text", "value": str(param)})
78
+
79
+ stmt["args"] = args
80
+
81
+ requests_data.append({"type": "execute", "stmt": stmt})
82
+
83
+ # Always close the connection at the end
84
+ requests_data.append({"type": "close"})
85
+
86
+ # Prepare the final request payload
87
+ data = {"requests": requests_data}
88
+
89
+ # Use the v2/pipeline endpoint
90
+ pipeline_url = f"{HTTP_URL}/v2/pipeline"
91
+ logger.info(f"Sending request to: {pipeline_url}")
92
+
93
+ headers = {
94
+ "Authorization": f"Bearer {AUTH_TOKEN}",
95
+ "Content-Type": "application/json"
96
+ }
97
+
98
+ try:
99
+ response = requests.post(pipeline_url, headers=headers, json=data, timeout=10)
100
+
101
+ # Log response status
102
+ logger.info(f"Response status: {response.status_code}")
103
+
104
+ # Check for auth errors specifically
105
+ if response.status_code == 401:
106
+ logger.error(f"Authentication error (401): {response.text}")
107
+ return None
108
+
109
+ # Raise for other errors
110
+ response.raise_for_status()
111
+
112
+ # Parse the response
113
+ result = response.json()
114
+
115
+ # Process the response
116
+ if "results" in result and len(result["results"]) > 0:
117
+ return result["results"][0]
118
+
119
+ return None
120
+ except requests.exceptions.RequestException as e:
121
+ logger.error(f"HTTP request failed: {str(e)}")
122
+ return None
123
+
124
+ def create_test_user():
125
+ """Create a test user with email [email protected]."""
126
+ # Generate a unique test ID
127
+ test_id = f"test_{int(time.time())}"
128
+ logger.info(f"[{test_id}] Starting test user creation")
129
+
130
+ # First check if the test user already exists
131
+ logger.info(f"[{test_id}] Checking if test user already exists")
132
+ check_query = "SELECT id FROM users WHERE email = ?"
133
+ check_result = execute_sql(check_query, ["[email protected]"])
134
+
135
+ if check_result and "rows" in check_result and len(check_result["rows"]) > 0:
136
+ user_id = check_result["rows"][0]["values"][0]
137
+ logger.info(f"[{test_id}] Test user already exists with ID: {user_id}")
138
+ return {
139
+ "success": True,
140
+ "user_id": user_id,
141
+ "email": "[email protected]",
142
+ "status": "already_exists"
143
+ }
144
+
145
+ # Use a pre-hashed password
146
+ logger.info(f"[{test_id}] Using pre-hashed password for test user")
147
+ # This is a pre-hashed version of "TestPassword123!" using Argon2
148
+ hashed_password = "$argon2id$v=19$m=65536,t=3,p=4$NElQRUZCWDRZSHpIWWRGSA$TYU8R7EfXGgEu9FWZGMX9AVwmMwpSKECCZMXgbzr6JE"
149
+
150
+ # Insert the test user
151
+ logger.info(f"[{test_id}] Inserting test user with email: [email protected]")
152
+ insert_query = "INSERT INTO users (email, hashed_password) VALUES (?, ?)"
153
+ insert_result = execute_sql(insert_query, ["[email protected]", hashed_password])
154
+
155
+ if insert_result:
156
+ logger.info(f"[{test_id}] Test user inserted successfully")
157
+
158
+ # Get the last inserted ID
159
+ id_query = "SELECT last_insert_rowid()"
160
+ id_result = execute_sql(id_query, [])
161
+
162
+ if id_result and "rows" in id_result and len(id_result["rows"]) > 0:
163
+ user_id = id_result["rows"][0]["values"][0]
164
+ logger.info(f"[{test_id}] Got user ID: {user_id}")
165
+ else:
166
+ logger.warning(f"[{test_id}] Could not get user ID")
167
+ user_id = None
168
+
169
+ # Verify the insert
170
+ verify_query = "SELECT id, email, created_at FROM users WHERE email = ?"
171
+ verify_result = execute_sql(verify_query, ["[email protected]"])
172
+
173
+ if verify_result and "rows" in verify_result and len(verify_result["rows"]) > 0:
174
+ user_data = verify_result["rows"][0]["values"]
175
+ user_id = user_data[0]
176
+ logger.info(f"[{test_id}] Verified test user with ID: {user_id}")
177
+ return {
178
+ "success": True,
179
+ "user_id": user_id,
180
+ "email": "[email protected]",
181
+ "created_at": user_data[2] if len(user_data) > 2 else None,
182
+ "status": "created"
183
+ }
184
+ else:
185
+ logger.error(f"[{test_id}] Failed to verify test user after insert")
186
+ return {
187
+ "success": False,
188
+ "error": "Failed to verify user after insert"
189
+ }
190
+ else:
191
+ logger.error(f"[{test_id}] Failed to insert test user")
192
+ return {
193
+ "success": False,
194
+ "error": "Failed to insert test user"
195
+ }
196
+
197
+ def list_all_users():
198
+ """List all users in the database."""
199
+ # Generate a unique test ID
200
+ test_id = f"test_{int(time.time())}"
201
+ logger.info(f"[{test_id}] Listing all users")
202
+ query = "SELECT id, email, created_at FROM users"
203
+ result = execute_sql(query, [])
204
+
205
+ if result and "rows" in result and len(result["rows"]) > 0:
206
+ users = []
207
+ for row in result["rows"]:
208
+ users.append({
209
+ "id": row["values"][0],
210
+ "email": row["values"][1],
211
+ "created_at": row["values"][2]
212
+ })
213
+ logger.info(f"[{test_id}] Found {len(users)} users")
214
+ return users
215
+ else:
216
+ logger.info(f"[{test_id}] No users found")
217
+ return []
218
+
219
+ def main():
220
+ """Main function."""
221
+ if len(sys.argv) < 2:
222
+ print("Usage: python direct_sql.py [create_test_user|list_users]")
223
+ sys.exit(1)
224
+
225
+ command = sys.argv[1]
226
+
227
+ if command == "create_test_user":
228
+ result = create_test_user()
229
+ print(json.dumps(result, indent=2))
230
+ elif command == "list_users":
231
+ users = list_all_users()
232
+ print(json.dumps(users, indent=2))
233
+ else:
234
+ print(f"Unknown command: {command}")
235
+ sys.exit(1)
236
+
237
+ if __name__ == "__main__":
238
+ main()
main.py CHANGED
@@ -837,76 +837,261 @@ async def create_test_user():
837
  dict: Information about the created test user.
838
  """
839
  import time
 
 
840
 
841
  # Generate a unique test ID
842
  test_id = f"test_{int(time.time())}"
843
  logger.info(f"[{test_id}] Starting test user creation (direct SQL)")
844
 
845
- if not hasattr(app, "db_conn"):
846
- logger.error(f"[{test_id}] Database connection not available")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
847
  return {
848
  "success": False,
849
- "error": "Database connection not available"
 
 
 
 
 
 
850
  }
851
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
852
  try:
853
- # First check if the test user already exists
854
- logger.info(f"[{test_id}] Checking if test user already exists")
855
- check_query = "SELECT id FROM users WHERE email = ?"
856
- existing_user = app.db_conn.execute(check_query, ("test@seamo.earth",)).fetchone()
 
 
 
 
857
 
858
- if existing_user:
859
- logger.info(f"[{test_id}] Test user already exists with ID: {existing_user[0]}")
860
  return {
861
- "success": True,
862
- "user_id": existing_user[0],
863
- "email": "[email protected]",
864
- "status": "already_exists"
865
  }
866
 
867
- # Use a pre-hashed password to avoid dependency on passlib
868
- logger.info(f"[{test_id}] Using pre-hashed password for test user")
869
- # This is a pre-hashed version of "TestPassword123!" using Argon2
870
- hashed_password = "$argon2id$v=19$m=65536,t=3,p=4$NElQRUZCWDRZSHpIWWRGSA$TYU8R7EfXGgEu9FWZGMX9AVwmMwpSKECCZMXgbzr6JE"
 
 
 
 
 
 
 
 
 
 
 
 
871
 
872
- # Insert the test user
873
- logger.info(f"[{test_id}] Inserting test user with email: [email protected]")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
874
  insert_query = "INSERT INTO users (email, hashed_password) VALUES (?, ?)"
875
- cursor = app.db_conn.execute(insert_query, ("[email protected]", hashed_password))
876
- app.db_conn.commit()
877
- logger.info(f"[{test_id}] Committed test user insert")
878
 
879
- # Try to get the user ID
880
- user_id = None
881
- try:
882
- user_id = cursor.lastrowid
883
- logger.info(f"[{test_id}] Got test user lastrowid: {user_id}")
884
- except Exception as e:
885
- logger.warning(f"[{test_id}] Could not get test user lastrowid: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
886
 
887
- # Verify the insert with a separate query
888
- logger.info(f"[{test_id}] Verifying test user was created")
 
 
 
 
 
 
 
 
889
  verify_query = "SELECT id, email, created_at FROM users WHERE email = ?"
890
- verify_result = app.db_conn.execute(verify_query, ("[email protected]",)).fetchone()
891
 
892
- if verify_result:
893
- user_id = verify_result[0]
894
- logger.info(f"[{test_id}] Verified test user with ID: {user_id}")
895
- return {
896
- "success": True,
897
- "user_id": user_id,
898
- "email": "[email protected]",
899
- "created_at": verify_result[2] if len(verify_result) > 2 else None,
900
- "status": "created"
901
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
902
  else:
903
- logger.error(f"[{test_id}] Failed to verify test user after insert")
904
  return {
905
  "success": False,
906
  "error": "Failed to verify user after insert"
907
  }
908
  except Exception as e:
909
- logger.error(f"[{test_id}] Error creating test user: {str(e)}")
910
  return {
911
  "success": False,
912
  "error": str(e)
 
837
  dict: Information about the created test user.
838
  """
839
  import time
840
+ import subprocess
841
+ import json
842
 
843
  # Generate a unique test ID
844
  test_id = f"test_{int(time.time())}"
845
  logger.info(f"[{test_id}] Starting test user creation (direct SQL)")
846
 
847
+ try:
848
+ # Run the direct SQL script
849
+ logger.info(f"[{test_id}] Running direct SQL script")
850
+ result = subprocess.run(
851
+ ["python", "direct_sql.py", "create_test_user"],
852
+ cwd=".",
853
+ capture_output=True,
854
+ text=True,
855
+ check=True
856
+ )
857
+
858
+ # Parse the output
859
+ try:
860
+ output = json.loads(result.stdout)
861
+ logger.info(f"[{test_id}] Direct SQL script result: {output}")
862
+ return output
863
+ except json.JSONDecodeError:
864
+ logger.error(f"[{test_id}] Failed to parse direct SQL script output: {result.stdout}")
865
+ return {
866
+ "success": False,
867
+ "error": f"Failed to parse direct SQL script output: {result.stdout}"
868
+ }
869
+ except subprocess.CalledProcessError as e:
870
+ logger.error(f"[{test_id}] Direct SQL script failed: {e.stderr}")
871
  return {
872
  "success": False,
873
+ "error": f"Direct SQL script failed: {e.stderr}"
874
+ }
875
+ except Exception as e:
876
+ logger.error(f"[{test_id}] Error creating test user: {str(e)}")
877
+ return {
878
+ "success": False,
879
+ "error": str(e)
880
  }
881
 
882
+ # Direct HTTP API endpoint for user registration
883
+ @app.post("/direct-register", tags=["Authentication"])
884
+ async def direct_register(request: Request):
885
+ """
886
+ Register a new user using direct HTTP API.
887
+ This is a workaround for issues with the libsql-experimental driver.
888
+ """
889
+ import time
890
+ import json
891
+ from pydantic import BaseModel, EmailStr
892
+
893
+ class UserCreate(BaseModel):
894
+ email: EmailStr
895
+ password: str
896
+
897
+ # Generate a unique request ID
898
+ request_id = f"direct_reg_{int(time.time())}"
899
+ logger.info(f"[{request_id}] Starting direct registration")
900
+
901
  try:
902
+ # Parse the request body
903
+ body = await request.json()
904
+ user = UserCreate(**body)
905
+ logger.info(f"[{request_id}] Registering user with email: {user.email}")
906
+
907
+ # Get Turso database connection details
908
+ db_url = os.getenv("TURSO_DATABASE_URL")
909
+ auth_token = os.getenv("TURSO_AUTH_TOKEN")
910
 
911
+ if not db_url or not auth_token:
912
+ logger.error(f"[{request_id}] Missing Turso credentials")
913
  return {
914
+ "success": False,
915
+ "error": "Missing Turso credentials"
 
 
916
  }
917
 
918
+ # Clean the auth token
919
+ auth_token = auth_token.strip()
920
+
921
+ # Convert URL from libsql:// to https://
922
+ if db_url.startswith("libsql://"):
923
+ http_url = db_url.replace("libsql://", "https://")
924
+ else:
925
+ http_url = db_url
926
+
927
+ # Ensure the URL doesn't have a trailing slash
928
+ http_url = http_url.rstrip('/')
929
+
930
+ # Verify the URL format
931
+ if not http_url.startswith("https://"):
932
+ if "://" not in http_url:
933
+ http_url = f"https://{http_url}"
934
 
935
+ logger.info(f"[{request_id}] Using HTTP URL: {http_url}")
936
+
937
+ # Check if user already exists
938
+ logger.info(f"[{request_id}] Checking if user already exists")
939
+ check_query = "SELECT id FROM users WHERE email = ?"
940
+
941
+ # Format the request for checking if user exists
942
+ check_data = {
943
+ "requests": [
944
+ {
945
+ "type": "execute",
946
+ "stmt": {
947
+ "sql": check_query,
948
+ "args": [
949
+ {"type": "text", "value": user.email}
950
+ ]
951
+ }
952
+ },
953
+ {"type": "close"}
954
+ ]
955
+ }
956
+
957
+ # Send the request
958
+ headers = {
959
+ "Authorization": f"Bearer {auth_token}",
960
+ "Content-Type": "application/json"
961
+ }
962
+
963
+ pipeline_url = f"{http_url}/v2/pipeline"
964
+ check_response = requests.post(pipeline_url, headers=headers, json=check_data, timeout=10)
965
+ check_response.raise_for_status()
966
+ check_result = check_response.json()
967
+
968
+ if "results" in check_result and len(check_result["results"]) > 0:
969
+ result = check_result["results"][0]
970
+ if "rows" in result and len(result["rows"]) > 0:
971
+ logger.warning(f"[{request_id}] User with email {user.email} already exists")
972
+ return {
973
+ "success": False,
974
+ "error": "Email already registered"
975
+ }
976
+
977
+ # Hash the password
978
+ logger.info(f"[{request_id}] Hashing password")
979
+ from passlib.context import CryptContext
980
+ pwd_context = CryptContext(schemes=["argon2"], deprecated="auto")
981
+ hashed_password = pwd_context.hash(user.password)
982
+ logger.info(f"[{request_id}] Password hashed successfully")
983
+
984
+ # Insert the user
985
+ logger.info(f"[{request_id}] Inserting user")
986
  insert_query = "INSERT INTO users (email, hashed_password) VALUES (?, ?)"
 
 
 
987
 
988
+ # Format the request for inserting the user
989
+ insert_data = {
990
+ "requests": [
991
+ {
992
+ "type": "execute",
993
+ "stmt": {
994
+ "sql": insert_query,
995
+ "args": [
996
+ {"type": "text", "value": user.email},
997
+ {"type": "text", "value": hashed_password}
998
+ ]
999
+ }
1000
+ },
1001
+ {
1002
+ "type": "execute",
1003
+ "stmt": {
1004
+ "sql": "SELECT last_insert_rowid()"
1005
+ }
1006
+ },
1007
+ {"type": "close"}
1008
+ ]
1009
+ }
1010
+
1011
+ # Send the request
1012
+ insert_response = requests.post(pipeline_url, headers=headers, json=insert_data, timeout=10)
1013
+ insert_response.raise_for_status()
1014
+ insert_result = insert_response.json()
1015
 
1016
+ # Get the user ID
1017
+ user_id = None
1018
+ if "results" in insert_result and len(insert_result["results"]) > 1:
1019
+ id_result = insert_result["results"][1]
1020
+ if "rows" in id_result and len(id_result["rows"]) > 0:
1021
+ user_id = id_result["rows"][0]["values"][0]
1022
+ logger.info(f"[{request_id}] User inserted with ID: {user_id}")
1023
+
1024
+ # Verify the insert
1025
+ logger.info(f"[{request_id}] Verifying user was created")
1026
  verify_query = "SELECT id, email, created_at FROM users WHERE email = ?"
 
1027
 
1028
+ # Format the request for verifying the user
1029
+ verify_data = {
1030
+ "requests": [
1031
+ {
1032
+ "type": "execute",
1033
+ "stmt": {
1034
+ "sql": verify_query,
1035
+ "args": [
1036
+ {"type": "text", "value": user.email}
1037
+ ]
1038
+ }
1039
+ },
1040
+ {"type": "close"}
1041
+ ]
1042
+ }
1043
+
1044
+ # Send the request
1045
+ verify_response = requests.post(pipeline_url, headers=headers, json=verify_data, timeout=10)
1046
+ verify_response.raise_for_status()
1047
+ verify_result = verify_response.json()
1048
+
1049
+ if "results" in verify_result and len(verify_result["results"]) > 0:
1050
+ result = verify_result["results"][0]
1051
+ if "rows" in result and len(result["rows"]) > 0:
1052
+ user_data = result["rows"][0]["values"]
1053
+ user_id = user_data[0]
1054
+ logger.info(f"[{request_id}] Verified user with ID: {user_id}")
1055
+
1056
+ # Generate access token
1057
+ from datetime import timedelta
1058
+ from app.api.routes.auth_router import create_access_token, create_refresh_token
1059
+
1060
+ access_token_expires = timedelta(minutes=30)
1061
+ refresh_token_expires = timedelta(days=7)
1062
+
1063
+ access_token = create_access_token(
1064
+ data={"sub": user.email},
1065
+ expires_delta=access_token_expires
1066
+ )
1067
+
1068
+ refresh_token = create_refresh_token(
1069
+ data={"sub": user.email},
1070
+ expires_delta=refresh_token_expires
1071
+ )
1072
+
1073
+ return {
1074
+ "success": True,
1075
+ "id": user_id,
1076
+ "email": user.email,
1077
+ "access_token": access_token,
1078
+ "refresh_token": refresh_token,
1079
+ "token_type": "bearer"
1080
+ }
1081
+ else:
1082
+ logger.error(f"[{request_id}] Failed to verify user after insert")
1083
+ return {
1084
+ "success": False,
1085
+ "error": "Failed to verify user after insert"
1086
+ }
1087
  else:
1088
+ logger.error(f"[{request_id}] Failed to verify user after insert")
1089
  return {
1090
  "success": False,
1091
  "error": "Failed to verify user after insert"
1092
  }
1093
  except Exception as e:
1094
+ logger.error(f"[{request_id}] Error during direct registration: {str(e)}")
1095
  return {
1096
  "success": False,
1097
  "error": str(e)