Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 79 additions & 25 deletions apps/discord_bot/src/five08/discord_bot/cogs/crm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,78 @@ def _format_applied_updates_value(cls, applied_lines: list[str]) -> str:
joined = "\n".join(kept)
return cls._truncate_embed_field(joined, cls._APPLIED_FIELD_TOTAL_LIMIT)

@staticmethod
def _format_discord_link_value(
*,
link_discord: dict[str, str] | None = None,
link_member: discord.Member | None = None,
) -> str | None:
user_id = ""
username = ""

if link_member is not None:
user_id = str(link_member.id)
username = str(link_member).strip()
elif link_discord:
user_id = str(link_discord.get("user_id") or "").strip()
username = str(link_discord.get("username") or "").strip()

if not user_id.isdigit():
return None

mention = f"<@{user_id}>"
safe_username = discord.utils.escape_markdown(
discord.utils.escape_mentions(username)
)
return f"{mention} ({safe_username})" if username else mention

def _build_apply_success_embed(
self,
*,
updated_fields: list[str],
updated_values: dict[str, Any],
link_discord_applied: bool | None,
) -> discord.Embed:
embed = discord.Embed(
title="✅ CRM Updated",
description=f"Applied updates for **{self.contact_name}**.",
color=0x00FF00,
)
display_fields = self._collapse_updated_fields(updated_fields)
labeled_fields = [self._field_label(field) for field in display_fields]
updated_fields_value = self._format_updated_fields_value(labeled_fields)
embed.add_field(
name="Updated Fields",
value=updated_fields_value,
inline=False,
)
applied_lines = self._build_applied_updates_lines(
updated_fields=updated_fields,
updated_values=updated_values,
)
if applied_lines:
applied_updates_value = self._format_applied_updates_value(applied_lines)
embed.add_field(
name="Applied Updates",
value=applied_updates_value,
inline=False,
)

if link_discord_applied:
discord_link_value = self._format_discord_link_value(
link_discord=self.link_discord
)
if discord_link_value:
embed.add_field(
name="Discord Link",
value=f"Linked contact to {discord_link_value}",
inline=False,
)

profile_url = f"{self.crm_cog.base_url}/#Contact/view/{self.contact_id}"
embed.add_field(name="🔗 CRM Profile", value=f"[View in CRM]({profile_url})")
return embed

@classmethod
def _collapse_updated_fields(cls, updated_fields: list[str]) -> list[str]:
"""Collapse skill fields into a single logical skills entry."""
Expand Down Expand Up @@ -2027,32 +2099,11 @@ def _audit_apply_event(result: str, metadata: dict[str, Any]) -> None:
)
return

embed = discord.Embed(
title="✅ CRM Updated",
description=f"Applied updates for **{self.contact_name}**.",
color=0x00FF00,
)
display_fields = self._collapse_updated_fields(updated_fields)
labeled_fields = [self._field_label(field) for field in display_fields]
updated_fields_value = self._format_updated_fields_value(labeled_fields)
embed.add_field(
name="Updated Fields",
value=updated_fields_value,
inline=False,
)
applied_lines = self._build_applied_updates_lines(
embed = self._build_apply_success_embed(
updated_fields=updated_fields,
updated_values=updated_values,
link_discord_applied=link_discord_applied,
)
if applied_lines:
applied_updates_value = self._format_applied_updates_value(applied_lines)
embed.add_field(
name="Applied Updates",
value=applied_updates_value,
inline=False,
)
profile_url = f"{self.crm_cog.base_url}/#Contact/view/{self.contact_id}"
embed.add_field(name="🔗 CRM Profile", value=f"[View in CRM]({profile_url})")
_audit_apply_event(
"success",
{
Expand Down Expand Up @@ -3194,11 +3245,14 @@ def format_skill_delta(current: Any, proposed: Any) -> str:
inline=True,
)

if link_member:
discord_link_value = ResumeUpdateConfirmationView._format_discord_link_value(
link_member=link_member
)
if discord_link_value:
embed.add_field(
name="Discord Link",
value=truncate_field_value(
f"Will link contact to {link_member.mention}"
f"Will link contact to {discord_link_value}"
),
inline=False,
)
Expand Down
55 changes: 55 additions & 0 deletions tests/unit/test_crm.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,43 @@ async def test_resume_apply_confirmation_maps_skill_attrs_only_to_skills(

assert collapsed == ["skills", "phoneNumber"]

@pytest.mark.asyncio
async def test_resume_apply_success_embed_includes_discord_link_mention(
self, crm_cog
):
view = ResumeUpdateConfirmationView(
crm_cog=crm_cog,
requester_id=123,
contact_id="contact-1",
contact_name="Test User",
proposed_updates={},
link_discord={"user_id": "123456789", "username": "test-user"},
)

embed = view._build_apply_success_embed(
updated_fields=["skills"],
updated_values={"skills": ["python"]},
link_discord_applied=True,
)

discord_link_field = next(
field for field in embed.fields if field.name == "Discord Link"
)
assert "<@123456789>" in discord_link_field.value
assert "test-user" in discord_link_field.value

def test_format_discord_link_value_escapes_username_mentions_and_markdown(self):
username = "@everyone **ops**"
expected_username = discord.utils.escape_markdown(
discord.utils.escape_mentions(username)
)

value = ResumeUpdateConfirmationView._format_discord_link_value(
link_discord={"user_id": "123456789", "username": username}
)

assert value == f"<@123456789> ({expected_username})"

@pytest.mark.asyncio
async def test_resume_apply_confirmation_groups_location_fields(self, crm_cog):
"""Applied updates should render location fields as one combined line."""
Expand Down Expand Up @@ -1049,6 +1086,24 @@ def test_resume_preview_embed_includes_debug_field(self, crm_cog):
assert "current role" in evidence_field.value
assert "developer profile" in evidence_field.value

def test_resume_preview_embed_includes_discord_link_mention(self, crm_cog):
link_member = Mock()
link_member.id = 123456789
link_member.__str__ = Mock(return_value="resume-user")

embed, _ = crm_cog._build_resume_preview_embed(
contact_id="contact-1",
contact_name="Test User",
result={"proposed_changes": []},
link_member=link_member,
)

discord_link_field = next(
field for field in embed.fields if field.name == "Discord Link"
)
assert "<@123456789>" in discord_link_field.value
assert "resume-user" in discord_link_field.value

def test_build_resume_extract_debug_file_serializes_raw_payload(self, crm_cog):
"""The debug attachment should include raw and normalized extraction payloads."""
debug_file = crm_cog._build_resume_extract_debug_file(
Expand Down