fix(tenancy): use absolute URL in team invitation email link
Some checks failed
Some checks failed
Email clients need absolute URLs to make links clickable. The acceptance_link was a relative path (/store/invitation/accept?token=...) which rendered as plain text. Now prepends the platform domain with the correct protocol. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -99,7 +99,7 @@ def send_campaign(
|
||||
db,
|
||||
template_id=data.template_id,
|
||||
prospect_ids=data.prospect_ids,
|
||||
sent_by_user_id=current_admin.user_id,
|
||||
sent_by_user_id=current_admin.id,
|
||||
)
|
||||
db.commit()
|
||||
return [CampaignSendResponse.model_validate(s) for s in sends]
|
||||
|
||||
@@ -48,7 +48,7 @@ def create_interaction(
|
||||
interaction = interaction_service.create(
|
||||
db,
|
||||
prospect_id=prospect_id,
|
||||
user_id=current_admin.user_id,
|
||||
user_id=current_admin.id,
|
||||
data=data.model_dump(exclude_none=True),
|
||||
)
|
||||
db.commit()
|
||||
|
||||
@@ -80,7 +80,7 @@ def create_prospect(
|
||||
prospect = prospect_service.create(
|
||||
db,
|
||||
data.model_dump(exclude_none=True),
|
||||
captured_by_user_id=current_admin.user_id,
|
||||
captured_by_user_id=current_admin.id,
|
||||
)
|
||||
db.commit()
|
||||
return _to_response(prospect)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# app/modules/prospecting/schemas/score.py
|
||||
"""Pydantic schemas for opportunity scoring."""
|
||||
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, field_validator
|
||||
|
||||
|
||||
class ProspectScoreResponse(BaseModel):
|
||||
@@ -23,5 +24,19 @@ class ProspectScoreResponse(BaseModel):
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
@field_validator("reason_flags", mode="before")
|
||||
@classmethod
|
||||
def parse_reason_flags(cls, v):
|
||||
if isinstance(v, str):
|
||||
return json.loads(v)
|
||||
return v
|
||||
|
||||
@field_validator("score_breakdown", mode="before")
|
||||
@classmethod
|
||||
def parse_score_breakdown(cls, v):
|
||||
if isinstance(v, str):
|
||||
return json.loads(v)
|
||||
return v
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
{{ loading_state('Loading prospect...') }}
|
||||
{{ error_state('Error loading prospect') }}
|
||||
|
||||
<div x-show="!loading && !error && prospect" class="space-y-6">
|
||||
<template x-if="!loading && !error && prospect">
|
||||
<div class="space-y-6">
|
||||
<!-- Header -->
|
||||
<div class="flex flex-col sm:flex-row sm:items-center justify-between my-6 gap-4">
|
||||
<div class="flex items-center space-x-4">
|
||||
@@ -215,6 +216,7 @@
|
||||
<p x-show="campaignSends.length === 0" class="text-sm text-gray-400 text-center py-8">No campaigns sent yet</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Interaction Modal -->
|
||||
{% call modal('interactionModal', 'Log Interaction', show_var='showInteractionModal', size='md', show_footer=false) %}
|
||||
|
||||
@@ -980,9 +980,13 @@ class StoreTeamService:
|
||||
role_name: str,
|
||||
):
|
||||
"""Send team invitation email."""
|
||||
from app.core.config import settings as app_settings
|
||||
from app.modules.messaging.services.email_service import EmailService
|
||||
|
||||
acceptance_link = f"/store/invitation/accept?token={token}"
|
||||
domain = app_settings.main_domain.rstrip("/")
|
||||
scheme = "http" if "localhost" in domain else "https"
|
||||
base_url = f"{scheme}://{domain}" if "://" not in domain else domain
|
||||
acceptance_link = f"{base_url}/store/invitation/accept?token={token}"
|
||||
|
||||
email_service = EmailService(db)
|
||||
email_service.send_template(
|
||||
|
||||
Reference in New Issue
Block a user