Fine Uploader - This is an unrecoverable error, we must restart the upload entirely on the next retry attempt - fine-uploader

Using Fine Uploader 5.0.6 i am trying to send both the original and scaled image onto my s3 bucket. it works until i set a minimum size limit with minSizeLimit in the validation options. When i leave this out or uncomment it it works fine but when it's in i get this output in my console:
POST http://zippi.bucket.artist.s3-eu-west-1.amazonaws.com/ 400 (Bad Request)
[Fine Uploader 5.0.6] This is an unrecoverable error, we must restart the upload entirely on the next retry attempt.
I have retry:EnableAuto:true so this runs through 3 times with the same result until stopping. This only applies to the scaled image, the main image uploads fine without issue
My signature.php page does not include any references to a minimum file size, just maximum in
$expectedMaxSize = 10000000;
In this function below. Could this be causing it?:
function isPolicyValid($policy) {
global $expectedMaxSize, $expectedBucketName;
$conditions = $policy["conditions"];
$bucket = null;
$parsedMaxSize = null;
for ($i = 0; $i < count($conditions); ++$i) {
$condition = $conditions[$i];
if (isset($condition["bucket"])) {
$bucket = $condition["bucket"];
}
else if (isset($condition[0]) && $condition[0] == "content-length-range") {
$parsedMaxSize = $condition[2];
}
}
return $bucket == $expectedBucketName && $parsedMaxSize == (string)$expectedMaxSize;
}
Code on my actual page:
var manualuploader = jQuery("#fine-uploader").fineUploaderS3({
request: {
endpoint: 's3.bucket.files.s3-eu-west-1.amazonaws.com',
accessKey: 'XXXXXXXXXXXX'
},
signature: {
endpoint: 'signature.php'
},
uploadSuccess: {
endpoint: 'success.php'
},
iframeSupport: {
localBlankPagePath: 'success.html'
},
multiple: false,
retry: {
enableAuto: true
},
autoUpload: false,
scaling: {
sizes: [
{name: "web", maxSize: 500}
]
},
validation: {
allowedExtensions: ['jpeg', 'jpg', 'png'],
sizeLimit: 10000000,
minSizeLimit: 400000 // THIS IS THE LINE
},
objectProperties: {
key: function (fileId) {
var filename = jQuery('#fine-uploader').fineUploader('getName', fileId);
var uuid = jQuery('#fine-uploader').fineUploader('getUuid', fileId);
var ext = filename.substr(filename.lastIndexOf('.') + 1);
folder_name = folder_name.replace(/\s/g, '-');
var new_filename;
if (filename.indexOf('(web)') >= 0){
new_filename = '/the_web_version.';
}
else {
new_filename = '/the_original_version.';
}
return artist + '/' + folder_name + new_filename + ext;
}
}
}).on('submitted', function(event, id, name) {
//....
}).on('cancel', function(event, id, name) {
//....
}).on('progress', function(event, id, fileName, loaded, total) {
//....
}).on('complete', function(event, id, name, response) {
if (response.success) {
//...
}
});
jQuery('#triggerUpload').click(function() {
manualuploader.fineUploaderS3('uploadStoredFiles');
});

If you set a minimum file size validation option, Fine Uploader will pass that value on to S3 to ensure it is respected. Most likely, a scaled image is smaller than that minimum size. I suggest simply removing this restriction if you are dealing with dynamically scaled images.

Related

Array validation not working for PATCH in mongoose

This is my mongoose schema. but when i send PATCH req from client. the options (array) validation not work. but others field's validation work.
I search in online but dont get the problem. How can I slove it. Thank you.
const optionsValidator = function (options) {
console.log("Validating options...");
const MinLength = 2;
const MaxLength = 6;
const MCQCode = 0;
// checking options are required or not for the question;
if (this.questionType !== MCQCode) {
throw new Error("Options are required only for MCQ");
}
if (options.length < MinLength) {
throw new Error(`At least ${MinLength} options are required`);
}
if (options.length > MaxLength) {
throw new Error(`Maximum ${MaxLength} options can be created`);
}
// make options lower case before checking uniqueness of the options
const lowerOptions = options.map((option) => option.toLowerCase());
if (lowerOptions.length !== new Set(lowerOptions).size) {
throw new Error("Options are not unique");
}
// options are validated
return true;
};
const questionSchema = new Schema({
quesId: { type: String, required: [true, "Id_required"] },
title: { type: String, required: [true, "title_required"] },
questionType: {
type: Number,
default: 0,
},
options: {
type: [String],
default: undefined,
required: function () {
return this.questionType === 0 && !this.options;
},
validate: {
validator: optionsValidator,
message: (props) => props.reason.message,
},
},
});
const updatedData = { ...questionData };
let optionsData;
if (updatedData.options) {
data = await Question.findById(id);
optionsData = {
$push: { options: { $each: updatedData.options } },
};
delete updatedData.options;
}
exports.patchQuestion = async (id, questionData) => {
return (result = await Question.findOneAndUpdate(
{ _id: id },
{ ...optionsData, $set: updatedData },
{ new: true, runValidators: true }
));
}
The is the PATCH request send form client.
{ "options": ["A","A"] }

How to create a list of wix media folder images with url and name

Is there a way in wix to get a list of all media files (images) urls and names?
I would need this to upload it in a field of the content manager to link data records and images.
You can use the new mediaManager API:
From Wix enable the developper mode
Go to the code files (icon {} to the left), and create a new backend JS file named 'http-functions.js'
Edit this file and add the following code:
import { ok, badRequest } from 'wix-http-functions';
import { mediaManager } from 'wix-media-backend';
export function get_filesList(request) {
const response = {
"headers": {
"Content-Type": "application/json"
}
};
var filters = {};
var paging = {};
if (request.query) {
if ('folder' in request.query ) { //
filters.parentFolderId = request.query["folder"];
}
if ('limit' in request.query) {
paging.limit = request.query['limit'];
}
if ('skip' in request.query) {
paging.skip = request.query['skip'];
}
}
return mediaManager.listFiles(filters, null, paging)
.then((myFiles) => {
response.body = {
"filesList": myFiles
};
return ok(response);
})
.catch((err) => {
response.body = {
"error": err
};
return badRequest(response);
});
}
export function get_listFolders(request) {
const response = {
"headers": {
"Content-Type": "application/json"
}
};
var filters = {};
var paging = {};
if (request.query) {
if ('folder' in request.query ) { //
filters.parentFolderId = request.query["folder"];
}
if ('limit' in request.query) {
paging.limit = request.query['limit'];
}
if ('skip' in request.query) {
paging.skip = request.query['skip'];
}
}
return mediaManager.listFolders(filters, null, paging)
.then((myFolders) => {
response.body = {
"foldersList": myFolders
};
return ok(response);
})
.catch((err) => {
response.body = {
"error": err
};
return badRequest(response);
});
}
Publish the files
You can query your custom API from: https://www.your_website.com/_functions/filesList and https://www.your_website.com/_functions/foldersList and query parameters folderId, skip and limit for pagination.
Wix documentation:
https://support.wix.com/en/article/velo-exposing-a-site-api-with-http-functions
https://www.wix.com/velo/reference/wix-media-backend/mediamanager-obj/listfiles

FineUploader 5.14.0 - setParams not working with large files

I've had the following code working for quite a while now (over a year) but a user has tried to upload a 14MB file and the extra data I post along with the upload seems to not get posted anymore.
In Chrome dev tools I look at the header of the (single) XHR and I see the data in the "Form data" section but nothing get's to the server which I don't understand.
Files that are a few MB or smaller work without issue. I've not found a magic MB limit yet.
The extra data is in the onUpload call back. board_hash is in the head of page.
var fu_instance = new qq.FineUploader(
{
element: $uploader[0],
template: 'agenda_file_template',
debug: true,
request: {
endpoint: '/m/upload',
forceMultipart: false,
customHeaders: {
Accept: 'application/json'
}
},
autoUpload: false,
messages:
{
noFilesError: "There is no files to upload. Select or drag and drop some files to upload.",
},
failedUploadTextDisplay:
{
mode: 'custom',
responseProperty: 'error'
},
callbacks:
{
onSubmit: function(id, filename)
{
// File added to upload
$uploader.addClass('hide-drop-msg');
$btn_submit_upload.html('Upload').show();
unsaved = true;
},
onUpload: function(id, name)
{
fu_instance.setParams({'board_hash': board_hash, 'parent': $parent.val()});
},
onCancel: function(id, name)
{
// Actually onBeforeCancel
if ($uploader.find('ul.qq-upload-list li').length == 1)
{
// There is currently 1 & it's about to be axed
$uploader.removeClass('hide-drop-msg');
$btn_reset_uploads.hide();
$btn_submit_upload.html('Upload').show();
unsaved = false;
}
},
onError: function(id, name, reason, resp)
{
// Specific file error
if (resp.hasOwnProperty('auth_expired'))
{
window.location.href = auth_url;
}
},
onComplete: function(id, name, resp)
{
if (resp.success)
{
var $parent_el = $('#'+$parent.val());
$parent_el.find('.files').append(resp.html);
$parent_el.find('.no-agenda-files').hide();
}
},
onAllComplete: function(succeeded, failed)
{
// Every file is done
$btn_submit_upload.hide();
$btn_reset_uploads.show();
unsaved = false;
}
}
});
My understanding is that chunking is off by default. Have I configured this wrong or am I in the wrong call back?

How to make ajax call on end of each block with infinite scrolling in ag-grid?

I am using ag-grid with angular 4.
I am using infinite scrolling as the rowModelType. But since my data is huge, we want to first call just 100 records in the first ajax call and when the scroll reaches the end, the next ajax call needs to be made with the next 100 records? How can i do this using ag-grid in angular 4.
This is my current code
table-component.ts
export class AssaysTableComponent implements OnInit{
//private rowData;
private gridApi;
private gridColumnApi;
private columnDefs;
private rowModelType;
private paginationPageSize;
private components;
private rowData: any[];
private cacheBlockSize;
private infiniteInitialRowCount;
allTableData : any[];
constructor(private http:HttpClient, private appServices:AppServices) {
this.columnDefs = [
{
headerName: "Date/Time",
field: "createdDate",
headerCheckboxSelection: true,
headerCheckboxSelectionFilteredOnly: true,
checkboxSelection: true,
width: 250,
cellRenderer: "loadingRenderer"
},
{headerName: 'Assay Name', field: 'assayName', width: 200},
{headerName: 'Samples', field: 'sampleCount', width: 100}
];
this.components = {
loadingRenderer: function(params) {
if (params.value !== undefined) {
return params.value;
} else {
return '<img src="../images/loading.gif">';
}
}
};
this.rowModelType = "infinite";
//this.paginationPageSize = 10;
this.cacheBlockSize = 10;
this.infiniteInitialRowCount = 1;
//this.rowData = this.appServices.assayData;
}
ngOnInit(){
}
onGridReady(params) {
this.gridApi = params.api;
this.gridColumnApi = params.columnApi;
//const allTableData:string[] = [];
//const apiCount = 0;
//apiCount++;
console.log("assayApiCall>>",this.appServices.assayApiCall);
const assaysObj = new Assays();
assaysObj.sortBy = 'CREATED_DATE';
assaysObj.sortOder = 'desc';
assaysObj.count = "50";
if(this.appServices.assayApiCall>0){
console.log("this.allTableData >> ",this.allTableData);
assaysObj.startEvalulationKey = {
}
}
this.appServices.downloadAssayFiles(assaysObj).subscribe(
(response) => {
if (response.length > 0) {
var dataSource = {
rowCount: null,
getRows: function (params) {
console.log("asking for " + params.startRow + " to " + params.endRow);
setTimeout(function () {
console.log("response>>",response);
if(this.allTableData == undefined){
this.allTableData = response;
}
else{
this.allTableData = this.allTableData.concat(response);
}
var rowsThisPage = response.slice(params.startRow, params.endRow);
var lastRow = -1;
if (response.length <= params.endRow) {
lastRow = response.length;
}
params.successCallback(rowsThisPage, lastRow);
}, 500);
}
}
params.api.setDatasource(dataSource);
this.appServices.setIsAssaysAvailable(true);
this.appServices.assayApiCall +=1;
}
else{
this.appServices.setIsAssaysAvailable(false)
}
}
)
}
}
I will need to call this.appServices.downloadAssayFiles(assaysObj) at the end of 100 rows again to get the next set of 100 rows.
Please suggest a method of doing this.
Edit 1:
private getRowData(startRow: number, endRow: number): Observable<any[]> {
var rowData =[];
const assaysObj = new Assays();
assaysObj.sortBy = 'CREATED_DATE';
assaysObj.sortOder = 'desc';
assaysObj.count = "10";
this.appServices.downloadAssayFiles(assaysObj).subscribe(
(response) => {
if (response.length > 0) {
console.log("response>>",response);
if(this.allTableData == undefined){
this.allTableData = response;
}
else{
rowData = response;
this.allTableData = this.allTableData.concat(response);
}
this.appServices.setIsAssaysAvailable(true);
}
else{
this.appServices.setIsAssaysAvailable(false)
}
console.log("rowdata>>",rowData);
});
return Observable.of(rowData);
}
onGridReady(params: any) {
console.log("onGridReady");
var dataSource = {
getRows: (params: IGetRowsParams) => {
this.info = "Getting datasource rows, start: " + params.startRow + ", end: " + params.endRow;
console.log(this.info);
this.getRowData(params.startRow, params.endRow)
.subscribe(data => params.successCallback(data));
}
};
params.api.setDatasource(dataSource);
}
Result 1 : The table is not loaded with the data. Also for some reason the service call this.appServices.downloadAssayFiles is being made thrice . Is there something wrong with my logic here.
There's an example of doing exactly this on the ag-grid site: https://www.ag-grid.com/javascript-grid-infinite-scrolling/.
How does your code currently act? It looks like you're modeling yours from the ag-grid docs page, but that you're getting all the data at once instead of getting only the chunks that you need.
Here's a stackblitz that I think does what you need. https://stackblitz.com/edit/ag-grid-infinite-scroll-example?file=src/app/app.component.ts
In general you want to make sure you have a service method that can retrieve just the correct chunk of your data. You seem to be setting the correct range of data to the grid in your code, but the issue is that you've already spent the effort of getting all of it.
Here's the relevant code from that stackblitz. getRowData is the service call that returns an observable of the records that the grid asks for. Then in your subscribe method for that observable, you supply that data to the grid.
private getRowData(startRow: number, endRow: number): Observable<any[]> {
// This is acting as a service call that will return just the
// data range that you're asking for. In your case, you'd probably
// call your http-based service which would also return an observable
// of your data.
var rowdata = [];
for (var i = startRow; i <= endRow; i++) {
rowdata.push({ one: "hello", two: "world", three: "Item " + i });
}
return Observable.of(rowdata);
}
onGridReady(params: any) {
console.log("onGridReady");
var datasource = {
getRows: (params: IGetRowsParams) => {
this.getRowData(params.startRow, params.endRow)
.subscribe(data => params.successCallback(data));
}
};
params.api.setDatasource(datasource);
}

jquery plugin creation issue

I have created a plugin with following codes:
var myplugin = {
init: function(options) {
$.myplugin.settings = $.extend({}, $.myplugin.defaults, options);
},
method1: function(par1) {
.....
},
method2: function(par1) {
.....
}
};
$.myplugin = function(method){
if ( myplugin[method] ) {
return myplugin[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if (typeof method === 'object' || !method) {
return myplugin.init.apply(this, arguments);
} else {
$.error( 'Method "' + method + '" does not exist in myplugin!');
}
};
$.myplugin.defaults = {
option1: 'test',
option2: '',
option3: ''
};
$.myplugin.settings = {};
$.myplugin();
This works well but the issue is that when I try to set more than 1 option and try to return its values afterwards, it gives empty; setting one option works well. For eg.
If on changing the first combo box value I call this:
$.myplugin({option1: 'first test'});
it works, but when I try to call another on second combo box it doesn't save the option, instead it reset to empty.
Is there any fix?
I would re-organize the plugin to use this structure:
var methods = {
settings: {
foo: "foo",
bar: "bar"
},
init: function(options) {
this.settings = $.extend({}, this.settings, options);
},
method1: function(par1) {
alert(this.settings.foo);
},
method2: function(par1) {
alert(this.settings.bar);
}
};
function MyPlugin(options) {
this.init(options);
return this;
}
$.extend(MyPlugin.prototype, methods);
$.myPlugin = function(options) {
return new MyPlugin(options);
}
/* usage */
// without parameters
var obj1 = $.myPlugin();
// with parameters
var obj2 = $.myPlugin({foo: "foobar"});
// each has it's own settings
obj1.method1();
obj2.method1();
Demo: http://jsfiddle.net/ypXdS/
Essentially $.myPlugin simply creates and returns a new instance of the MyPlugin class. You could get rid of it completely and use new myPlugin(options) in it's place.

Resources