mirror of
https://github.com/dartdavros/chatballs.git
synced 2026-10-12 04:14:59 +03:00
SPEC-HUB-0011 §12 (алгоритм start) + §14 (error model).
- token.py: HS256 JWT verify через stdlib (hmac/hashlib/base64), envelope claims
(iss/aud/contract/iat/exp/jti/data). RS256/EdDSA — TODO.
- jsonpath.py: ограниченный JSONPath-subset ($.field, $.a.b, $.arr[0].field).
- session.py: verify_and_resolve (channel policy → token → contract → schema →
identity/operator/ai/search extraction) + start_support_session (snapshot upsert,
create-or-continue conversation, audit success/denied). Raw token не сохраняется
и не логируется — только хэш jti.
- errors.py: машинные коды (TOKEN_*, CONTRACT_*, PAYLOAD_SCHEMA_INVALID, ...) +
SupportSessionError; публичное сообщение безопасное.
- services.py: register_contract / set_contract_status (зеркало products).
- selectors.py / serializers.py / views.py / urls.py: CRUD контрактов (IsOwner),
POST /api/v1/support/sessions/ (AllowAny, продукт→Hub), snapshot-by-subject.
- Публичный error envelope {error, message} для start (как OrderIngestView).
43 lines
1.8 KiB
Python
43 lines
1.8 KiB
Python
from __future__ import annotations
|
|
|
|
from hub_platform.support.models import ProductSupportContract, SupportIdentitySnapshot
|
|
|
|
|
|
def support_contract_payload(contract: ProductSupportContract) -> dict[str, object]:
|
|
return {
|
|
"id": contract.id,
|
|
"code": contract.code,
|
|
"version": contract.version,
|
|
"status": contract.status,
|
|
"product": {"code": contract.product.code, "name": contract.product.name},
|
|
"allowedChannels": [
|
|
{"id": ch.id, "code": ch.code, "name": ch.name}
|
|
for ch in contract.allowed_channels.all()
|
|
],
|
|
"schemaJson": contract.schema_json,
|
|
"identityMappingJson": contract.identity_mapping_json,
|
|
"operatorUiJson": contract.operator_ui_json,
|
|
"aiContextJson": contract.ai_context_json,
|
|
"searchMappingJson": contract.search_mapping_json,
|
|
"sensitiveFieldsJson": contract.sensitive_fields_json,
|
|
"createdAt": contract.created_at.isoformat(),
|
|
"updatedAt": contract.updated_at.isoformat(),
|
|
}
|
|
|
|
|
|
def support_identity_snapshot_payload(snapshot: SupportIdentitySnapshot) -> dict[str, object]:
|
|
# payload_json НЕ отдаётся — внутреннее; оператор получает operator_context_json.
|
|
return {
|
|
"id": snapshot.id,
|
|
"product": {"code": snapshot.product.code, "name": snapshot.product.name},
|
|
"contractCode": snapshot.contract_code,
|
|
"subjectKey": snapshot.subject_key,
|
|
"accountKey": snapshot.account_key,
|
|
"displayName": snapshot.display_name,
|
|
"displayEmail": snapshot.display_email,
|
|
"operatorContextJson": snapshot.operator_context_json,
|
|
"aiContextJson": snapshot.ai_context_json,
|
|
"searchText": snapshot.search_text,
|
|
"verifiedAt": snapshot.verified_at.isoformat(),
|
|
}
|