mirror of
https://github.com/ascribe/onion.git
synced 2024-12-22 09:23:13 +01:00
Merge pull request #119 from ascribe/AG-109-marketplace-thumbnail-uploader-does-not-use-validation
AG-109 Marketplace thumbnail uploader does not use validation
This commit is contained in:
commit
83eadf8528
11
README.md
11
README.md
@ -48,15 +48,18 @@ For this project, we're using:
|
|||||||
|
|
||||||
Branch names
|
Branch names
|
||||||
=====================
|
=====================
|
||||||
Since we moved to Github, we cannot create branch names automatically with JIRA anymore.
|
|
||||||
To not lose context, but still be able to switch branches quickly using a ticket's number, we're recommending the following rules when naming our branches in onion.
|
To allow Github and JIRA to track branches while still allowing us to switch branches quickly using a ticket's number (and keep our peace of mind), we have the following rules for naming branches:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
// For issues logged in Github:
|
||||||
|
AG-<Github-issue-id>-brief-and-sane-description-of-the-ticket
|
||||||
|
|
||||||
|
// For issues logged in JIRA:
|
||||||
AD-<JIRA-ticket-id>-brief-and-sane-description-of-the-ticket
|
AD-<JIRA-ticket-id>-brief-and-sane-description-of-the-ticket
|
||||||
```
|
```
|
||||||
|
|
||||||
where `brief-and-sane-description-of-the-ticket` does not need to equal to the ticket's title.
|
where `brief-and-sane-description-of-the-ticket` does not need to equal to the issue or ticket's title.
|
||||||
This allows JIRA to still track branches and pull-requests while allowing us to keep our peace of mind.
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
-------------
|
-------------
|
||||||
|
@ -8,6 +8,7 @@ import ReactS3FineUploader from './../ascribe_uploader/react_s3_fine_uploader';
|
|||||||
|
|
||||||
import ApiUrls from '../../constants/api_urls';
|
import ApiUrls from '../../constants/api_urls';
|
||||||
import AppConstants from '../../constants/application_constants';
|
import AppConstants from '../../constants/application_constants';
|
||||||
|
import { validationTypes } from '../../constants/uploader_constants';
|
||||||
|
|
||||||
import { getCookie } from '../../utils/fetch_api_utils';
|
import { getCookie } from '../../utils/fetch_api_utils';
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
@ -15,23 +16,26 @@ import { getLangText } from '../../utils/lang_utils';
|
|||||||
|
|
||||||
let FurtherDetailsFileuploader = React.createClass({
|
let FurtherDetailsFileuploader = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
|
pieceId: React.PropTypes.number.isRequired,
|
||||||
|
|
||||||
|
areAssetsDownloadable: React.PropTypes.bool,
|
||||||
|
editable: React.PropTypes.bool,
|
||||||
|
isReadyForFormSubmission: React.PropTypes.func,
|
||||||
label: React.PropTypes.string,
|
label: React.PropTypes.string,
|
||||||
pieceId: React.PropTypes.number,
|
multiple: React.PropTypes.bool,
|
||||||
otherData: React.PropTypes.arrayOf(React.PropTypes.object),
|
otherData: React.PropTypes.arrayOf(React.PropTypes.object),
|
||||||
|
onValidationFailed: React.PropTypes.func,
|
||||||
setIsUploadReady: React.PropTypes.func,
|
setIsUploadReady: React.PropTypes.func,
|
||||||
submitFile: React.PropTypes.func,
|
submitFile: React.PropTypes.func,
|
||||||
onValidationFailed: React.PropTypes.func,
|
validation: ReactS3FineUploader.propTypes.validation
|
||||||
isReadyForFormSubmission: React.PropTypes.func,
|
|
||||||
editable: React.PropTypes.bool,
|
|
||||||
multiple: React.PropTypes.bool,
|
|
||||||
areAssetsDownloadable: React.PropTypes.bool
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultProps() {
|
getDefaultProps() {
|
||||||
return {
|
return {
|
||||||
areAssetsDownloadable: true,
|
areAssetsDownloadable: true,
|
||||||
label: getLangText('Additional files'),
|
label: getLangText('Additional files'),
|
||||||
multiple: false
|
multiple: false,
|
||||||
|
validation: validationTypes.additionalData
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -61,7 +65,7 @@ let FurtherDetailsFileuploader = React.createClass({
|
|||||||
url: ApiUrls.blob_otherdatas,
|
url: ApiUrls.blob_otherdatas,
|
||||||
pieceId: this.props.pieceId
|
pieceId: this.props.pieceId
|
||||||
}}
|
}}
|
||||||
validation={AppConstants.fineUploader.validation.additionalData}
|
validation={this.props.validation}
|
||||||
submitFile={this.props.submitFile}
|
submitFile={this.props.submitFile}
|
||||||
onValidationFailed={this.props.onValidationFailed}
|
onValidationFailed={this.props.onValidationFailed}
|
||||||
setIsUploadReady={this.props.setIsUploadReady}
|
setIsUploadReady={this.props.setIsUploadReady}
|
||||||
|
@ -2,19 +2,20 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import Form from '../ascribe_forms/form';
|
import ContractListActions from '../../actions/contract_list_actions';
|
||||||
import Property from '../ascribe_forms/property';
|
|
||||||
|
|
||||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||||
|
|
||||||
import ContractListActions from '../../actions/contract_list_actions';
|
|
||||||
|
|
||||||
import AppConstants from '../../constants/application_constants';
|
|
||||||
import ApiUrls from '../../constants/api_urls';
|
|
||||||
|
|
||||||
import InputFineUploader from './input_fineuploader';
|
import InputFineUploader from './input_fineuploader';
|
||||||
|
|
||||||
|
import Form from '../ascribe_forms/form';
|
||||||
|
import Property from '../ascribe_forms/property';
|
||||||
|
|
||||||
|
import ApiUrls from '../../constants/api_urls';
|
||||||
|
import AppConstants from '../../constants/application_constants';
|
||||||
|
import { validationTypes } from '../../constants/uploader_constants';
|
||||||
|
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils';
|
import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils';
|
||||||
|
|
||||||
@ -78,8 +79,8 @@ let CreateContractForm = React.createClass({
|
|||||||
url: ApiUrls.blob_contracts
|
url: ApiUrls.blob_contracts
|
||||||
}}
|
}}
|
||||||
validation={{
|
validation={{
|
||||||
itemLimit: AppConstants.fineUploader.validation.additionalData.itemLimit,
|
itemLimit: validationTypes.additionalData.itemLimit,
|
||||||
sizeLimit: AppConstants.fineUploader.validation.additionalData.sizeLimit,
|
sizeLimit: validationTypes.additionalData.sizeLimit,
|
||||||
allowedExtensions: ['pdf']
|
allowedExtensions: ['pdf']
|
||||||
}}
|
}}
|
||||||
areAssetsDownloadable={true}
|
areAssetsDownloadable={true}
|
||||||
|
@ -8,12 +8,16 @@ import UserActions from '../../actions/user_actions';
|
|||||||
import Form from './form';
|
import Form from './form';
|
||||||
import Property from './property';
|
import Property from './property';
|
||||||
import InputFineUploader from './input_fineuploader';
|
import InputFineUploader from './input_fineuploader';
|
||||||
import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button';
|
|
||||||
import FormSubmitButton from '../ascribe_buttons/form_submit_button';
|
import FormSubmitButton from '../ascribe_buttons/form_submit_button';
|
||||||
|
|
||||||
|
import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button';
|
||||||
|
|
||||||
|
import AscribeSpinner from '../ascribe_spinner';
|
||||||
|
|
||||||
import ApiUrls from '../../constants/api_urls';
|
import ApiUrls from '../../constants/api_urls';
|
||||||
import AppConstants from '../../constants/application_constants';
|
import AppConstants from '../../constants/application_constants';
|
||||||
import AscribeSpinner from '../ascribe_spinner';
|
import { validationParts, validationTypes } from '../../constants/uploader_constants';
|
||||||
|
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
import { mergeOptions } from '../../utils/general_utils';
|
import { mergeOptions } from '../../utils/general_utils';
|
||||||
@ -180,7 +184,7 @@ let RegisterPieceForm = React.createClass({
|
|||||||
createBlobRoutine={{
|
createBlobRoutine={{
|
||||||
url: ApiUrls.blob_digitalworks
|
url: ApiUrls.blob_digitalworks
|
||||||
}}
|
}}
|
||||||
validation={AppConstants.fineUploader.validation.registerWork}
|
validation={validationTypes.registerWork}
|
||||||
setIsUploadReady={this.setIsUploadReady('digitalWorkKeyReady')}
|
setIsUploadReady={this.setIsUploadReady('digitalWorkKeyReady')}
|
||||||
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
|
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
|
||||||
isFineUploaderActive={isFineUploaderActive}
|
isFineUploaderActive={isFineUploaderActive}
|
||||||
@ -206,9 +210,9 @@ let RegisterPieceForm = React.createClass({
|
|||||||
fileClass: 'thumbnail'
|
fileClass: 'thumbnail'
|
||||||
}}
|
}}
|
||||||
validation={{
|
validation={{
|
||||||
itemLimit: AppConstants.fineUploader.validation.workThumbnail.itemLimit,
|
itemLimit: validationTypes.workThumbnail.itemLimit,
|
||||||
sizeLimit: AppConstants.fineUploader.validation.workThumbnail.sizeLimit,
|
sizeLimit: validationTypes.workThumbnail.sizeLimit,
|
||||||
allowedExtensions: ['png', 'jpg', 'jpeg', 'gif']
|
allowedExtensions: validationParts.allowedExtensions.images
|
||||||
}}
|
}}
|
||||||
setIsUploadReady={this.setIsUploadReady('thumbnailKeyReady')}
|
setIsUploadReady={this.setIsUploadReady('thumbnailKeyReady')}
|
||||||
fileClassToUpload={{
|
fileClassToUpload={{
|
||||||
|
@ -28,11 +28,7 @@ const InputFineUploader = React.createClass({
|
|||||||
createBlobRoutine: shape({
|
createBlobRoutine: shape({
|
||||||
url: string
|
url: string
|
||||||
}),
|
}),
|
||||||
validation: shape({
|
validation: ReactS3FineUploader.propTypes.validation,
|
||||||
itemLimit: number,
|
|
||||||
sizeLimit: string,
|
|
||||||
allowedExtensions: arrayOf(string)
|
|
||||||
}),
|
|
||||||
|
|
||||||
// isFineUploaderActive is used to lock react fine uploader in case
|
// isFineUploaderActive is used to lock react fine uploader in case
|
||||||
// a user is actually not logged in already to prevent him from droping files
|
// a user is actually not logged in already to prevent him from droping files
|
||||||
|
@ -2,17 +2,18 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader';
|
|
||||||
import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button';
|
|
||||||
|
|
||||||
import AppConstants from '../../constants/application_constants';
|
|
||||||
import ApiUrls from '../../constants/api_urls';
|
|
||||||
|
|
||||||
import ContractListActions from '../../actions/contract_list_actions';
|
import ContractListActions from '../../actions/contract_list_actions';
|
||||||
|
|
||||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||||
|
|
||||||
|
import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader';
|
||||||
|
import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button';
|
||||||
|
|
||||||
|
import ApiUrls from '../../constants/api_urls';
|
||||||
|
import AppConstants from '../../constants/application_constants';
|
||||||
|
import { validationTypes } from '../../constants/uploader_constants';
|
||||||
|
|
||||||
import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils';
|
import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils';
|
||||||
import { getCookie } from '../../utils/fetch_api_utils';
|
import { getCookie } from '../../utils/fetch_api_utils';
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
@ -68,8 +69,8 @@ let ContractSettingsUpdateButton = React.createClass({
|
|||||||
url: ApiUrls.blob_contracts
|
url: ApiUrls.blob_contracts
|
||||||
}}
|
}}
|
||||||
validation={{
|
validation={{
|
||||||
itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit,
|
itemLimit: validationTypes.registerWork.itemLimit,
|
||||||
sizeLimit: AppConstants.fineUploader.validation.additionalData.sizeLimit,
|
sizeLimit: validationTypes.additionalData.sizeLimit,
|
||||||
allowedExtensions: ['pdf']
|
allowedExtensions: ['pdf']
|
||||||
}}
|
}}
|
||||||
setIsUploadReady={() =>{/* So that ReactS3FineUploader is not complaining */}}
|
setIsUploadReady={() =>{/* So that ReactS3FineUploader is not complaining */}}
|
||||||
|
@ -13,9 +13,9 @@ import GlobalNotificationActions from '../../actions/global_notification_actions
|
|||||||
|
|
||||||
import AppConstants from '../../constants/application_constants';
|
import AppConstants from '../../constants/application_constants';
|
||||||
|
|
||||||
import { computeHashOfFile } from '../../utils/file_utils';
|
|
||||||
import { displayValidFilesFilter, transformAllowedExtensionsToInputAcceptProp } from './react_s3_fine_uploader_utils';
|
import { displayValidFilesFilter, transformAllowedExtensionsToInputAcceptProp } from './react_s3_fine_uploader_utils';
|
||||||
import { getCookie } from '../../utils/fetch_api_utils';
|
import { getCookie } from '../../utils/fetch_api_utils';
|
||||||
|
import { computeHashOfFile, extractFileExtensionFromString } from '../../utils/file_utils';
|
||||||
import { getLangText } from '../../utils/lang_utils';
|
import { getLangText } from '../../utils/lang_utils';
|
||||||
|
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ const ReactS3FineUploader = React.createClass({
|
|||||||
}),
|
}),
|
||||||
validation: shape({
|
validation: shape({
|
||||||
itemLimit: number,
|
itemLimit: number,
|
||||||
sizeLimit: string,
|
sizeLimit: number,
|
||||||
allowedExtensions: arrayOf(string)
|
allowedExtensions: arrayOf(string)
|
||||||
}),
|
}),
|
||||||
messages: shape({
|
messages: shape({
|
||||||
@ -278,22 +278,6 @@ const ReactS3FineUploader = React.createClass({
|
|||||||
this.setState(this.getInitialState());
|
this.setState(this.getInitialState());
|
||||||
},
|
},
|
||||||
|
|
||||||
// Cancel uploads and clear previously selected files on the input element
|
|
||||||
cancelUploads(id) {
|
|
||||||
typeof id !== 'undefined' ? this.state.uploader.cancel(id) : this.state.uploader.cancelAll();
|
|
||||||
|
|
||||||
// Reset the file input element to clear the previously selected files so that
|
|
||||||
// the user can reselect them again.
|
|
||||||
this.clearFileSelection();
|
|
||||||
},
|
|
||||||
|
|
||||||
clearFileSelection() {
|
|
||||||
const { fileInput } = this.refs;
|
|
||||||
if (fileInput && typeof fileInput.clearSelection === 'function') {
|
|
||||||
fileInput.clearSelection();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
requestKey(fileId) {
|
requestKey(fileId) {
|
||||||
let filename = this.state.uploader.getName(fileId);
|
let filename = this.state.uploader.getName(fileId);
|
||||||
let uuid = this.state.uploader.getUuid(fileId);
|
let uuid = this.state.uploader.getUuid(fileId);
|
||||||
@ -384,6 +368,107 @@ const ReactS3FineUploader = React.createClass({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Cancel uploads and clear previously selected files on the input element
|
||||||
|
cancelUploads(id) {
|
||||||
|
typeof id !== 'undefined' ? this.state.uploader.cancel(id) : this.state.uploader.cancelAll();
|
||||||
|
|
||||||
|
// Reset the file input element to clear the previously selected files so that
|
||||||
|
// the user can reselect them again.
|
||||||
|
this.clearFileSelection();
|
||||||
|
},
|
||||||
|
|
||||||
|
clearFileSelection() {
|
||||||
|
const { fileInput } = this.refs;
|
||||||
|
if (fileInput && typeof fileInput.clearSelection === 'function') {
|
||||||
|
fileInput.clearSelection();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getAllowedExtensions() {
|
||||||
|
const { validation: { allowedExtensions } = {} } = this.props;
|
||||||
|
|
||||||
|
if (allowedExtensions && allowedExtensions.length) {
|
||||||
|
return transformAllowedExtensionsToInputAcceptProp(allowedExtensions);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getXhrErrorComment(xhr) {
|
||||||
|
if (xhr) {
|
||||||
|
return {
|
||||||
|
response: xhr.response,
|
||||||
|
url: xhr.responseURL,
|
||||||
|
status: xhr.status,
|
||||||
|
statusText: xhr.statusText
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isDropzoneInactive() {
|
||||||
|
const filesToDisplay = this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1);
|
||||||
|
|
||||||
|
if ((this.props.enableLocalHashing && !this.props.uploadMethod) || !this.props.areAssetsEditable || !this.props.multiple && filesToDisplay.length > 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isFileValid(file) {
|
||||||
|
const { validation: { allowedExtensions, sizeLimit = 0 }, onValidationFailed } = this.props;
|
||||||
|
const fileExt = extractFileExtensionFromString(file.name);
|
||||||
|
|
||||||
|
if (file.size > sizeLimit) {
|
||||||
|
const fileSizeInMegaBytes = sizeLimit / 1000000;
|
||||||
|
|
||||||
|
const notification = new GlobalNotificationModel(getLangText('A file you submitted is bigger than ' + fileSizeInMegaBytes + 'MB.'), 'danger', 5000);
|
||||||
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
|
|
||||||
|
if (typeof onValidationFailed === 'function') {
|
||||||
|
onValidationFailed(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} else if (allowedExtensions && !allowedExtensions.includes(fileExt)) {
|
||||||
|
const notification = new GlobalNotificationModel(getLangText(`The file you've submitted is of an invalid file format: Valid format(s): ${allowedExtensions.join(', ')}`), 'danger', 5000);
|
||||||
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
selectValidFiles(files) {
|
||||||
|
return Array.from(files).reduce((validFiles, file) => {
|
||||||
|
if (this.isFileValid(file)) {
|
||||||
|
validFiles.push(file);
|
||||||
|
}
|
||||||
|
return validFiles;
|
||||||
|
}, []);
|
||||||
|
},
|
||||||
|
|
||||||
|
// This method has been made promise-based to immediately afterwards
|
||||||
|
// call a callback function (instantly after this.setState went through)
|
||||||
|
// This is e.g. needed when showing/hiding the optional thumbnail upload
|
||||||
|
// field in the registration form
|
||||||
|
setStatusOfFile(fileId, status) {
|
||||||
|
return Q.Promise((resolve) => {
|
||||||
|
let changeSet = {};
|
||||||
|
|
||||||
|
if(status === 'deleted' || status === 'canceled') {
|
||||||
|
changeSet.progress = { $set: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
changeSet.status = { $set: status };
|
||||||
|
|
||||||
|
let filesToUpload = React.addons.update(this.state.filesToUpload, { [fileId]: changeSet });
|
||||||
|
|
||||||
|
this.setState({ filesToUpload }, resolve);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
setThumbnailForFileId(fileId, url) {
|
setThumbnailForFileId(fileId, url) {
|
||||||
const { filesToUpload } = this.state;
|
const { filesToUpload } = this.state;
|
||||||
|
|
||||||
@ -506,34 +591,6 @@ const ReactS3FineUploader = React.createClass({
|
|||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||||
},
|
},
|
||||||
|
|
||||||
getXhrErrorComment(xhr) {
|
|
||||||
if (xhr) {
|
|
||||||
return {
|
|
||||||
response: xhr.response,
|
|
||||||
url: xhr.responseURL,
|
|
||||||
status: xhr.status,
|
|
||||||
statusText: xhr.statusText
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
isFileValid(file) {
|
|
||||||
if (file.size > this.props.validation.sizeLimit) {
|
|
||||||
const fileSizeInMegaBytes = this.props.validation.sizeLimit / 1000000;
|
|
||||||
|
|
||||||
const notification = new GlobalNotificationModel(getLangText('A file you submitted is bigger than ' + fileSizeInMegaBytes + 'MB.'), 'danger', 5000);
|
|
||||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
|
||||||
|
|
||||||
if (typeof this.props.onValidationFailed === 'function') {
|
|
||||||
this.props.onValidationFailed(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onCancel(id) {
|
onCancel(id) {
|
||||||
// when a upload is canceled, we need to update this components file array
|
// when a upload is canceled, we need to update this components file array
|
||||||
this.setStatusOfFile(id, 'canceled')
|
this.setStatusOfFile(id, 'canceled')
|
||||||
@ -670,6 +727,13 @@ const ReactS3FineUploader = React.createClass({
|
|||||||
this.cancelUploads(fileId);
|
this.cancelUploads(fileId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleCancelHashing() {
|
||||||
|
// Every progress tick of the hashing function in handleUploadFile there is a
|
||||||
|
// check if this.state.hashingProgress is -1. If so, there is an error thrown that cancels
|
||||||
|
// the hashing of all files immediately.
|
||||||
|
this.setState({ hashingProgress: -1 });
|
||||||
|
},
|
||||||
|
|
||||||
handlePauseFile(fileId) {
|
handlePauseFile(fileId) {
|
||||||
if(this.state.uploader.pauseUpload(fileId)) {
|
if(this.state.uploader.pauseUpload(fileId)) {
|
||||||
this.setStatusOfFile(fileId, 'paused');
|
this.setStatusOfFile(fileId, 'paused');
|
||||||
@ -698,15 +762,8 @@ const ReactS3FineUploader = React.createClass({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate each submitted file if it fits the file size
|
// Select only the submitted files that fit the file size and allowed extensions
|
||||||
let validFiles = [];
|
files = this.selectValidFiles(files);
|
||||||
for(let i = 0; i < files.length; i++) {
|
|
||||||
if(this.isFileValid(files[i])) {
|
|
||||||
validFiles.push(files[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// override standard files list with only valid files
|
|
||||||
files = validFiles;
|
|
||||||
|
|
||||||
// if multiple is set to false and user drops multiple files into the dropzone,
|
// if multiple is set to false and user drops multiple files into the dropzone,
|
||||||
// take the first one and notify user that only one file can be submitted
|
// take the first one and notify user that only one file can be submitted
|
||||||
@ -817,13 +874,6 @@ const ReactS3FineUploader = React.createClass({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleCancelHashing() {
|
|
||||||
// Every progress tick of the hashing function in handleUploadFile there is a
|
|
||||||
// check if this.state.hashingProgress is -1. If so, there is an error thrown that cancels
|
|
||||||
// the hashing of all files immediately.
|
|
||||||
this.setState({ hashingProgress: -1 });
|
|
||||||
},
|
|
||||||
|
|
||||||
// ReactFineUploader is essentially just a react layer around s3 fineuploader.
|
// ReactFineUploader is essentially just a react layer around s3 fineuploader.
|
||||||
// However, since we need to display the status of a file (progress, uploading) as well as
|
// However, since we need to display the status of a file (progress, uploading) as well as
|
||||||
// be able to execute actions on a currently uploading file we need to exactly sync the file list
|
// be able to execute actions on a currently uploading file we need to exactly sync the file list
|
||||||
@ -893,46 +943,6 @@ const ReactS3FineUploader = React.createClass({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// This method has been made promise-based to immediately afterwards
|
|
||||||
// call a callback function (instantly after this.setState went through)
|
|
||||||
// This is e.g. needed when showing/hiding the optional thumbnail upload
|
|
||||||
// field in the registration form
|
|
||||||
setStatusOfFile(fileId, status) {
|
|
||||||
return Q.Promise((resolve) => {
|
|
||||||
let changeSet = {};
|
|
||||||
|
|
||||||
if(status === 'deleted' || status === 'canceled') {
|
|
||||||
changeSet.progress = { $set: 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
changeSet.status = { $set: status };
|
|
||||||
|
|
||||||
let filesToUpload = React.addons.update(this.state.filesToUpload, { [fileId]: changeSet });
|
|
||||||
|
|
||||||
this.setState({ filesToUpload }, resolve);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
isDropzoneInactive() {
|
|
||||||
const filesToDisplay = this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1);
|
|
||||||
|
|
||||||
if ((this.props.enableLocalHashing && !this.props.uploadMethod) || !this.props.areAssetsEditable || !this.props.multiple && filesToDisplay.length > 0) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getAllowedExtensions() {
|
|
||||||
let { validation } = this.props;
|
|
||||||
|
|
||||||
if(validation && validation.allowedExtensions && validation.allowedExtensions.length > 0) {
|
|
||||||
return transformAllowedExtensionsToInputAcceptProp(validation.allowedExtensions);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
multiple,
|
multiple,
|
||||||
|
@ -3,19 +3,21 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { History } from 'react-router';
|
import { History } from 'react-router';
|
||||||
|
|
||||||
|
import GlobalNotificationModel from '../../../../../../models/global_notification_model';
|
||||||
|
import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
|
||||||
|
|
||||||
import Form from '../../../../../ascribe_forms/form';
|
import Form from '../../../../../ascribe_forms/form';
|
||||||
import Property from '../../../../../ascribe_forms/property';
|
import Property from '../../../../../ascribe_forms/property';
|
||||||
import InputTextAreaToggable from '../../../../../ascribe_forms/input_textarea_toggable';
|
import InputTextAreaToggable from '../../../../../ascribe_forms/input_textarea_toggable';
|
||||||
|
|
||||||
import UploadButton from '../../../../../ascribe_uploader/ascribe_upload_button/upload_button';
|
|
||||||
import InputFineuploader from '../../../../../ascribe_forms/input_fineuploader';
|
import InputFineuploader from '../../../../../ascribe_forms/input_fineuploader';
|
||||||
|
import UploadButton from '../../../../../ascribe_uploader/ascribe_upload_button/upload_button';
|
||||||
|
|
||||||
import AscribeSpinner from '../../../../../ascribe_spinner';
|
import AscribeSpinner from '../../../../../ascribe_spinner';
|
||||||
|
|
||||||
import GlobalNotificationModel from '../../../../../../models/global_notification_model';
|
|
||||||
import GlobalNotificationActions from '../../../../../../actions/global_notification_actions';
|
|
||||||
|
|
||||||
import AppConstants from '../../../../../../constants/application_constants';
|
|
||||||
import ApiUrls from '../../../../../../constants/api_urls';
|
import ApiUrls from '../../../../../../constants/api_urls';
|
||||||
|
import AppConstants from '../../../../../../constants/application_constants';
|
||||||
|
import { validationParts, validationTypes } from '../../../../../../constants/uploader_constants';
|
||||||
|
|
||||||
import requests from '../../../../../../utils/requests';
|
import requests from '../../../../../../utils/requests';
|
||||||
|
|
||||||
@ -193,7 +195,7 @@ const PRRegisterPieceForm = React.createClass({
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { location } = this.props;
|
const { location } = this.props;
|
||||||
const maxThumbnailSize = AppConstants.fineUploader.validation.workThumbnail.sizeLimit / 1000000;
|
const maxThumbnailSize = validationTypes.workThumbnail.sizeLimit / 1000000;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="register-piece--form">
|
<div className="register-piece--form">
|
||||||
@ -305,8 +307,8 @@ const PRRegisterPieceForm = React.createClass({
|
|||||||
fileClass: 'digitalwork'
|
fileClass: 'digitalwork'
|
||||||
}}
|
}}
|
||||||
validation={{
|
validation={{
|
||||||
itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit,
|
itemLimit: validationTypes.registerWork.itemLimit,
|
||||||
sizeLimit: AppConstants.fineUploader.validation.additionalData.sizeLimit,
|
sizeLimit: validationTypes.additionalData.sizeLimit,
|
||||||
allowedExtensions: ['pdf']
|
allowedExtensions: ['pdf']
|
||||||
}}
|
}}
|
||||||
location={location}
|
location={location}
|
||||||
@ -318,7 +320,7 @@ const PRRegisterPieceForm = React.createClass({
|
|||||||
</Property>
|
</Property>
|
||||||
<Property
|
<Property
|
||||||
name="thumbnailKey"
|
name="thumbnailKey"
|
||||||
label={`${getLangText('Featured Cover photo')} max ${maxThumbnailSize}MB`}>
|
label={`${getLangText('Featured Cover photo')} (max ${maxThumbnailSize}MB)`}>
|
||||||
<InputFineuploader
|
<InputFineuploader
|
||||||
fileInputElement={UploadButton()}
|
fileInputElement={UploadButton()}
|
||||||
createBlobRoutine={{
|
createBlobRoutine={{
|
||||||
@ -331,9 +333,9 @@ const PRRegisterPieceForm = React.createClass({
|
|||||||
fileClass: 'thumbnail'
|
fileClass: 'thumbnail'
|
||||||
}}
|
}}
|
||||||
validation={{
|
validation={{
|
||||||
itemLimit: AppConstants.fineUploader.validation.workThumbnail.itemLimit,
|
itemLimit: validationTypes.workThumbnail.itemLimit,
|
||||||
sizeLimit: AppConstants.fineUploader.validation.workThumbnail.sizeLimit,
|
sizeLimit: validationTypes.workThumbnail.sizeLimit,
|
||||||
allowedExtensions: ['png', 'jpg', 'jpeg', 'gif']
|
allowedExtensions: validationParts.allowedExtensions.images
|
||||||
}}
|
}}
|
||||||
location={location}
|
location={location}
|
||||||
fileClassToUpload={{
|
fileClassToUpload={{
|
||||||
@ -356,8 +358,8 @@ const PRRegisterPieceForm = React.createClass({
|
|||||||
fileClass: 'otherdata'
|
fileClass: 'otherdata'
|
||||||
}}
|
}}
|
||||||
validation={{
|
validation={{
|
||||||
itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit,
|
itemLimit: validationParts.itemLimit.single,
|
||||||
sizeLimit: AppConstants.fineUploader.validation.additionalData.sizeLimit
|
sizeLimit: validationTypes.additionalData.sizeLimit
|
||||||
}}
|
}}
|
||||||
location={location}
|
location={location}
|
||||||
fileClassToUpload={{
|
fileClassToUpload={{
|
||||||
@ -378,9 +380,9 @@ const PRRegisterPieceForm = React.createClass({
|
|||||||
fileClass: 'otherdata'
|
fileClass: 'otherdata'
|
||||||
}}
|
}}
|
||||||
validation={{
|
validation={{
|
||||||
itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit,
|
itemLimit: validationParts.itemLimit.single,
|
||||||
sizeLimit: AppConstants.fineUploader.validation.additionalData.sizeLimit,
|
sizeLimit: validationTypes.additionalData.sizeLimit,
|
||||||
allowedExtensions: ['png', 'jpg', 'jpeg', 'gif']
|
allowedExtensions: validationParts.allowedExtensions.images
|
||||||
}}
|
}}
|
||||||
location={location}
|
location={location}
|
||||||
fileClassToUpload={{
|
fileClassToUpload={{
|
||||||
|
@ -11,14 +11,14 @@ import InputTextAreaToggable from '../../../../../ascribe_forms/input_textarea_t
|
|||||||
import Form from '../../../../../ascribe_forms/form';
|
import Form from '../../../../../ascribe_forms/form';
|
||||||
import Property from '../../../../../ascribe_forms/property';
|
import Property from '../../../../../ascribe_forms/property';
|
||||||
|
|
||||||
import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils';
|
|
||||||
|
|
||||||
import AscribeSpinner from '../../../../../ascribe_spinner';
|
import AscribeSpinner from '../../../../../ascribe_spinner';
|
||||||
|
|
||||||
import ApiUrls from '../../../../../../constants/api_urls';
|
import ApiUrls from '../../../../../../constants/api_urls';
|
||||||
import AppConstants from '../../../../../../constants/application_constants';
|
import { validationParts, validationTypes } from '../../../../../../constants/uploader_constants';
|
||||||
|
|
||||||
import requests from '../../../../../../utils/requests';
|
import requests from '../../../../../../utils/requests';
|
||||||
|
|
||||||
|
import { formSubmissionValidation } from '../../../../../ascribe_uploader/react_s3_fine_uploader_utils';
|
||||||
import { mergeOptions } from '../../../../../../utils/general_utils';
|
import { mergeOptions } from '../../../../../../utils/general_utils';
|
||||||
import { getLangText } from '../../../../../../utils/lang_utils';
|
import { getLangText } from '../../../../../../utils/lang_utils';
|
||||||
|
|
||||||
@ -170,7 +170,12 @@ let MarketAdditionalDataForm = React.createClass({
|
|||||||
otherData={otherData}
|
otherData={otherData}
|
||||||
pieceId={pieceId}
|
pieceId={pieceId}
|
||||||
setIsUploadReady={this.setIsUploadReady}
|
setIsUploadReady={this.setIsUploadReady}
|
||||||
submitFile={function () {}} />
|
submitFile={function () {}}
|
||||||
|
validation={{
|
||||||
|
itemLimit: validationTypes.workThumbnail.itemLimit,
|
||||||
|
sizeLimit: validationTypes.workThumbnail.sizeLimit,
|
||||||
|
allowedExtensions: validationParts.allowedExtensions.images
|
||||||
|
}} />
|
||||||
<Property
|
<Property
|
||||||
name='artist_bio'
|
name='artist_bio'
|
||||||
label={getLangText('Artist Bio')}
|
label={getLangText('Artist Bio')}
|
||||||
|
@ -68,23 +68,6 @@ const constants = {
|
|||||||
// Source: http://www.w3schools.com/tags/att_input_type.asp
|
// Source: http://www.w3schools.com/tags/att_input_type.asp
|
||||||
'possibleInputTypes': ['button', 'checkbox', 'color', 'date', 'datetime', 'datetime-local', 'email', 'file', 'hidden', 'image', 'month', 'number', 'password', 'radio', 'range', 'reset', 'search', 'submit', 'tel', 'text', 'time', 'url', 'week'],
|
'possibleInputTypes': ['button', 'checkbox', 'color', 'date', 'datetime', 'datetime-local', 'email', 'file', 'hidden', 'image', 'month', 'number', 'password', 'radio', 'range', 'reset', 'search', 'submit', 'tel', 'text', 'time', 'url', 'week'],
|
||||||
|
|
||||||
'fineUploader': {
|
|
||||||
'validation': {
|
|
||||||
'additionalData': {
|
|
||||||
'itemLimit': 100,
|
|
||||||
'sizeLimit': '25000000000'
|
|
||||||
},
|
|
||||||
'registerWork': {
|
|
||||||
'itemLimit': 1,
|
|
||||||
'sizeLimit': '25000000000'
|
|
||||||
},
|
|
||||||
'workThumbnail': {
|
|
||||||
'itemLimit': 1,
|
|
||||||
'sizeLimit': '5000000'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
'copyrightAssociations': ['ARS', 'DACS', 'Bildkunst', 'Pictoright', 'SODRAC', 'Copyright Agency/Viscopy', 'SAVA',
|
'copyrightAssociations': ['ARS', 'DACS', 'Bildkunst', 'Pictoright', 'SODRAC', 'Copyright Agency/Viscopy', 'SAVA',
|
||||||
'Bildrecht GmbH', 'SABAM', 'AUTVIS', 'CREAIMAGEN', 'SONECA', 'Copydan', 'EAU', 'Kuvasto', 'GCA', 'HUNGART',
|
'Bildrecht GmbH', 'SABAM', 'AUTVIS', 'CREAIMAGEN', 'SONECA', 'Copydan', 'EAU', 'Kuvasto', 'GCA', 'HUNGART',
|
||||||
'IVARO', 'SIAE', 'JASPAR-SPDA', 'AKKA/LAA', 'LATGA-A', 'SOMAAP', 'ARTEGESTION', 'CARIER', 'BONO', 'APSAV',
|
'IVARO', 'SIAE', 'JASPAR-SPDA', 'AKKA/LAA', 'LATGA-A', 'SOMAAP', 'ARTEGESTION', 'CARIER', 'BONO', 'APSAV',
|
||||||
|
32
js/constants/uploader_constants.js
Normal file
32
js/constants/uploader_constants.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
export const validationParts = {
|
||||||
|
allowedExtensions: {
|
||||||
|
images: ['png', 'jpg', 'jpeg', 'gif']
|
||||||
|
},
|
||||||
|
itemLimit: {
|
||||||
|
single: 1,
|
||||||
|
multiple: 100
|
||||||
|
},
|
||||||
|
sizeLimit: {
|
||||||
|
default: 25000000000,
|
||||||
|
thumbnail: 5000000
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const { allowedExtensions, itemLimit, sizeLimit } = validationParts;
|
||||||
|
|
||||||
|
export const validationTypes = {
|
||||||
|
additionalData: {
|
||||||
|
itemLimit: itemLimit.multiple,
|
||||||
|
sizeLimit: sizeLimit.default
|
||||||
|
},
|
||||||
|
registerWork: {
|
||||||
|
itemLimit: itemLimit.single,
|
||||||
|
sizeLimit: sizeLimit.default
|
||||||
|
},
|
||||||
|
workThumbnail: {
|
||||||
|
itemLimit: itemLimit.single,
|
||||||
|
sizeLimit: sizeLimit.thumbnail
|
||||||
|
}
|
||||||
|
};
|
@ -78,7 +78,7 @@ export function computeHashOfFile(file) {
|
|||||||
progress: start / file.size,
|
progress: start / file.size,
|
||||||
reject
|
reject
|
||||||
});
|
});
|
||||||
|
|
||||||
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
|
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,4 +101,4 @@ export function extractFileExtensionFromString(s) {
|
|||||||
const explodedFileName = s.split('.');
|
const explodedFileName = s.split('.');
|
||||||
return explodedFileName.length > 1 ? explodedFileName.pop()
|
return explodedFileName.length > 1 ? explodedFileName.pop()
|
||||||
: '';
|
: '';
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
transition: .2s bottom cubic-bezier(.77, 0, .175, 1);
|
transition: .2s bottom cubic-bezier(.77, 0, .175, 1);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ascribe-global-notification-off {
|
.ascribe-global-notification-off {
|
||||||
@ -37,6 +39,8 @@
|
|||||||
right: -50em;
|
right: -50em;
|
||||||
transition: 1s right ease;
|
transition: 1s right ease;
|
||||||
|
|
||||||
|
z-index: 9999;
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
padding: .75em 1.5em;
|
padding: .75em 1.5em;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user