AjaxSubmit not uploading formData using my Custom Route
-
Re: Documentation on making ajaxify.go work for custom routes?
Hello:
I am trying to create an alternate route, very similar to topic thumbnail upload route (/api/topic/thumb/upload) for uploading tiny icons. It appears that at server side, my controller does not receive the formData from ajaxSubmit call on the client side.Currently, my plugin is using existing hook filter:uploadStored but it is adding significant complexity to my logic since I am required to preserve uploadThumb functionality. Besides the absence of image resize hook for bypassing that step caused a heck of work around.
Instrumentation shows the data flow correctly on the client side to AjaxSubmit and call is received at server endpoint but no data is uploaded.
Route definition:
plugin.init = function(params, callback) { var app = params.router; var middleware = params.middleware; var multipart = require('connect-multiparty'); var multipartMiddleware = multipart(); var middlewares = [middleware.maintenanceMode, multipartMiddleware, middleware.validateFiles, middleware.applyCSRF]; var controller = uploadsController.uploadIcon; // routeHelpers.setupPageRoute(app, '/icon/upload',middleware ,middlewares , uploadIcon); var name = '/icon/upload'; app.post(name, middlewares, controller); app.post('/api' + name, controller); app.get('/admin/icons', middleware.admin.buildHeader, renderAdmin); app.get('/api/admin/icons', renderAdmin); callback(); };
My controller for uploadIcon has almost identical implementation as uploadsController.uploadThumb at this point:
uploadsController.uploadIcon= function(req, res, next) { console.log('\n\n\nrequest object:',req); // I get request object without formData values console.log('... files:',req.files); //undefined console.log("... uuid:!%o",req.uuid); //undefined console.log("...formData:!%o",req.formData); //undefined // don't execute beyond this line var files = req.files.files; }
My change handler icon upload form container is identical to Thumb upload as well except the change handler calls icon upload function :
//uploadTopicIcon({files: files, post_uuid: post_uuid, route: '/api/topic/thumb/upload', formData: fd}); // everything works uploadTopicIcon({files: files, post_uuid: post_uuid, route: '/api/icon/upload', formData: fd}); // no data is sent to server
This function is also almost identical to thumb upload except the names of the forms has changed:
function uploadTopicIcon(params) { var post_uuid = params.post_uuid, postContainer = $('#cmp-uuid-' + post_uuid), spinner = postContainer.find('.topic-icon-spinner'), iconForm = postContainer.find('#iconForm.'); iconForm.attr('action', config.relative_path + params.route); iconForm.off('submit').submit(function() { spinner.removeClass('hide'); uploads.inProgress[post_uuid] = uploads.inProgress[post_uuid] || []; uploads.inProgress[post_uuid].push(1); $(this).ajaxSubmit({ headers: { 'x-csrf-token': config.csrf_token }, formData: params.formData, error: onUploadError, success: function(uploads) { postContainer.find('#topic-icon-url').val((uploads[0] || {}).url || '').trigger('change'); }, complete: function() { uploads.inProgress[post_uuid].pop(); spinner.addClass('hide'); } }); return false; }); iconForm.submit(); }
As I mentioned I have developed my plugin using the hooks but it is very intrusive and I really wish to get the custom route work. Any pointers appreciated since I have been pulling my hair for a few days now.
Thanks in advance
-
Hi, I recently had a similar experience working on the upcoming emoji plugin rework. I used multer instead of connect-multiparty.
Here's the backend code for it: https://github.com/NodeBB/nodebb-plugin-emoji/blob/master/lib/controllers.ts#L58
It's typescript, but it shouldn't be too hard to read.The frontend code is React, but here's the rundown:
I used a custom button because the image file upload button looks ugly to me, this allows for more customization.
<button type="button" className="btn btn-default">Upload image</button> <form action="{window.config.relative_path}/api/admin/plugins/emoji/upload" method="post" encType="multipart/form-data" style="display: none;" id="image-form" > <input type="file" name="emojiImage" accept="image/*" id="image-input" /> <input type="hidden" name="fileName" id="file-name-input" /> </form>
Then I generate a unique filename on the upload, which is used server-side
const uploadImageButton = document.getElementById('upload-image'); const imageForm = document.getElementById('image-form'); const imageInput = document.getElementById('image-input'); const fileNameInput = document.getElementById('file-name-input'); const uploadImage = () => { imageInput.click(); $(imageInput).one('change', () => { if (!imageInput.files.length) { return; } const fileName = `${window.utils.generateUUID()}-${imageInput.files[0].name}`; fileNameInput.value = fileName; $(imageForm).ajaxSubmit({ success: () => { // do stuff imageInput.value = ''; }, error: () => { const err = Error('Failed to upload file'); console.error(err); window.app.alertError(err); imageInput.value = ''; }, }); }); }; uploadImageButton.addEventListener('click', uploadImage, false);
-
@pitaj Thanks for the very helpful post. For the benefit of others who stumble upon same issue using multi-part middleware, the fix for issue in my original post was simply as follows:
plugin.init = function(params, callback) { var app = params.router; var middleware = params.middleware; var multipart = require('connect-multiparty'); var multipartMiddleware = multipart(); var middlewares = [multipartMiddleware, middleware.applyCSRF]; var controller = uploadsController.uploadIcon; var name = '/icon/upload'; app.post(name, middlewares, controller); app.post('/api' + name, middlewares, controller); app.get('/admin/icons', middleware.admin.buildHeader, renderAdmin); app.get('/api/admin/icons', renderAdmin); callback(); }; Thanks again for your support.
-
Hello:
This module worked flawlessly for nearly three years but since a few days ago, I noticed again it wasn't transferring the file names to the route destination. It works intermittently but mostly it bombs out and returns error: onUploadError:Something went wrong while parsing server response.
To my knowledge, nothing has changed in that code listed above and I didn't see anything in the breaking changes related to this issue. It has been a couple of days of tracing and debugging so I am out of ideas.
I was running Nodebb 1.14.2 for a while when all this started to happen and then I upgraded to latest 1.14.3 Beta hoping that rebuilding the package from source in the process may help. It sure helped with some tools finding their missing components (like Huskey) but wasn't the cure.
At this juncture, I am not sure which is the best way to go: Either use a 3rd party tool like Multer or there is an easier fix.
Edit: This issue currently appears only on the windows development environment and production seems to be working (Nodebb 1.14.2/Ubuntu 18) normally. There are no server-side error logs related to this operation. My Node.js is v14.12.0, Mongo 4.2.2 and Chrome Version 86.0.4240.111 64. I have same issue with IE.
Any advice would be greatly appreciated.
Thank you.