Skip to content

Commit 9b24604

Browse files
committed
Add DB alter endpoint, reorganize prospects and tests
Add a new /prospects/alter endpoint to run a DB schema change (drops tertiary_email_verification_source if present). Reorganize prospect-related files into app/api/prospects/database (rename CSVs and modules) and register the new router in routes.py. Add a placeholder /prospects/init endpoint and update prospects module formatting. Add tests for prospects endpoints and health, and adjust favicon file mode.
1 parent d11958d commit 9b24604

11 files changed

Lines changed: 151 additions & 5 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from fastapi import APIRouter, status
2+
from app.utils.db import get_db_connection
3+
4+
router = APIRouter()
5+
6+
@router.get("/prospects/alter", status_code=status.HTTP_200_OK)
7+
def alter_prospects_table() -> dict:
8+
"""
9+
Checks if the 'prospects' table exists, then checks if the 'secondary_email' column exists.
10+
If both exist, attempts to drop the 'secondary_email' column and returns the result.
11+
"""
12+
import psycopg2
13+
column_name = 'tertiary_email_verification_source' # Change this variable to alter a different column
14+
conn_gen = get_db_connection()
15+
conn = next(conn_gen)
16+
cur = conn.cursor()
17+
try:
18+
# Check if 'prospects' table exists
19+
cur.execute("""
20+
SELECT EXISTS (
21+
SELECT 1 FROM information_schema.tables
22+
WHERE table_name = 'prospects'
23+
);
24+
""")
25+
table_row = cur.fetchone()
26+
if table_row is None:
27+
result = {"detail": "Error: Could not fetch table existence result."}
28+
return result
29+
table_exists = table_row[0]
30+
if not table_exists:
31+
result = {"detail": "Table 'prospects' does not exist."}
32+
return result
33+
34+
# Check if the column exists
35+
cur.execute(f"""
36+
SELECT EXISTS (
37+
SELECT 1 FROM information_schema.columns
38+
WHERE table_name = 'prospects' AND column_name = %s
39+
);
40+
""", (column_name,))
41+
column_row = cur.fetchone()
42+
if column_row is None:
43+
result = {"detail": "Error: Could not fetch column existence result."}
44+
return result
45+
column_exists = column_row[0]
46+
if not column_exists:
47+
result = {"detail": f"Column '{column_name}' does not exist in 'prospects' table."}
48+
return result
49+
50+
# Try to drop the column
51+
try:
52+
cur.execute(f'ALTER TABLE prospects DROP COLUMN {column_name};')
53+
conn.commit()
54+
result = {"detail": f"Column '{column_name}' dropped successfully from 'prospects' table."}
55+
except Exception as e:
56+
conn.rollback()
57+
result = {"detail": f"Failed to drop column: {str(e)}"}
58+
except Exception as e:
59+
conn.rollback()
60+
result = {"detail": f"Error: {str(e)}"}
61+
finally:
62+
cur.close()
63+
conn.close()
64+
return result

app/api/prospects/prospects.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def get_unique_fields(fields: list[str] = Query(..., description="List of field
3434
cur.close()
3535
conn.close()
3636

37+
3738
@router.get("/prospects")
3839
def root() -> dict:
3940
"""Return all prospects table records"""
@@ -72,3 +73,12 @@ def root() -> dict:
7273
cur.close()
7374
conn.close()
7475
return result
76+
77+
78+
# New endpoint: /prospects/init
79+
@router.get("/prospects/init")
80+
def prospects_init() -> dict:
81+
"""Initialize prospects (placeholder endpoint)"""
82+
meta = make_meta("success", "Initialized prospects (placeholder)")
83+
data = {"message": "This is a placeholder for prospects/init."}
84+
return {"meta": meta, "data": data}

app/api/routes.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@
1313
from app.api.root import router as root_router
1414
from app.api.health import router as health_router
1515

16-
from app.api.prospects.prospects import router as prospects_router
17-
1816

19-
from app.api.prospects.seed import router as prospects_seed_router
20-
from app.api.prospects.empty import router as prospects_empty_router
21-
from app.api.prospects.process import router as prospects_process_router
17+
from app.api.prospects.prospects import router as prospects_router
18+
from app.api.prospects.database.alter import router as prospects_alter_router
19+
from app.api.prospects.database.seed import router as prospects_seed_router
20+
from app.api.prospects.database.empty import router as prospects_empty_router
21+
from app.api.prospects.database.process import router as prospects_process_router
2222

2323
router.include_router(root_router)
2424
router.include_router(health_router)
2525
router.include_router(prospects_router)
26+
router.include_router(prospects_alter_router)
2627
router.include_router(prospects_seed_router)
2728
router.include_router(prospects_empty_router)
2829
router.include_router(prospects_process_router)

app/static/favicon.ico

100755100644
0 Bytes
Binary file not shown.

tests/prospects/test_prospects.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import sys
2+
import os
3+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../")))
4+
import pytest
5+
from fastapi.testclient import TestClient
6+
from app.main import app
7+
8+
client = TestClient(app)
9+
10+
def test_prospects_init_returns_placeholder():
11+
response = client.get("/prospects/init")
12+
assert response.status_code == 200
13+
data = response.json()
14+
assert "meta" in data
15+
assert "data" in data
16+
assert data["data"]["message"] == "This is a placeholder for prospects/init."
17+
18+
def test_prospects_returns_list():
19+
response = client.get("/prospects")
20+
assert response.status_code == 200
21+
data = response.json()
22+
assert "meta" in data
23+
assert "data" in data
24+
assert isinstance(data["data"], list) or isinstance(data["data"], dict)
25+
26+
def test_prospects_unique_valid_fields():
27+
# This test assumes at least one valid field exists in the prospects table, e.g., 'id'.
28+
response = client.get("/prospects/unique?fields=id")
29+
assert response.status_code == 200
30+
data = response.json()
31+
assert "meta" in data
32+
assert "data" in data
33+
assert isinstance(data["data"], dict)
34+
35+
def test_prospects_unique_invalid_field():
36+
response = client.get("/prospects/unique?fields=notafield")
37+
assert response.status_code == 200
38+
data = response.json()
39+
assert "meta" in data
40+
assert "errors" in data
41+
assert "notafield" in data["errors"]
42+
43+
def test_prospects_init_meta_keys():
44+
response = client.get("/prospects/init")
45+
meta = response.json()["meta"]
46+
for key in ["severity", "title", "version", "base_url", "time"]:
47+
assert key in meta

0 commit comments

Comments
 (0)