first commit

This commit is contained in:
2026-01-17 15:21:41 -05:00
commit b93d41c1ae
36 changed files with 3391 additions and 0 deletions

191
routes/auth/current_user.py Normal file
View File

@@ -0,0 +1,191 @@
from fastapi import Depends, HTTPException, status, APIRouter
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update
import logging
from database import get_db
from models import Account_User, Customer_Customer, Customer_Description, Card
from schemas import TokenData, CustomerUpdate
from jose import JWTError, jwt
from config import load_config
logger = logging.getLogger(__name__)
# Load JWT configuration from environment
ApplicationConfig = load_config()
SECRET_KEY = ApplicationConfig.JWT_SECRET_KEY
ALGORITHM = ApplicationConfig.JWT_ALGORITHM
async def get_current_user(token: str = Depends(OAuth2PasswordBearer(tokenUrl="auth/login")), db: AsyncSession = Depends(get_db)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except JWTError:
raise credentials_exception
user = await db.execute(select(Account_User).where(Account_User.username == token_data.username))
user = user.scalar_one_or_none()
if user is None:
raise credentials_exception
return user
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/login")
router = APIRouter()
@router.get("/me")
async def read_users_me(current_user: Account_User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
# Get customer details for the current user using user_id
customer = None
if current_user.user_id:
customer_result = await db.execute(select(Customer_Customer).where(Customer_Customer.id == current_user.user_id))
customer = customer_result.scalar_one_or_none()
# Get house description if exists
house_description = None
if customer:
description_record = await db.execute(
select(Customer_Description).where(Customer_Description.customer_id == customer.id)
)
description_record = description_record.scalar_one_or_none()
if description_record:
house_description = description_record.description
# Map state code to name
state_mapping = {0: "MA", 1: "NH"} # Add more as needed
state_name = state_mapping.get(customer.customer_state, str(customer.customer_state)) if customer else None
return {
"id": current_user.id,
"username": current_user.username,
"email": current_user.email,
"account_number": current_user.account_number,
"customer_first_name": customer.customer_first_name if customer else None,
"customer_last_name": customer.customer_last_name if customer else None,
"customer_address": customer.customer_address if customer else None,
"customer_apt": customer.customer_apt if customer else None,
"customer_town": customer.customer_town if customer else None,
"customer_state": state_name,
"customer_zip": customer.customer_zip if customer else None,
"customer_phone_number": customer.customer_phone_number if customer else None,
"customer_home_type": customer.customer_home_type if customer else None,
"customer_email": customer.customer_email if customer else None,
"house_description": house_description,
"member_since": current_user.member_since,
"last_seen": current_user.last_seen
}
@router.put("/update-customer")
async def update_customer_info(
customer_data: CustomerUpdate,
current_user: Account_User = Depends(get_current_user),
db: AsyncSession = Depends(get_db)
):
if not current_user.user_id:
raise HTTPException(status_code=404, detail="Customer not found")
try:
# Update Customer_Customer table
customer_update_data = customer_data.dict(exclude_unset=True)
customer_fields = {
'customer_first_name', 'customer_last_name', 'customer_address', 'customer_apt',
'customer_town', 'customer_state', 'customer_zip', 'customer_phone_number',
'customer_home_type', 'customer_email'
}
customer_update_dict = {k: v for k, v in customer_update_data.items() if k in customer_fields}
if customer_update_dict:
await db.execute(
update(Customer_Customer)
.where(Customer_Customer.id == current_user.user_id)
.values(**customer_update_dict)
)
# Update house description if provided
if 'house_description' in customer_update_data and customer_update_data['house_description']:
# Get customer record
customer = await db.execute(
select(Customer_Customer).where(Customer_Customer.id == current_user.user_id)
)
customer = customer.scalar_one_or_none()
if customer:
# Check if description record exists
description_record = await db.execute(
select(Customer_Description).where(Customer_Description.customer_id == customer.id)
)
description_record = description_record.scalar_one_or_none()
if description_record:
# Update existing
await db.execute(
update(Customer_Description)
.where(Customer_Description.customer_id == customer.id)
.values(description=customer_update_data['house_description'])
)
else:
# Create new
new_description = Customer_Description(
customer_id=customer.id,
account_number=current_user.account_number,
company_id=customer.company_id or 1,
fill_location=0,
description=customer_update_data['house_description']
)
db.add(new_description)
await db.commit()
# Sync billing info to Authorize.net if address-related fields were updated
billing_fields = {
'customer_first_name', 'customer_last_name', 'customer_address',
'customer_town', 'customer_state', 'customer_zip', 'customer_phone_number',
'customer_email'
}
if any(k in customer_update_dict for k in billing_fields):
# Late import to avoid circular dependency
from routes.payment.routes import update_customer_profile, update_payment_profile_billing
# Refetch the updated customer
customer_result = await db.execute(
select(Customer_Customer).where(Customer_Customer.id == current_user.user_id)
)
updated_customer = customer_result.scalar_one_or_none()
if updated_customer and updated_customer.auth_net_profile_id:
# Update customer profile in Authorize.net
update_customer_profile(updated_customer.auth_net_profile_id, updated_customer)
# Update all saved payment profiles with new billing info
cards_result = await db.execute(
select(Card).where(Card.user_id == updated_customer.id)
)
cards = cards_result.scalars().all()
for card in cards:
if card.auth_net_payment_profile_id:
update_payment_profile_billing(
customer_profile_id=updated_customer.auth_net_profile_id,
payment_profile_id=card.auth_net_payment_profile_id,
customer=updated_customer,
card=card
)
logger.info(f"Synced billing info to Authorize.net for customer {updated_customer.id}")
return {"message": "Customer information updated successfully"}
except Exception as e:
await db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to update customer information: {str(e)}"
)