127 lines
4.4 KiB
Python
127 lines
4.4 KiB
Python
import logging
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlmodel import select
|
|
|
|
from inbox.models import Inbox
|
|
from job.candidate.models import CandidateHistory, Manual_UPLOAD_CANDIDATE
|
|
from job.history.serializers import serialize_history
|
|
from users.models import Users
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _text(value):
|
|
if value is None:
|
|
return None
|
|
if isinstance(value, bool):
|
|
return "true" if value else "false"
|
|
if isinstance(value, datetime):
|
|
return value.isoformat()
|
|
return str(value)
|
|
|
|
|
|
class HistoryRecorder:
|
|
def __init__(self, session: AsyncSession):
|
|
self.session = session
|
|
|
|
async def resolve_user_id(
|
|
self,
|
|
*,
|
|
user_id=None,
|
|
inbox_id=None,
|
|
manual_upload_candidate_id=None,
|
|
message_id=None,
|
|
):
|
|
uid = CandidateHistory._as_uuid(user_id)
|
|
if uid is not None:
|
|
return uid
|
|
if inbox_id is not None:
|
|
row = await Inbox.get_inbox_by_id(self.session, inbox_id)
|
|
if row and row.user_id:
|
|
return row.user_id
|
|
if manual_upload_candidate_id is not None:
|
|
row = await Manual_UPLOAD_CANDIDATE.get_by_id(self.session, manual_upload_candidate_id)
|
|
if row and row.user_id:
|
|
return row.user_id
|
|
if message_id is not None:
|
|
row = await Inbox.get_inbox_by_message_id(self.session, message_id)
|
|
if row and row.user_id:
|
|
return row.user_id
|
|
return None
|
|
|
|
def _actor_id(self, current_user=None, actor_id=None):
|
|
if actor_id is not None:
|
|
return CandidateHistory._as_uuid(actor_id)
|
|
if isinstance(current_user, dict) and current_user.get("id"):
|
|
return CandidateHistory._as_uuid(current_user.get("id"))
|
|
if current_user and not isinstance(current_user, dict):
|
|
return CandidateHistory._as_uuid(current_user)
|
|
return None
|
|
|
|
async def record(
|
|
self,
|
|
event_type,
|
|
*,
|
|
current_user=None,
|
|
actor_id=None,
|
|
user_id=None,
|
|
inbox_id=None,
|
|
manual_upload_candidate_id=None,
|
|
message_id=None,
|
|
entity_type=None,
|
|
entity_id=None,
|
|
from_value=None,
|
|
to_value=None,
|
|
description=None,
|
|
meta=None,
|
|
actor_kind=None,
|
|
commit=False,
|
|
):
|
|
try:
|
|
resolved = await self.resolve_user_id(
|
|
user_id=user_id,
|
|
inbox_id=inbox_id,
|
|
manual_upload_candidate_id=manual_upload_candidate_id,
|
|
message_id=message_id,
|
|
)
|
|
if resolved is None:
|
|
return None
|
|
fields = {
|
|
"user_id": resolved,
|
|
"inbox_id": int(inbox_id) if inbox_id is not None else None,
|
|
"manual_upload_candidate_id": CandidateHistory._as_uuid(manual_upload_candidate_id),
|
|
"event_type": event_type,
|
|
"entity_type": entity_type,
|
|
"entity_id": str(entity_id) if entity_id is not None else None,
|
|
"from_value": _text(from_value),
|
|
"to_value": _text(to_value),
|
|
"description": description,
|
|
"actor_id": self._actor_id(current_user=current_user, actor_id=actor_id),
|
|
"actor_kind": actor_kind or "user",
|
|
"meta": meta,
|
|
}
|
|
return await CandidateHistory.insert_event(self.session, fields, commit=commit)
|
|
except Exception:
|
|
logger.exception("candidate history record failed for %s", event_type)
|
|
if commit:
|
|
try:
|
|
await self.session.rollback()
|
|
except Exception:
|
|
logger.exception("candidate history rollback failed")
|
|
return None
|
|
|
|
async def list_for_user(self, user_id, *, limit=200, offset=0):
|
|
rows, total = await CandidateHistory.fetch_by_user(
|
|
self.session, user_id, limit=limit, offset=offset
|
|
)
|
|
actor_ids = {r.actor_id for r in rows if r.actor_id}
|
|
names = {}
|
|
if actor_ids:
|
|
result = await self.session.execute(
|
|
select(Users.id, Users.name).where(Users.id.in_(actor_ids))
|
|
)
|
|
names = {uid: name for uid, name in result.all()}
|
|
return [serialize_history(r, actor_name=names.get(r.actor_id)) for r in rows], total
|