# ============================================================ # app/models/user.py - User Model # ============================================================ from datetime import datetime from typing import Optional from datetime import datetime from enum import Enum class UserRole(str, Enum): """User roles""" RENTER = "renter" LANDLORD = "landlord" ADMIN = "admin" class SubscriptionType(str, Enum): """Subscription types""" FREE = "free" PREMIUM = "premium" class User: """User model for MongoDB""" @staticmethod def create_document( first_name: str, last_name: str, email: Optional[str], phone: Optional[str], hashed_password: str, role: str, preferred_language: str = "en", ) -> dict: """Create user document for insertion""" now = datetime.utcnow() return { "firstName": first_name, "lastName": last_name, "email": email.lower() if email else None, "phone": phone, "password": hashed_password, "role": role, "subscriptionType": SubscriptionType.FREE.value, "subscriptionExpiresAt": None, "isEmailVerified": False if email else None, "isPhoneVerified": False if phone else None, "isActive": False, # Inactive until email/phone verified "totalListings": 0, "profilePicture": None, "bio": None, "location": None, "languages": [], "preferredLanguage": preferred_language, # User's preferred language for emails/notifications "isVerified": False, "rating": 0.0, # User's average rating from reviews "reviews_count": 0, # Number of reviews received "lastLogin": None, "createdAt": now, "updatedAt": now, } @staticmethod def format_response(user_doc: dict) -> dict: """Format user document for API response""" if not user_doc: return None return { "id": str(user_doc.get("_id", "")), "firstName": user_doc.get("firstName"), "lastName": user_doc.get("lastName"), "email": user_doc.get("email"), "phone": user_doc.get("phone"), "role": user_doc.get("role"), "subscriptionType": user_doc.get("subscriptionType", "free"), "subscriptionExpiresAt": user_doc.get("subscriptionExpiresAt"), "isEmailVerified": user_doc.get("isEmailVerified"), "isPhoneVerified": user_doc.get("isPhoneVerified"), "isActive": user_doc.get("isActive"), "totalListings": user_doc.get("totalListings", 0), "profilePicture": user_doc.get("profilePicture"), "bio": user_doc.get("bio"), "location": user_doc.get("location"), "languages": user_doc.get("languages", []), "preferredLanguage": user_doc.get("preferredLanguage", "en"), "isVerified": user_doc.get("isVerified", False), "rating": user_doc.get("rating", 0.0), # User's average rating "reviews_count": user_doc.get("reviews_count", 0), "lastLogin": user_doc.get("lastLogin"), "createdAt": user_doc.get("createdAt"), "updatedAt": user_doc.get("updatedAt"), } # ============================================================ # app/models/otp.py - OTP Model # ============================================================ class OTP: """OTP model for MongoDB""" OTP_PURPOSES = ["signup", "password_reset"] @staticmethod def create_document( identifier: str, code: str, purpose: str, ) -> dict: """Create OTP document for insertion""" return { "identifier": identifier, "code": code, "purpose": purpose, "isVerified": False, "attempts": 0, "createdAt": datetime.utcnow(), } @staticmethod def format_response(otp_doc: dict) -> dict: """Format OTP document for API response""" if not otp_doc: return None return { "id": str(otp_doc.get("_id", "")), "identifier": otp_doc.get("identifier"), "purpose": otp_doc.get("purpose"), "isVerified": otp_doc.get("isVerified"), "attempts": otp_doc.get("attempts"), "createdAt": otp_doc.get("createdAt"), }