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:
parent
b21327a5d3
commit
462704fae7
@ -156,7 +156,7 @@ $routes->get('/activities/suspend/(:num)', 'Activities::suspend/$1');
|
|||||||
$routes->get('/activities/disable/(:num)', 'Activities::disable/$1');
|
$routes->get('/activities/disable/(:num)', 'Activities::disable/$1');
|
||||||
// $routes->get('/activities/delete/(:num)', 'Activities::delete/$1');
|
// $routes->get('/activities/delete/(:num)', 'Activities::delete/$1');
|
||||||
$routes->match(['get','post'],'/activities/save', 'Activities::save');
|
$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/getproduct/(:num)', 'Activities::getproduct/$1/$2/$3');
|
||||||
$routes->get('/activities/getvendor/(:num)', 'Activities::getvendor/$1');
|
$routes->get('/activities/getvendor/(:num)', 'Activities::getvendor/$1');
|
||||||
$routes->get('/activities/getconsumable/(:num)', 'Activities::getconsumable/$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')) {
|
// if (is_file(APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php')) {
|
||||||
// require APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php';
|
// require APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php';
|
||||||
// }
|
// }
|
||||||
|
|||||||
@ -9,6 +9,7 @@ use App\Models\ActdetailModel;
|
|||||||
use App\Models\InvTransModel;
|
use App\Models\InvTransModel;
|
||||||
|
|
||||||
use CodeIgniter\Controller;
|
use CodeIgniter\Controller;
|
||||||
|
use CodeIgniter\HTTP\Files\UploadedFile;
|
||||||
|
|
||||||
class Activities extends Controller {
|
class Activities extends Controller {
|
||||||
|
|
||||||
@ -98,6 +99,28 @@ class Activities extends Controller {
|
|||||||
|
|
||||||
return implode(',', array_unique(array_filter($normalized)));
|
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() {
|
public function index() {
|
||||||
$data = array();
|
$data = array();
|
||||||
@ -1075,35 +1098,62 @@ class Activities extends Controller {
|
|||||||
return $datas;
|
return $datas;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function upload(){
|
public function upload()
|
||||||
if ($this->request->getMethod() === 'POST') {
|
{
|
||||||
if ( 0 < $_FILES['file']['error'] ) {
|
$method = strtolower($this->request->getMethod());
|
||||||
return $this->response->setJSON([
|
if ($method === 'options') {
|
||||||
'status' => 'error',
|
return $this->response->setStatusCode(204);
|
||||||
'message' => 'Upload failed',
|
}
|
||||||
'error' => $_FILES['file']['error'],
|
|
||||||
]);
|
if ($method !== 'post') {
|
||||||
}
|
return $this->response->setStatusCode(405)->setJSON([
|
||||||
else {
|
'status' => 'error',
|
||||||
$subfolder = $this->getAttachmentSubfolder();
|
'message' => 'Invalid request method',
|
||||||
$uploadDir = FCPATH . "upload/$subfolder/";
|
]);
|
||||||
if (!is_dir($uploadDir)) {
|
}
|
||||||
mkdir($uploadDir, 0755, true);
|
|
||||||
}
|
$file = $this->request->getFile('file');
|
||||||
$filename = basename(str_replace('\\', '/', $_FILES['file']['name']));
|
if ($file === null || $file->getError() === UPLOAD_ERR_NO_FILE) {
|
||||||
if (!move_uploaded_file($_FILES['file']['tmp_name'], $uploadDir . $filename)) {
|
$file = $this->findFirstUploadedFile($this->request->getFiles());
|
||||||
return $this->response->setJSON([
|
}
|
||||||
'status' => 'error',
|
|
||||||
'message' => 'Unable to save upload',
|
if ($file === null || $file->getError() === UPLOAD_ERR_NO_FILE) {
|
||||||
]);
|
return $this->response->setStatusCode(400)->setJSON([
|
||||||
}
|
'status' => 'error',
|
||||||
return $this->response->setJSON([
|
'message' => 'No file uploaded',
|
||||||
'status' => 'success',
|
]);
|
||||||
'relativePath' => $this->buildAttachmentRelativePath($filename),
|
}
|
||||||
'filename' => $filename,
|
|
||||||
]);
|
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
|
public function act_content($actid, $filter_email=false) { // Parameter Ke-2 Untuk Email
|
||||||
|
|||||||
@ -1179,7 +1179,7 @@ toggleCalibrateAccordion();
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.crmActivitiesUploadEndpoint = <?= json_encode(base_url('activities/upload')) ?>;
|
window.crmActivitiesUploadEndpoint = <?= json_encode(site_url('activities/upload')) ?>;
|
||||||
</script>
|
</script>
|
||||||
<script type="module" src="<?=base_url();?>/assets/uppy/uppy-old.js"></script>
|
<script type="module" src="<?=base_url();?>/assets/uppy/uppy-old.js"></script>
|
||||||
<?= $this->endSection() ?>
|
<?= $this->endSection() ?>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { Uppy, Dashboard, XHRUpload } from "https://releases.transloadit.com/uppy/v3.15.0/uppy.min.mjs";
|
import { Uppy, Dashboard, XHRUpload } from "https://releases.transloadit.com/uppy/v3.15.0/uppy.min.mjs";
|
||||||
|
|
||||||
const uploadEndpoint = window.crmActivitiesUploadEndpoint ?? "/activities/upload";
|
const uploadEndpoint = window.crmActivitiesUploadEndpoint ?? "/activities/upload";
|
||||||
|
const attachmentInput = document.querySelector("#attachment");
|
||||||
|
|
||||||
// var uppy = new Uppy({
|
// var uppy = new Uppy({
|
||||||
// onBeforeFileAdded: (currentFile, files) => {
|
// onBeforeFileAdded: (currentFile, files) => {
|
||||||
@ -57,7 +58,12 @@ onBeforeFileAdded: (currentFile, files) => {
|
|||||||
height: 300,
|
height: 300,
|
||||||
})
|
})
|
||||||
|
|
||||||
.use(XHRUpload, { endpoint: uploadEndpoint, method: 'post' });
|
.use(XHRUpload, {
|
||||||
|
endpoint: uploadEndpoint,
|
||||||
|
method: "post",
|
||||||
|
fieldName: "file",
|
||||||
|
formData: true,
|
||||||
|
});
|
||||||
|
|
||||||
uppy.on("complete", (result) => {
|
uppy.on("complete", (result) => {
|
||||||
let array = result.successful;
|
let array = result.successful;
|
||||||
@ -73,17 +79,45 @@ uppy.on("complete", (result) => {
|
|||||||
|
|
||||||
let text = arrtext.join();
|
let text = arrtext.join();
|
||||||
|
|
||||||
$('#attachment').val(function(){
|
if (attachmentInput) {
|
||||||
if (this.value == '') {
|
$(attachmentInput).val(function(){
|
||||||
return this.value + text;
|
if (this.value === "") {
|
||||||
} else if (this.value != ''){
|
return this.value + text;
|
||||||
return this.value + ',' + text;
|
}
|
||||||
}
|
|
||||||
});
|
return this.value + "," + text;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
console.log( "Upload complete! We’ve uploaded these files:", result.successful);
|
console.log( "Upload complete! We’ve 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 attachmentList = document.querySelector('#attachment').value;
|
||||||
const arrayx = attachmentList ? attachmentList.split(',') : [];
|
const arrayx = attachmentList ? attachmentList.split(',') : [];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user