2026-04-05 22:49:01 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
use MintyPHP\Module\Helpdesk\HelpdeskAuthorizationPolicy;
|
|
|
|
|
use MintyPHP\Module\Helpdesk\Service\BcSoapGateway;
|
|
|
|
|
use MintyPHP\Router;
|
|
|
|
|
use MintyPHP\Support\Guard;
|
|
|
|
|
|
|
|
|
|
Guard::requireLogin();
|
|
|
|
|
Guard::requireAbilityOrForbidden(HelpdeskAuthorizationPolicy::ABILITY_ACCESS);
|
|
|
|
|
|
|
|
|
|
$request = requestInput();
|
|
|
|
|
if ($request->method() !== 'GET') {
|
|
|
|
|
http_response_code(405);
|
|
|
|
|
Router::json(['ok' => false, 'error' => 'method_not_allowed']);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$entryNo = (int) $request->query('entryNo', '0');
|
2026-04-05 22:56:11 +02:00
|
|
|
$ticketNo = trim((string) $request->query('ticketNo', ''));
|
2026-04-05 22:49:01 +02:00
|
|
|
$filename = trim((string) $request->query('filename', ''));
|
|
|
|
|
|
|
|
|
|
if ($entryNo <= 0) {
|
|
|
|
|
http_response_code(400);
|
|
|
|
|
Router::json(['ok' => false, 'error' => 'missing_entry_no']);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$soapGateway = app(BcSoapGateway::class);
|
2026-04-05 22:56:11 +02:00
|
|
|
$odataGateway = app(\MintyPHP\Module\Helpdesk\Service\BcODataGateway::class);
|
|
|
|
|
|
|
|
|
|
// Resolve contactNo from ticket's Current_Contact_Name for SOAP authorization
|
|
|
|
|
$contactNo = '';
|
|
|
|
|
if ($ticketNo !== '') {
|
|
|
|
|
try {
|
|
|
|
|
$ticket = $odataGateway->getTicket($ticketNo);
|
|
|
|
|
if (is_array($ticket)) {
|
|
|
|
|
$contactName = trim((string) ($ticket['Current_Contact_Name'] ?? ''));
|
|
|
|
|
$customerName = trim((string) ($ticket['Company_Contact_Name'] ?? ''));
|
|
|
|
|
if ($contactName !== '' && $customerName !== '') {
|
|
|
|
|
$contacts = $odataGateway->getContactsForCustomer('', $customerName);
|
|
|
|
|
foreach ($contacts as $contact) {
|
|
|
|
|
if (trim((string) ($contact['Name'] ?? '')) === $contactName) {
|
|
|
|
|
$contactNo = trim((string) ($contact['No'] ?? ''));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (\Throwable) {
|
|
|
|
|
// Continue without contactNo — SOAP may still work
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-05 22:49:01 +02:00
|
|
|
|
|
|
|
|
try {
|
2026-04-05 22:56:11 +02:00
|
|
|
$result = $soapGateway->getTicketFile($entryNo, $contactNo);
|
2026-04-05 22:49:01 +02:00
|
|
|
} catch (\Throwable) {
|
|
|
|
|
http_response_code(502);
|
|
|
|
|
Router::json(['ok' => false, 'error' => 'Failed to load file']);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!$result['ok'] || !isset($result['data'])) {
|
|
|
|
|
http_response_code(404);
|
|
|
|
|
Router::json(['ok' => false, 'error' => $result['error'] ?? 'File not found']);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$data = $result['data'];
|
2026-04-05 22:53:46 +02:00
|
|
|
$maxFileSize = 20 * 1024 * 1024; // 20 MB
|
|
|
|
|
|
|
|
|
|
if (strlen($data) > $maxFileSize) {
|
|
|
|
|
http_response_code(413);
|
|
|
|
|
Router::json(['ok' => false, 'error' => 'File too large']);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-04-05 22:49:01 +02:00
|
|
|
|
2026-04-05 22:58:12 +02:00
|
|
|
// Ensure filename has an extension — derive from content if missing
|
2026-04-05 22:49:01 +02:00
|
|
|
$displayFilename = $filename !== '' ? $filename : 'attachment-' . $entryNo;
|
2026-04-05 22:58:12 +02:00
|
|
|
if (!str_contains($displayFilename, '.')) {
|
|
|
|
|
$ext = match (true) {
|
|
|
|
|
str_starts_with($data, "\x89PNG") => '.png',
|
|
|
|
|
str_starts_with($data, "\xFF\xD8\xFF") => '.jpg',
|
|
|
|
|
str_starts_with($data, "GIF8") => '.gif',
|
|
|
|
|
str_starts_with($data, "%PDF") => '.pdf',
|
|
|
|
|
str_starts_with($data, "PK\x03\x04") => '.zip',
|
|
|
|
|
default => '',
|
|
|
|
|
};
|
|
|
|
|
$displayFilename .= $ext;
|
|
|
|
|
}
|
2026-04-05 22:49:01 +02:00
|
|
|
|
2026-04-05 22:53:46 +02:00
|
|
|
header('X-Content-Type-Options: nosniff');
|
|
|
|
|
header('Content-Security-Policy: sandbox');
|
|
|
|
|
|
2026-04-05 22:53:17 +02:00
|
|
|
Router::download($displayFilename, $data);
|