mirror of
http://88.130.71.182:3000/BlitTech/badoHair_be.git
synced 2026-06-12 23:23:22 +00:00
Initial Commit
This commit is contained in:
127
app/services/auth_service.py
Normal file
127
app/services/auth_service.py
Normal file
@@ -0,0 +1,127 @@
|
||||
import asyncpg
|
||||
from supabase import create_client, Client
|
||||
|
||||
from app.config import get_settings
|
||||
from app.exceptions import AppError, UnauthorizedError
|
||||
from app.models.auth import RegisterRequest, LoginRequest, RefreshRequest
|
||||
|
||||
|
||||
def _client() -> Client:
|
||||
s = get_settings()
|
||||
return create_client(s.SUPABASE_URL, s.SUPABASE_ANON_KEY)
|
||||
|
||||
|
||||
def _admin_client() -> Client:
|
||||
s = get_settings()
|
||||
return create_client(s.SUPABASE_URL, s.SUPABASE_SERVICE_ROLE_KEY)
|
||||
|
||||
|
||||
async def register(req: RegisterRequest, db: asyncpg.Connection) -> dict:
|
||||
try:
|
||||
result = _client().auth.sign_up({"email": req.email, "password": req.password})
|
||||
except Exception as e:
|
||||
raise AppError("REGISTRATION_FAILED", str(e), 400)
|
||||
|
||||
if not result.user:
|
||||
raise AppError("REGISTRATION_FAILED", "Could not create account", 400)
|
||||
|
||||
user_id = str(result.user.id)
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO profiles (id, email, full_name, phone, role)
|
||||
VALUES ($1, $2, $3, $4, 'client')
|
||||
ON CONFLICT (id) DO NOTHING
|
||||
""",
|
||||
user_id, req.email, req.resolved_name(), req.phone,
|
||||
)
|
||||
|
||||
if result.session:
|
||||
return {
|
||||
"access_token": result.session.access_token,
|
||||
"refresh_token": result.session.refresh_token,
|
||||
"token_type": "bearer",
|
||||
"expires_in": result.session.expires_in,
|
||||
}
|
||||
|
||||
return {"message": "Account created successfully."}
|
||||
|
||||
|
||||
async def login(req: LoginRequest) -> dict:
|
||||
try:
|
||||
result = _client().auth.sign_in_with_password({"email": req.email, "password": req.password})
|
||||
except Exception:
|
||||
raise UnauthorizedError("Invalid email or password")
|
||||
|
||||
if not result.session:
|
||||
raise UnauthorizedError("Invalid email or password")
|
||||
|
||||
return {
|
||||
"access_token": result.session.access_token,
|
||||
"refresh_token": result.session.refresh_token,
|
||||
"token_type": "bearer",
|
||||
"expires_in": result.session.expires_in,
|
||||
}
|
||||
|
||||
|
||||
async def refresh(req: RefreshRequest) -> dict:
|
||||
try:
|
||||
result = _client().auth.refresh_session(req.refresh_token)
|
||||
except Exception:
|
||||
raise UnauthorizedError("Invalid or expired refresh token")
|
||||
|
||||
return {
|
||||
"access_token": result.session.access_token,
|
||||
"refresh_token": result.session.refresh_token,
|
||||
"token_type": "bearer",
|
||||
"expires_in": result.session.expires_in,
|
||||
}
|
||||
|
||||
|
||||
async def forgot_password(email: str):
|
||||
try:
|
||||
_client().auth.reset_password_email(email)
|
||||
except Exception:
|
||||
pass # Always return success to avoid email enumeration
|
||||
|
||||
|
||||
async def update_profile(user_id: str, db: asyncpg.Connection, full_name: str | None, phone: str | None) -> dict:
|
||||
updates = {}
|
||||
if full_name is not None:
|
||||
updates["full_name"] = full_name
|
||||
if phone is not None:
|
||||
updates["phone"] = phone
|
||||
|
||||
if not updates:
|
||||
row = await db.fetchrow("SELECT * FROM profiles WHERE id = $1", user_id)
|
||||
return dict(row)
|
||||
|
||||
set_clauses = [f"{k} = ${i + 2}" for i, k in enumerate(updates)]
|
||||
row = await db.fetchrow(
|
||||
f"UPDATE profiles SET {', '.join(set_clauses)}, updated_at = now() WHERE id = $1 RETURNING *",
|
||||
user_id, *updates.values(),
|
||||
)
|
||||
return dict(row)
|
||||
|
||||
|
||||
async def create_admin_user(email: str, password: str, full_name: str, db: asyncpg.Connection) -> dict:
|
||||
try:
|
||||
result = _admin_client().auth.admin.create_user({
|
||||
"email": email,
|
||||
"password": password,
|
||||
"email_confirm": True,
|
||||
})
|
||||
except Exception as e:
|
||||
raise AppError("USER_CREATE_FAILED", str(e), 400)
|
||||
|
||||
user_id = str(result.user.id)
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO profiles (id, email, full_name, role)
|
||||
VALUES ($1, $2, $3, 'admin')
|
||||
ON CONFLICT (id) DO UPDATE SET role = 'admin'
|
||||
""",
|
||||
user_id, email, full_name,
|
||||
)
|
||||
|
||||
row = await db.fetchrow("SELECT * FROM profiles WHERE id = $1", user_id)
|
||||
return dict(row)
|
||||
Reference in New Issue
Block a user