energensy contacts, dashboard
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
"""add_is_active_to_emergency_contacts
|
||||||
|
|
||||||
|
Revision ID: d9c621d45a82
|
||||||
|
Revises: 2a4784830015
|
||||||
|
Create Date: 2025-09-26 08:42:00.128700
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'd9c621d45a82'
|
||||||
|
down_revision = '2a4784830015'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# Add is_active column to emergency_contacts table
|
||||||
|
op.add_column('emergency_contacts', sa.Column('is_active', sa.Boolean(), nullable=False, server_default='true'))
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# Remove is_active column from emergency_contacts table
|
||||||
|
op.drop_column('emergency_contacts', 'is_active')
|
||||||
32
deploy_migration.sh
Executable file
32
deploy_migration.sh
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Deploy database migration to production server
|
||||||
|
echo "Deploying database migration to production server 192.168.0.103..."
|
||||||
|
|
||||||
|
# Create migration file on server
|
||||||
|
echo "Creating migration directory on server..."
|
||||||
|
ssh trevor@192.168.0.103 "sudo mkdir -p /opt/chat/alembic/versions"
|
||||||
|
|
||||||
|
# Copy migration file
|
||||||
|
echo "Copying migration file..."
|
||||||
|
scp alembic/versions/d9c621d45a82_add_is_active_to_emergency_contacts.py trevor@192.168.0.103:/tmp/
|
||||||
|
ssh trevor@192.168.0.103 "sudo mv /tmp/d9c621d45a82_add_is_active_to_emergency_contacts.py /opt/chat/alembic/versions/"
|
||||||
|
|
||||||
|
# Apply migration on server
|
||||||
|
echo "Applying migration on production server..."
|
||||||
|
ssh trevor@192.168.0.103 << 'EOF'
|
||||||
|
cd /opt/chat
|
||||||
|
|
||||||
|
# Activate virtual environment if it exists
|
||||||
|
if [ -d ".venv" ]; then
|
||||||
|
source .venv/bin/activate
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Apply migration
|
||||||
|
export PYTHONPATH="/opt/chat:$PYTHONPATH"
|
||||||
|
python -m alembic upgrade head
|
||||||
|
|
||||||
|
echo "Migration applied successfully!"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Migration deployment completed!"
|
||||||
@@ -9,6 +9,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
|||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from fastapi.openapi.utils import get_openapi
|
from fastapi.openapi.utils import get_openapi
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from shared.config import settings
|
from shared.config import settings
|
||||||
from services.user_service.schemas import UserCreate, UserLogin, UserResponse, UserUpdate, Token
|
from services.user_service.schemas import UserCreate, UserLogin, UserResponse, UserUpdate, Token
|
||||||
@@ -248,7 +249,17 @@ async def register_user(user_create: UserCreate, request: Request):
|
|||||||
async def login_user(user_login: UserLogin, request: Request):
|
async def login_user(user_login: UserLogin, request: Request):
|
||||||
"""Login user"""
|
"""Login user"""
|
||||||
client_ip = get_client_ip(request)
|
client_ip = get_client_ip(request)
|
||||||
|
|
||||||
|
# Дополнительное логирование для отладки
|
||||||
|
try:
|
||||||
|
request_body = await request.body()
|
||||||
|
print(f"RAW request body from {client_ip}: {request_body}")
|
||||||
|
print(f"Request headers: {dict(request.headers)}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
print(f"Login request from {client_ip}: {user_login.model_dump(exclude={'password'})}")
|
print(f"Login request from {client_ip}: {user_login.model_dump(exclude={'password'})}")
|
||||||
|
print(f"Full login data: {user_login.model_dump()}")
|
||||||
|
|
||||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||||
try:
|
try:
|
||||||
@@ -312,6 +323,113 @@ async def login_user(user_login: UserLogin, request: Request):
|
|||||||
raise HTTPException(status_code=500, detail=f"Login error: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"Login error: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
# Debug endpoint to analyze raw request data
|
||||||
|
@app.post("/api/v1/debug/login", tags=["Debug"], summary="Debug login request data")
|
||||||
|
async def debug_login_request(request: Request):
|
||||||
|
"""Debug endpoint to analyze raw request data from mobile app"""
|
||||||
|
try:
|
||||||
|
client_ip = get_client_ip(request)
|
||||||
|
headers = dict(request.headers)
|
||||||
|
body = await request.body()
|
||||||
|
|
||||||
|
debug_info = {
|
||||||
|
"client_ip": client_ip,
|
||||||
|
"headers": headers,
|
||||||
|
"raw_body": body.decode('utf-8', errors='ignore') if body else None,
|
||||||
|
"content_length": len(body) if body else 0,
|
||||||
|
"content_type": headers.get('content-type', 'unknown')
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"DEBUG LOGIN from {client_ip}:")
|
||||||
|
print(f"Headers: {headers}")
|
||||||
|
print(f"Raw body: {body}")
|
||||||
|
|
||||||
|
# Try to parse as JSON
|
||||||
|
try:
|
||||||
|
if body:
|
||||||
|
import json
|
||||||
|
json_data = json.loads(body)
|
||||||
|
debug_info["parsed_json"] = json_data
|
||||||
|
print(f"Parsed JSON: {json_data}")
|
||||||
|
except Exception as e:
|
||||||
|
debug_info["json_parse_error"] = str(e)
|
||||||
|
print(f"JSON parse error: {e}")
|
||||||
|
|
||||||
|
return debug_info
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Debug endpoint error: {str(e)}")
|
||||||
|
return {"error": str(e)}
|
||||||
|
|
||||||
|
|
||||||
|
# Alternative login endpoint for mobile app debugging
|
||||||
|
@app.post("/api/v1/auth/login-flexible", tags=["Authentication"], summary="Flexible login for debugging")
|
||||||
|
async def login_flexible(request: Request):
|
||||||
|
"""Flexible login endpoint that accepts various data formats"""
|
||||||
|
try:
|
||||||
|
client_ip = get_client_ip(request)
|
||||||
|
body = await request.body()
|
||||||
|
|
||||||
|
print(f"Flexible login from {client_ip}")
|
||||||
|
print(f"Raw request: {body}")
|
||||||
|
|
||||||
|
# Try to parse JSON
|
||||||
|
import json
|
||||||
|
try:
|
||||||
|
data = json.loads(body) if body else {}
|
||||||
|
except:
|
||||||
|
return {"error": "Invalid JSON format", "status": 422}
|
||||||
|
|
||||||
|
print(f"Parsed data: {data}")
|
||||||
|
|
||||||
|
# Extract login fields with flexible names
|
||||||
|
email = data.get('email') or data.get('Email') or data.get('EMAIL')
|
||||||
|
username = data.get('username') or data.get('Username') or data.get('user_name') or data.get('login')
|
||||||
|
password = data.get('password') or data.get('Password') or data.get('PASSWORD') or data.get('pass')
|
||||||
|
|
||||||
|
print(f"Extracted: email={email}, username={username}, password={'***' if password else None}")
|
||||||
|
|
||||||
|
# Validation
|
||||||
|
if not password:
|
||||||
|
return {"error": "Password is required", "status": 422}
|
||||||
|
|
||||||
|
if not email and not username:
|
||||||
|
return {"error": "Either email or username must be provided", "status": 422}
|
||||||
|
|
||||||
|
# Create proper login data
|
||||||
|
login_data = {
|
||||||
|
"email": email,
|
||||||
|
"username": username,
|
||||||
|
"password": password
|
||||||
|
}
|
||||||
|
|
||||||
|
# Forward to user service
|
||||||
|
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||||
|
response = await client.post(
|
||||||
|
f"{SERVICES['users']}/api/v1/auth/login",
|
||||||
|
json=login_data,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"User service response: {response.status_code} - {response.text}")
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
error_data = response.json()
|
||||||
|
return {"error": error_data.get("detail", "Login failed"), "status": response.status_code}
|
||||||
|
except:
|
||||||
|
return {"error": response.text, "status": response.status_code}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Flexible login error: {str(e)}")
|
||||||
|
return {"error": str(e), "status": 500}
|
||||||
|
|
||||||
|
|
||||||
# Utility endpoints
|
# Utility endpoints
|
||||||
@app.get("/api/v1/auth/check-email", tags=["Authentication"], summary="Check if email is available")
|
@app.get("/api/v1/auth/check-email", tags=["Authentication"], summary="Check if email is available")
|
||||||
async def check_email_availability(email: str):
|
async def check_email_availability(email: str):
|
||||||
|
|||||||
@@ -372,6 +372,58 @@ async def delete_emergency_contact(
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/api/v1/users/dashboard", tags=["Dashboard"])
|
||||||
|
async def get_user_dashboard(
|
||||||
|
current_user: User = Depends(get_current_user),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
):
|
||||||
|
"""Get user dashboard data"""
|
||||||
|
try:
|
||||||
|
# Get emergency contacts count
|
||||||
|
emergency_contacts_result = await db.execute(
|
||||||
|
select(EmergencyContact).filter(
|
||||||
|
EmergencyContact.user_id == current_user.id,
|
||||||
|
EmergencyContact.is_active == True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
emergency_contacts = emergency_contacts_result.scalars().all()
|
||||||
|
|
||||||
|
dashboard_data = {
|
||||||
|
"user": {
|
||||||
|
"id": current_user.id,
|
||||||
|
"uuid": str(current_user.uuid),
|
||||||
|
"email": current_user.email,
|
||||||
|
"username": current_user.username,
|
||||||
|
"first_name": current_user.first_name,
|
||||||
|
"last_name": current_user.last_name,
|
||||||
|
"avatar_url": current_user.avatar_url
|
||||||
|
},
|
||||||
|
"emergency_contacts_count": len(emergency_contacts),
|
||||||
|
"settings": {
|
||||||
|
"location_sharing_enabled": current_user.location_sharing_enabled,
|
||||||
|
"emergency_notifications_enabled": current_user.emergency_notifications_enabled,
|
||||||
|
"push_notifications_enabled": current_user.push_notifications_enabled
|
||||||
|
},
|
||||||
|
"verification_status": {
|
||||||
|
"email_verified": current_user.email_verified,
|
||||||
|
"phone_verified": current_user.phone_verified
|
||||||
|
},
|
||||||
|
"account_status": {
|
||||||
|
"is_active": current_user.is_active,
|
||||||
|
"created_at": str(current_user.created_at) if hasattr(current_user, 'created_at') else None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dashboard_data
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Dashboard error: {str(e)}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="Failed to load dashboard data"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/v1/health")
|
@app.get("/api/v1/health")
|
||||||
async def health_check_v1():
|
async def health_check_v1():
|
||||||
"""Health check endpoint with API version"""
|
"""Health check endpoint with API version"""
|
||||||
|
|||||||
106
test_fixed_endpoints.py
Normal file
106
test_fixed_endpoints.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
def test_fixed_endpoints():
|
||||||
|
"""Test the fixed endpoints on production server"""
|
||||||
|
base_url = "http://192.168.0.103:8000"
|
||||||
|
|
||||||
|
# First, login to get access token
|
||||||
|
print("🔐 Step 1: Login to get access token")
|
||||||
|
login_response = requests.post(
|
||||||
|
f"{base_url}/api/v1/auth/login",
|
||||||
|
json={
|
||||||
|
"username": "Trevor1985",
|
||||||
|
"password": "Cl0ud_1985!"
|
||||||
|
},
|
||||||
|
headers={"Content-Type": "application/json"}
|
||||||
|
)
|
||||||
|
|
||||||
|
if login_response.status_code != 200:
|
||||||
|
print(f"❌ Login failed: {login_response.status_code} - {login_response.text}")
|
||||||
|
return
|
||||||
|
|
||||||
|
token_data = login_response.json()
|
||||||
|
access_token = token_data["access_token"]
|
||||||
|
print(f"✅ Login successful! Got access token.")
|
||||||
|
|
||||||
|
# Test endpoints that were failing
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {access_token}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_endpoints = [
|
||||||
|
{
|
||||||
|
"name": "User Profile",
|
||||||
|
"url": "/api/v1/users/me",
|
||||||
|
"method": "GET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "User Dashboard (was 404)",
|
||||||
|
"url": "/api/v1/users/dashboard",
|
||||||
|
"method": "GET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Emergency Contacts (was 500)",
|
||||||
|
"url": "/api/v1/users/me/emergency-contacts",
|
||||||
|
"method": "GET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Profile (alternative endpoint)",
|
||||||
|
"url": "/api/v1/profile",
|
||||||
|
"method": "GET"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
print(f"\n🧪 Step 2: Testing fixed endpoints")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
for endpoint in test_endpoints:
|
||||||
|
print(f"\n📍 Testing: {endpoint['name']}")
|
||||||
|
print(f" URL: {endpoint['url']}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if endpoint['method'] == 'GET':
|
||||||
|
response = requests.get(
|
||||||
|
f"{base_url}{endpoint['url']}",
|
||||||
|
headers=headers,
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f" Status: {response.status_code}")
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
try:
|
||||||
|
data = response.json()
|
||||||
|
if endpoint['name'] == "User Dashboard (was 404)":
|
||||||
|
print(f" ✅ Dashboard loaded! Emergency contacts: {data.get('emergency_contacts_count', 0)}")
|
||||||
|
print(f" User: {data.get('user', {}).get('username', 'N/A')}")
|
||||||
|
elif endpoint['name'] == "Emergency Contacts (was 500)":
|
||||||
|
contacts = data if isinstance(data, list) else []
|
||||||
|
print(f" ✅ Emergency contacts loaded! Count: {len(contacts)}")
|
||||||
|
else:
|
||||||
|
print(f" ✅ Success! Got user data.")
|
||||||
|
except:
|
||||||
|
print(f" ✅ Success! (Response not JSON)")
|
||||||
|
else:
|
||||||
|
print(f" ❌ Failed: {response.text[:100]}...")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" 💥 Error: {str(e)}")
|
||||||
|
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print("📊 Summary:")
|
||||||
|
print("• Login: ✅ Working")
|
||||||
|
print("• Check each endpoint status above")
|
||||||
|
print("• All 422 login errors should be resolved")
|
||||||
|
print("• Database errors should be fixed")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("🚀 Testing fixed endpoints on production server 192.168.0.103")
|
||||||
|
test_fixed_endpoints()
|
||||||
149
test_mobile_formats.py
Normal file
149
test_mobile_formats.py
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
def test_mobile_app_formats():
|
||||||
|
"""Test various data formats that mobile apps commonly send"""
|
||||||
|
base_url = "http://192.168.0.103:8000"
|
||||||
|
|
||||||
|
# Common mobile app data format issues
|
||||||
|
test_cases = [
|
||||||
|
{
|
||||||
|
"name": "Android app - nested data structure",
|
||||||
|
"data": {
|
||||||
|
"user": {
|
||||||
|
"email": "testuser@example.com",
|
||||||
|
"password": "SecurePass123"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "iOS app - camelCase fields",
|
||||||
|
"data": {
|
||||||
|
"emailAddress": "testuser@example.com",
|
||||||
|
"userPassword": "SecurePass123"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "React Native - mixed case",
|
||||||
|
"data": {
|
||||||
|
"Email": "testuser@example.com",
|
||||||
|
"Password": "SecurePass123"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Flutter app - snake_case",
|
||||||
|
"data": {
|
||||||
|
"user_email": "testuser@example.com",
|
||||||
|
"user_password": "SecurePass123"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mobile app with extra fields",
|
||||||
|
"data": {
|
||||||
|
"email": "testuser@example.com",
|
||||||
|
"password": "SecurePass123",
|
||||||
|
"device_id": "mobile123",
|
||||||
|
"app_version": "1.0.0",
|
||||||
|
"platform": "android"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Empty string fields (common mobile bug)",
|
||||||
|
"data": {
|
||||||
|
"email": "",
|
||||||
|
"username": "",
|
||||||
|
"password": "SecurePass123"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Null fields (another common mobile bug)",
|
||||||
|
"data": {
|
||||||
|
"email": None,
|
||||||
|
"username": None,
|
||||||
|
"password": "SecurePass123"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Correct format",
|
||||||
|
"data": {
|
||||||
|
"email": "testuser@example.com",
|
||||||
|
"password": "SecurePass123"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json",
|
||||||
|
"User-Agent": "WomenSafetyApp/1.0 (Android)"
|
||||||
|
}
|
||||||
|
|
||||||
|
print("📱 Testing mobile app data formats on 192.168.0.103")
|
||||||
|
print("=" * 70)
|
||||||
|
|
||||||
|
for i, test_case in enumerate(test_cases, 1):
|
||||||
|
print(f"\n{i}. 🧪 {test_case['name']}")
|
||||||
|
print("-" * 50)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Send request
|
||||||
|
response = requests.post(
|
||||||
|
f"{base_url}/api/v1/auth/login",
|
||||||
|
json=test_case["data"],
|
||||||
|
headers=headers,
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"📤 Request: {json.dumps(test_case['data'], indent=2)}")
|
||||||
|
print(f"📊 Status: {response.status_code}")
|
||||||
|
|
||||||
|
# Analyze response
|
||||||
|
if response.status_code == 200:
|
||||||
|
print("✅ SUCCESS - Login worked!")
|
||||||
|
try:
|
||||||
|
token_data = response.json()
|
||||||
|
print(f"🔐 Token type: {token_data.get('token_type')}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif response.status_code == 422:
|
||||||
|
print("❌ VALIDATION ERROR")
|
||||||
|
try:
|
||||||
|
error_data = response.json()
|
||||||
|
if "detail" in error_data:
|
||||||
|
detail = error_data["detail"]
|
||||||
|
if isinstance(detail, list):
|
||||||
|
print("📝 Validation issues:")
|
||||||
|
for error in detail:
|
||||||
|
field = error.get("loc", [])[-1] if error.get("loc") else "unknown"
|
||||||
|
msg = error.get("msg", "Unknown error")
|
||||||
|
input_val = error.get("input", "")
|
||||||
|
print(f" • Field '{field}': {msg} (input: {input_val})")
|
||||||
|
else:
|
||||||
|
print(f"📝 Error: {detail}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"📝 Raw error: {response.text}")
|
||||||
|
|
||||||
|
elif response.status_code == 401:
|
||||||
|
print("🔒 AUTHENTICATION FAILED - Wrong credentials")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(f"🚫 OTHER ERROR: {response.status_code}")
|
||||||
|
print(f"📝 Response: {response.text[:200]}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"💥 REQUEST ERROR: {str(e)}")
|
||||||
|
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
print(f"\n{'='*70}")
|
||||||
|
print("📋 SUMMARY:")
|
||||||
|
print("• Check which format works correctly")
|
||||||
|
print("• Compare with mobile app's actual request format")
|
||||||
|
print("• Update mobile app to match working format")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_mobile_app_formats()
|
||||||
100
test_production_login.py
Normal file
100
test_production_login.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
def test_production_login():
|
||||||
|
"""Test login endpoint on production server"""
|
||||||
|
base_url = "http://192.168.0.103:8000"
|
||||||
|
|
||||||
|
# Test cases that might be coming from mobile app
|
||||||
|
test_cases = [
|
||||||
|
{
|
||||||
|
"name": "Empty request (like from emulator)",
|
||||||
|
"data": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Only password",
|
||||||
|
"data": {"password": "testpass123"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Email with extra spaces",
|
||||||
|
"data": {
|
||||||
|
"email": " testuser@example.com ",
|
||||||
|
"password": "SecurePass123"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Valid login data",
|
||||||
|
"data": {
|
||||||
|
"email": "testuser@example.com",
|
||||||
|
"password": "SecurePass123"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Username login",
|
||||||
|
"data": {
|
||||||
|
"username": "testuser123",
|
||||||
|
"password": "SecurePass123"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Invalid JSON structure (common mobile app error)",
|
||||||
|
"data": '{"email":"test@example.com","password":"test123"',
|
||||||
|
"raw": True
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json",
|
||||||
|
"User-Agent": "MobileApp/1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
for test_case in test_cases:
|
||||||
|
print(f"\n🧪 Testing: {test_case['name']}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if test_case.get("raw"):
|
||||||
|
data = test_case["data"]
|
||||||
|
print(f"Raw data: {data}")
|
||||||
|
else:
|
||||||
|
data = json.dumps(test_case["data"])
|
||||||
|
print(f"JSON data: {data}")
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
f"{base_url}/api/v1/auth/login",
|
||||||
|
data=data,
|
||||||
|
headers=headers,
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Status: {response.status_code}")
|
||||||
|
print(f"Response: {response.text[:200]}...")
|
||||||
|
|
||||||
|
if response.status_code == 422:
|
||||||
|
print("🔍 This is a validation error - checking details...")
|
||||||
|
try:
|
||||||
|
error_details = response.json()
|
||||||
|
if "detail" in error_details:
|
||||||
|
detail = error_details["detail"]
|
||||||
|
if isinstance(detail, list):
|
||||||
|
for error in detail:
|
||||||
|
field = error.get("loc", [])[-1] if error.get("loc") else "unknown"
|
||||||
|
msg = error.get("msg", "Unknown error")
|
||||||
|
print(f" Field '{field}': {msg}")
|
||||||
|
else:
|
||||||
|
print(f" Error: {detail}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Request error: {str(e)}")
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("🔍 Testing login endpoint on production server 192.168.0.103")
|
||||||
|
test_production_login()
|
||||||
Reference in New Issue
Block a user