Added some comments
This commit is contained in:
parent
ed2b99e8b9
commit
cbd6ead5f3
@ -10,6 +10,8 @@ from .mixins.job import JobMixin
|
|||||||
from .mixins.skill import SkillMixin
|
from .mixins.skill import SkillMixin
|
||||||
from .mixins.ai import AIMixin
|
from .mixins.ai import AIMixin
|
||||||
|
|
||||||
|
# RedisDatabase is the main class that combines all mixins for a
|
||||||
|
# comprehensive Redis database interface.
|
||||||
class RedisDatabase(
|
class RedisDatabase(
|
||||||
AIMixin,
|
AIMixin,
|
||||||
BaseMixin,
|
BaseMixin,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -11,8 +11,11 @@ from ..constants import KEY_PREFIXES
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class UserMixin(DatabaseProtocol):
|
class UserMixin(DatabaseProtocol):
|
||||||
"""Mixin for user and candidate operations"""
|
"""Mixin for user operations"""
|
||||||
|
|
||||||
|
# ================
|
||||||
|
# Guests
|
||||||
|
# ================
|
||||||
async def set_guest(self, guest_id: str, guest_data: Dict[str, Any]) -> None:
|
async def set_guest(self, guest_id: str, guest_data: Dict[str, Any]) -> None:
|
||||||
"""Store guest data with enhanced persistence"""
|
"""Store guest data with enhanced persistence"""
|
||||||
try:
|
try:
|
||||||
@ -211,6 +214,56 @@ class UserMixin(DatabaseProtocol):
|
|||||||
logger.error(f"❌ Error getting guest statistics: {e}")
|
logger.error(f"❌ Error getting guest statistics: {e}")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
# ================
|
||||||
|
# Users
|
||||||
|
# ================
|
||||||
|
async def get_user_by_username(self, username: str) -> Optional[Dict]:
|
||||||
|
"""Get user by username specifically"""
|
||||||
|
username_key = f"{KEY_PREFIXES['users']}{username.lower()}"
|
||||||
|
data = await self.redis.get(username_key)
|
||||||
|
return self._deserialize(data) if data else None
|
||||||
|
|
||||||
|
async def get_user_rag_update_time(self, user_id: str) -> Optional[datetime]:
|
||||||
|
"""Get the last time user's RAG data was updated (returns timezone-aware UTC)"""
|
||||||
|
try:
|
||||||
|
rag_update_key = f"user:{user_id}:rag_last_update"
|
||||||
|
timestamp_str = await self.redis.get(rag_update_key)
|
||||||
|
if timestamp_str:
|
||||||
|
dt = datetime.fromisoformat(timestamp_str)
|
||||||
|
# Ensure the datetime is timezone-aware (assume UTC if naive)
|
||||||
|
if dt.tzinfo is None:
|
||||||
|
dt = dt.replace(tzinfo=timezone.utc)
|
||||||
|
else:
|
||||||
|
# Convert to UTC if it's in a different timezone
|
||||||
|
dt = dt.astimezone(timezone.utc)
|
||||||
|
return dt
|
||||||
|
logger.warning(f"⚠️ No RAG update time found for user {user_id}")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Error getting user RAG update time: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def update_user_rag_timestamp(self, user_id: str) -> bool:
|
||||||
|
"""Set the user's RAG data update time (stores as UTC ISO format)"""
|
||||||
|
try:
|
||||||
|
update_time = datetime.now(timezone.utc)
|
||||||
|
|
||||||
|
# Ensure we're storing UTC timezone-aware format
|
||||||
|
if update_time.tzinfo is None:
|
||||||
|
update_time = update_time.replace(tzinfo=timezone.utc)
|
||||||
|
else:
|
||||||
|
update_time = update_time.astimezone(timezone.utc)
|
||||||
|
|
||||||
|
rag_update_key = f"user:{user_id}:rag_last_update"
|
||||||
|
# Store as ISO format with timezone info
|
||||||
|
timestamp_str = update_time.isoformat() # This includes timezone
|
||||||
|
await self.redis.set(rag_update_key, timestamp_str)
|
||||||
|
logger.info(f"✅ User RAG update time set for user {user_id}: {timestamp_str}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Error setting user RAG update time: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
async def set_user_by_id(self, user_id: str, user_data: Dict[str, Any]) -> bool:
|
async def set_user_by_id(self, user_id: str, user_data: Dict[str, Any]) -> bool:
|
||||||
"""Store user data with ID as key for direct lookup"""
|
"""Store user data with ID as key for direct lookup"""
|
||||||
try:
|
try:
|
||||||
@ -281,7 +334,40 @@ class UserMixin(DatabaseProtocol):
|
|||||||
"""Delete user"""
|
"""Delete user"""
|
||||||
key = f"{KEY_PREFIXES['users']}{email}"
|
key = f"{KEY_PREFIXES['users']}{email}"
|
||||||
await self.redis.delete(key)
|
await self.redis.delete(key)
|
||||||
|
|
||||||
|
async def get_user(self, login: str) -> Optional[Dict[str, Any]]:
|
||||||
|
"""Get user by email or username"""
|
||||||
|
try:
|
||||||
|
login = login.strip().lower()
|
||||||
|
key = f"users:{login}"
|
||||||
|
|
||||||
|
data = await self.redis.get(key)
|
||||||
|
if data:
|
||||||
|
user_data = json.loads(data)
|
||||||
|
logger.info(f"👤 Retrieved user data for {login}")
|
||||||
|
return user_data
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Error retrieving user {login}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def set_user(self, login: str, user_data: Dict[str, Any]) -> bool:
|
||||||
|
"""Store user data by email or username"""
|
||||||
|
try:
|
||||||
|
login = login.strip().lower()
|
||||||
|
key = f"users:{login}"
|
||||||
|
|
||||||
|
await self.redis.set(key, json.dumps(user_data, default=str))
|
||||||
|
logger.info(f"👤 Stored user data for {login}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Error storing user {login}: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# ================
|
||||||
|
# Employers
|
||||||
|
# ================
|
||||||
async def get_employer(self, employer_id: str) -> Optional[Dict]:
|
async def get_employer(self, employer_id: str) -> Optional[Dict]:
|
||||||
"""Get employer by ID"""
|
"""Get employer by ID"""
|
||||||
key = f"{KEY_PREFIXES['employers']}{employer_id}"
|
key = f"{KEY_PREFIXES['employers']}{employer_id}"
|
||||||
@ -319,36 +405,9 @@ class UserMixin(DatabaseProtocol):
|
|||||||
await self.redis.delete(key)
|
await self.redis.delete(key)
|
||||||
|
|
||||||
|
|
||||||
async def get_user(self, login: str) -> Optional[Dict[str, Any]]:
|
# ================
|
||||||
"""Get user by email or username"""
|
# Candidates
|
||||||
try:
|
# ================
|
||||||
login = login.strip().lower()
|
|
||||||
key = f"users:{login}"
|
|
||||||
|
|
||||||
data = await self.redis.get(key)
|
|
||||||
if data:
|
|
||||||
user_data = json.loads(data)
|
|
||||||
logger.info(f"👤 Retrieved user data for {login}")
|
|
||||||
return user_data
|
|
||||||
return None
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"❌ Error retrieving user {login}: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
async def set_user(self, login: str, user_data: Dict[str, Any]) -> bool:
|
|
||||||
"""Store user data by email or username"""
|
|
||||||
try:
|
|
||||||
login = login.strip().lower()
|
|
||||||
key = f"users:{login}"
|
|
||||||
|
|
||||||
await self.redis.set(key, json.dumps(user_data, default=str))
|
|
||||||
logger.info(f"👤 Stored user data for {login}")
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"❌ Error storing user {login}: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Candidates operations
|
|
||||||
async def get_candidate(self, candidate_id: str) -> Optional[Dict]:
|
async def get_candidate(self, candidate_id: str) -> Optional[Dict]:
|
||||||
"""Get candidate by ID"""
|
"""Get candidate by ID"""
|
||||||
key = f"{KEY_PREFIXES['candidates']}{candidate_id}"
|
key = f"{KEY_PREFIXES['candidates']}{candidate_id}"
|
||||||
@ -723,13 +782,6 @@ class UserMixin(DatabaseProtocol):
|
|||||||
logger.error(f"❌ Critical error during batch candidate deletion: {e}")
|
logger.error(f"❌ Critical error during batch candidate deletion: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# User Operations
|
|
||||||
async def get_user_by_username(self, username: str) -> Optional[Dict]:
|
|
||||||
"""Get user by username specifically"""
|
|
||||||
username_key = f"{KEY_PREFIXES['users']}{username.lower()}"
|
|
||||||
data = await self.redis.get(username_key)
|
|
||||||
return self._deserialize(data) if data else None
|
|
||||||
|
|
||||||
async def find_candidate_by_username(self, username: str) -> Optional[Dict]:
|
async def find_candidate_by_username(self, username: str) -> Optional[Dict]:
|
||||||
"""Find candidate by username"""
|
"""Find candidate by username"""
|
||||||
all_candidates = await self.get_all_candidates()
|
all_candidates = await self.get_all_candidates()
|
||||||
@ -741,7 +793,6 @@ class UserMixin(DatabaseProtocol):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Batch Operations
|
|
||||||
async def get_multiple_candidates_by_usernames(self, usernames: List[str]) -> Dict[str, Dict]:
|
async def get_multiple_candidates_by_usernames(self, usernames: List[str]) -> Dict[str, Dict]:
|
||||||
"""Get multiple candidates by their usernames efficiently"""
|
"""Get multiple candidates by their usernames efficiently"""
|
||||||
all_candidates = await self.get_all_candidates()
|
all_candidates = await self.get_all_candidates()
|
||||||
@ -787,6 +838,9 @@ class UserMixin(DatabaseProtocol):
|
|||||||
"recent_sessions": sessions[:5] # Last 5 sessions
|
"recent_sessions": sessions[:5] # Last 5 sessions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ================
|
||||||
|
# Viewers
|
||||||
|
# ================
|
||||||
async def get_viewer(self, viewer_id: str) -> Optional[Dict]:
|
async def get_viewer(self, viewer_id: str) -> Optional[Dict]:
|
||||||
"""Get viewer by ID"""
|
"""Get viewer by ID"""
|
||||||
key = f"{KEY_PREFIXES['viewers']}{viewer_id}"
|
key = f"{KEY_PREFIXES['viewers']}{viewer_id}"
|
||||||
@ -824,44 +878,3 @@ class UserMixin(DatabaseProtocol):
|
|||||||
key = f"{KEY_PREFIXES['viewers']}{viewer_id}"
|
key = f"{KEY_PREFIXES['viewers']}{viewer_id}"
|
||||||
await self.redis.delete(key)
|
await self.redis.delete(key)
|
||||||
|
|
||||||
async def get_user_rag_update_time(self, user_id: str) -> Optional[datetime]:
|
|
||||||
"""Get the last time user's RAG data was updated (returns timezone-aware UTC)"""
|
|
||||||
try:
|
|
||||||
rag_update_key = f"user:{user_id}:rag_last_update"
|
|
||||||
timestamp_str = await self.redis.get(rag_update_key)
|
|
||||||
if timestamp_str:
|
|
||||||
dt = datetime.fromisoformat(timestamp_str)
|
|
||||||
# Ensure the datetime is timezone-aware (assume UTC if naive)
|
|
||||||
if dt.tzinfo is None:
|
|
||||||
dt = dt.replace(tzinfo=timezone.utc)
|
|
||||||
else:
|
|
||||||
# Convert to UTC if it's in a different timezone
|
|
||||||
dt = dt.astimezone(timezone.utc)
|
|
||||||
return dt
|
|
||||||
logger.warning(f"⚠️ No RAG update time found for user {user_id}")
|
|
||||||
return None
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"❌ Error getting user RAG update time: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
async def update_user_rag_timestamp(self, user_id: str) -> bool:
|
|
||||||
"""Set the user's RAG data update time (stores as UTC ISO format)"""
|
|
||||||
try:
|
|
||||||
update_time = datetime.now(timezone.utc)
|
|
||||||
|
|
||||||
# Ensure we're storing UTC timezone-aware format
|
|
||||||
if update_time.tzinfo is None:
|
|
||||||
update_time = update_time.replace(tzinfo=timezone.utc)
|
|
||||||
else:
|
|
||||||
update_time = update_time.astimezone(timezone.utc)
|
|
||||||
|
|
||||||
rag_update_key = f"user:{user_id}:rag_last_update"
|
|
||||||
# Store as ISO format with timezone info
|
|
||||||
timestamp_str = update_time.isoformat() # This includes timezone
|
|
||||||
await self.redis.set(rag_update_key, timestamp_str)
|
|
||||||
logger.info(f"✅ User RAG update time set for user {user_id}: {timestamp_str}")
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"❌ Error setting user RAG update time: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user