修复V4来源附件URL展示脱敏
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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.',
|
||||
|
||||
Reference in New Issue
Block a user