修复V4来源附件URL展示脱敏

This commit is contained in:
andy
2026-07-19 14:20:06 +07:00
parent cae169cefd
commit 145511620c
5 changed files with 53 additions and 6 deletions

View File

@@ -175,8 +175,8 @@ function normalizeAttachments(value: unknown): AttachmentSummary[] {
function toAttachmentSummary(value: unknown, index: number): AttachmentSummary {
const record = readRecord(value)
const name = record
? readFirstString(record, ['name', 'file_name', 'filename', 'display_name', 'title']) ?? t('conversation.unnamedAttachment')
: String(value)
? safeAttachmentName(readFirstString(record, ['name', 'file_name', 'filename', 'display_name', 'title']))
: safeAttachmentName(String(value))
const type = record ? readFirstString(record, ['content_type', 'mime_type', 'media_type', 'file_type']) : null
const size = record ? readNumber(record, 'size_bytes') ?? readNumber(record, 'size') : null
return {
@@ -249,6 +249,18 @@ function formatFileSize(size: number | null): string {
}
return `${(size / 1024 / 1024).toFixed(1)} MB`
}
function safeAttachmentName(value: string | null): string {
const trimmedValue = value?.trim()
if (!trimmedValue || isUnsafeAttachmentText(trimmedValue)) {
return t('conversation.unnamedAttachment')
}
return trimmedValue
}
function isUnsafeAttachmentText(value: string): boolean {
return /^(https?:\/\/|oss:\/\/|s3:\/\/)/i.test(value.trim())
}
</script>
<style scoped>

View File

@@ -75,6 +75,36 @@ describe('reservation V4 pages', () => {
})
})
it('does not render direct attachment URLs from V4 source message payload', async () => {
const detail = createOrderTaskDetail({
sourceDisplayPayload: {
subject: 'Booking Request',
sender_summary: 'guest@example.test',
relevant_message_excerpt: 'Please book one twin room.',
uploaded_media: [
'https://oss.example/private/booking.pdf',
'oss://bucket/private-voucher.jpg',
{
file_name: 'safe-booking.pdf',
content_type: 'application/pdf',
},
],
},
})
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
const wrapper = await mountWithPlugins(
ReservationV4OrderTaskDetailView,
'/reservation/order-tasks/9001',
)
await flushPromises()
expect(wrapper.text()).toContain('safe-booking.pdf')
expect(wrapper.text()).toContain(zhCN.conversation.unnamedAttachment)
expect(wrapper.text()).not.toContain('https://oss.example')
expect(wrapper.text()).not.toContain('oss://bucket')
})
it('submits V4 review resolution with field_pointer overrides and confirmed order id', async () => {
const detail = createOrderTaskDetail({
businessCardStatus: 'REVIEW_REQUIRED',
@@ -250,10 +280,11 @@ async function mountWithPlugins(component: object, initialPath: string) {
function createOrderTaskDetail(options: {
businessCardStatus?: string
businessCardAvailability?: Partial<ReservationV4TaskCardResult['availability']>
sourceDisplayPayload?: ReservationV4TaskCardResult['display_payload']
} = {}): ReservationV4OrderTaskDetailResult {
const sourceCard = createCard('card-source', 'SOURCE_MESSAGE_DISPLAY', 'READONLY', {
fields: [],
display_payload: {
display_payload: options.sourceDisplayPayload ?? {
subject: 'Booking Request',
sender_summary: 'guest@example.test',
relevant_message_excerpt: 'Please book one twin room.',