fix(upload): harden activities uploader for Uppy requests

Support POST/OPTIONS handling and robust file discovery in Activities::upload so Uppy submissions are accepted reliably.

Align client upload endpoint/payload config and add clearer upload error handling to surface failures in the editor UI.
This commit is contained in:
mahdahar 2026-04-20 09:51:50 +07:00
parent b21327a5d3
commit 462704fae7
4 changed files with 124 additions and 40 deletions

View File

@ -156,7 +156,7 @@ $routes->get('/activities/suspend/(:num)', 'Activities::suspend/$1');
$routes->get('/activities/disable/(:num)', 'Activities::disable/$1');
// $routes->get('/activities/delete/(:num)', 'Activities::delete/$1');
$routes->match(['get','post'],'/activities/save', 'Activities::save');
$routes->post('/activities/upload', 'Activities::upload');
$routes->match(['post', 'options'], '/activities/upload', 'Activities::upload');
$routes->get('/activities/getproduct/(:num)', 'Activities::getproduct/$1/$2/$3');
$routes->get('/activities/getvendor/(:num)', 'Activities::getvendor/$1');
$routes->get('/activities/getconsumable/(:num)', 'Activities::getconsumable/$1');
@ -335,4 +335,4 @@ $routes->get('/api/getProductSites', 'Api::getProductSites');
*/
// if (is_file(APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php')) {
// require APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php';
// }
// }

View File

@ -9,6 +9,7 @@ use App\Models\ActdetailModel;
use App\Models\InvTransModel;
use CodeIgniter\Controller;
use CodeIgniter\HTTP\Files\UploadedFile;
class Activities extends Controller {
@ -98,6 +99,28 @@ class Activities extends Controller {
return implode(',', array_unique(array_filter($normalized)));
}
protected function findFirstUploadedFile(array $files): ?UploadedFile
{
foreach ($files as $file) {
if ($file instanceof UploadedFile) {
if ($file->getError() !== UPLOAD_ERR_NO_FILE) {
return $file;
}
continue;
}
if (is_array($file)) {
$uploadedFile = $this->findFirstUploadedFile($file);
if ($uploadedFile !== null) {
return $uploadedFile;
}
}
}
return null;
}
public function index() {
$data = array();
@ -1075,35 +1098,62 @@ class Activities extends Controller {
return $datas;
}
public function upload(){
if ($this->request->getMethod() === 'POST') {
if ( 0 < $_FILES['file']['error'] ) {
return $this->response->setJSON([
'status' => 'error',
'message' => 'Upload failed',
'error' => $_FILES['file']['error'],
]);
}
else {
$subfolder = $this->getAttachmentSubfolder();
$uploadDir = FCPATH . "upload/$subfolder/";
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$filename = basename(str_replace('\\', '/', $_FILES['file']['name']));
if (!move_uploaded_file($_FILES['file']['tmp_name'], $uploadDir . $filename)) {
return $this->response->setJSON([
'status' => 'error',
'message' => 'Unable to save upload',
]);
}
return $this->response->setJSON([
'status' => 'success',
'relativePath' => $this->buildAttachmentRelativePath($filename),
'filename' => $filename,
]);
}
}
public function upload()
{
$method = strtolower($this->request->getMethod());
if ($method === 'options') {
return $this->response->setStatusCode(204);
}
if ($method !== 'post') {
return $this->response->setStatusCode(405)->setJSON([
'status' => 'error',
'message' => 'Invalid request method',
]);
}
$file = $this->request->getFile('file');
if ($file === null || $file->getError() === UPLOAD_ERR_NO_FILE) {
$file = $this->findFirstUploadedFile($this->request->getFiles());
}
if ($file === null || $file->getError() === UPLOAD_ERR_NO_FILE) {
return $this->response->setStatusCode(400)->setJSON([
'status' => 'error',
'message' => 'No file uploaded',
]);
}
if (! $file->isValid()) {
return $this->response->setStatusCode(400)->setJSON([
'status' => 'error',
'message' => 'Upload failed',
'error' => $file->getErrorString(),
]);
}
$subfolder = $this->getAttachmentSubfolder();
$uploadDir = FCPATH . 'upload/' . $subfolder . '/';
if (! is_dir($uploadDir) && ! mkdir($uploadDir, 0755, true) && ! is_dir($uploadDir)) {
return $this->response->setStatusCode(500)->setJSON([
'status' => 'error',
'message' => 'Unable to create upload directory',
]);
}
$filename = basename(str_replace('\\', '/', $file->getClientName()));
if (! $file->move($uploadDir, $filename, true)) {
return $this->response->setStatusCode(500)->setJSON([
'status' => 'error',
'message' => 'Unable to save upload',
]);
}
return $this->response->setJSON([
'status' => 'success',
'relativePath' => $this->buildAttachmentRelativePath($filename),
'filename' => $filename,
]);
}
public function act_content($actid, $filter_email=false) { // Parameter Ke-2 Untuk Email

View File

@ -1179,7 +1179,7 @@ toggleCalibrateAccordion();
</script>
<script>
window.crmActivitiesUploadEndpoint = <?= json_encode(base_url('activities/upload')) ?>;
window.crmActivitiesUploadEndpoint = <?= json_encode(site_url('activities/upload')) ?>;
</script>
<script type="module" src="<?=base_url();?>/assets/uppy/uppy-old.js"></script>
<?= $this->endSection() ?>

View File

@ -1,6 +1,7 @@
import { Uppy, Dashboard, XHRUpload } from "https://releases.transloadit.com/uppy/v3.15.0/uppy.min.mjs";
const uploadEndpoint = window.crmActivitiesUploadEndpoint ?? "/activities/upload";
const attachmentInput = document.querySelector("#attachment");
// var uppy = new Uppy({
// onBeforeFileAdded: (currentFile, files) => {
@ -57,7 +58,12 @@ onBeforeFileAdded: (currentFile, files) => {
height: 300,
})
.use(XHRUpload, { endpoint: uploadEndpoint, method: 'post' });
.use(XHRUpload, {
endpoint: uploadEndpoint,
method: "post",
fieldName: "file",
formData: true,
});
uppy.on("complete", (result) => {
let array = result.successful;
@ -73,17 +79,45 @@ uppy.on("complete", (result) => {
let text = arrtext.join();
$('#attachment').val(function(){
if (this.value == '') {
return this.value + text;
} else if (this.value != ''){
return this.value + ',' + text;
}
});
if (attachmentInput) {
$(attachmentInput).val(function(){
if (this.value === "") {
return this.value + text;
}
return this.value + "," + text;
});
}
console.log( "Upload complete! Weve uploaded these files:", result.successful);
});
uppy.on("upload-error", (file, error, response) => {
const fallbackMessage = error?.message ?? "Upload failed";
const responseMessage = response?.body?.message ?? response?.statusText ?? "";
const fileName = file?.name ?? "file";
const message = responseMessage !== "" ? responseMessage : fallbackMessage;
console.error("Uppy upload-error", {
file,
error,
response,
uploadEndpoint,
});
alert("Upload failed for " + fileName + ": " + message);
});
uppy.on("restriction-failed", (file, error) => {
console.error("Uppy restriction-failed", { file, error });
alert(error?.message ?? "File is not allowed.");
});
uppy.on("error", (error) => {
console.error("Uppy error", error);
alert(error?.message ?? "Unexpected uploader error.");
});
/*
const attachmentList = document.querySelector('#attachment').value;
const arrayx = attachmentList ? attachmentList.split(',') : [];