fix: correct email-in-address format, remove dead code, update tests (#110)

- Fix email format in AuthService.get_email_in_address to use
  receipts+{token}@receipts.cartsnitch.com (was broken: @email.cartsnitch.com)
- Remove dead EmailInAddressResponse class and GET /auth/me/email-in-address
  endpoint from auth/routes.py (endpoint moved to routes/user.py)
- Add instructions field to EmailInAddressResponse schema
- Update routes/user.py to include instructions in the response
- Update test URLs from /auth/me/email-in-address to /api/v1/me/email-in-address

Co-authored-by: CartSnitch Engineer Bot <cartnoreply@cartsnitch.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
cartsnitch-engineer[bot]
2026-04-03 13:34:21 +00:00
committed by GitHub
parent 80004e4285
commit 6c297b5e81
5 changed files with 14 additions and 32 deletions
-25
View File
@@ -22,11 +22,6 @@ from cartsnitch_api.services.auth import AuthService
router = APIRouter(prefix="/auth", tags=["auth"])
class EmailInAddressResponse(BaseModel):
email_address: str
instructions: str
@router.get("/me", response_model=UserResponse)
async def get_me(
user_id: str = Depends(get_current_user),
@@ -70,23 +65,3 @@ async def delete_me(
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="User not found"
) from None
@router.get("/me/email-in-address", response_model=EmailInAddressResponse)
async def get_email_in_address(
user_id: str = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(User.email_inbound_token).where(User.id == user_id))
token = result.scalar_one_or_none()
if not token:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Email inbound token not found"
) from None
return EmailInAddressResponse(
email_address=f"receipts+{token}@receipts.cartsnitch.com",
instructions=(
"Forward your digital receipt emails to this address. "
"We currently support Meijer, Kroger, and Target receipt emails."
),
)
+7 -1
View File
@@ -19,7 +19,13 @@ async def get_email_in_address(
svc = AuthService(db)
try:
email_address = await svc.get_email_in_address(user_id)
return EmailInAddressResponse(email_address=email_address)
return EmailInAddressResponse(
email_address=email_address,
instructions=(
"Forward your digital receipt emails to this address. "
"We currently support Meijer, Kroger, and Target receipt emails."
),
)
except LookupError:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="User not found"
+1
View File
@@ -24,6 +24,7 @@ class UserResponse(BaseModel):
class EmailInAddressResponse(BaseModel):
email_address: str
instructions: str
# ---------- Stores ----------
+1 -1
View File
@@ -76,4 +76,4 @@ class AuthService:
if not user:
raise LookupError("User not found")
return f"{user.email_inbound_token}@email.cartsnitch.com"
return f"receipts+{user.email_inbound_token}@receipts.cartsnitch.com"
+5 -5
View File
@@ -1,4 +1,4 @@
"""Tests for GET /auth/me/email-in-address endpoint."""
"""Tests for GET /api/v1/me/email-in-address endpoint."""
import pytest
from httpx import AsyncClient
@@ -8,7 +8,7 @@ from httpx import AsyncClient
async def test_get_email_in_address_authenticated(client: AsyncClient, auth_headers: dict):
"""Authenticated user gets their email-in address."""
response = await client.get(
"/auth/me/email-in-address",
"/api/v1/me/email-in-address",
headers=auth_headers,
)
@@ -27,7 +27,7 @@ async def test_get_email_in_address_authenticated(client: AsyncClient, auth_head
@pytest.mark.asyncio
async def test_get_email_in_address_unauthenticated(client: AsyncClient):
"""Unauthenticated request returns 401."""
response = await client.get("/auth/me/email-in-address")
response = await client.get("/api/v1/me/email-in-address")
assert response.status_code == 401
@@ -35,7 +35,7 @@ async def test_get_email_in_address_unauthenticated(client: AsyncClient):
async def test_get_email_in_address_invalid_token(client: AsyncClient):
"""Invalid JWT token returns 401."""
response = await client.get(
"/auth/me/email-in-address",
"/api/v1/me/email-in-address",
headers={"Authorization": "Bearer invalid-token-xyz"},
)
assert response.status_code == 401
@@ -45,7 +45,7 @@ async def test_get_email_in_address_invalid_token(client: AsyncClient):
async def test_email_address_format(client: AsyncClient, auth_headers: dict):
"""Email address format is receipts+{22-char-urlsafe-token}@receipts.cartsnitch.com."""
response = await client.get(
"/auth/me/email-in-address",
"/api/v1/me/email-in-address",
headers=auth_headers,
)