diff --git a/public/assets/js/publishFileFunctions.js b/public/assets/js/publishFileFunctions.js
index 4ce63d0c..425d3094 100644
--- a/public/assets/js/publishFileFunctions.js
+++ b/public/assets/js/publishFileFunctions.js
@@ -9,103 +9,7 @@ const publishFileFunctions = {
}
return null;
},
- createMetadata: function() {
- const nameInput = document.getElementById('claim-name-input');
- const titleInput = document.getElementById('publish-title');
- const descriptionInput = document.getElementById('publish-description');
- const licenseInput = document.getElementById('publish-license');
- const nsfwInput = document.getElementById('publish-nsfw');
- const thumbnailInput = document.getElementById('claim-thumbnail-input');
- const channelName = this.returnNullOrChannel();
- let metadata = {
- name: nameInput.value.trim(),
- title: titleInput.value.trim(),
- description: descriptionInput.value.trim(),
- license: licenseInput.value.trim(),
- nsfw: nsfwInput.checked,
- type: stagedFiles[0].type,
- thumbnail: thumbnailInput.value.trim(),
- };
- if (channelName) {
- metadata['channelName'] = channelName;
- }
- return metadata;
- },
- appendDataToFormData: function (file, metadata) {
- var fd = new FormData();
- fd.append('file', file)
- for (var key in metadata) {
- if (metadata.hasOwnProperty(key)) {
- console.log(key, metadata[key]);
- fd.append(key, metadata[key]);
- }
- }
- return fd;
- },
- publishFile: function (file, metadata) {
- var uri = "/api/claim-publish";
- var xhr = new XMLHttpRequest();
- var fd = this.appendDataToFormData(file, metadata);
- var that = this;
- xhr.upload.addEventListener("loadstart", function(e) {
- that.showUploadStartedMessage();
- })
- xhr.upload.addEventListener("progress", function(e) {
- if (e.lengthComputable) {
- var percentage = Math.round((e.loaded * 100) / e.total);
- console.log('progress:', percentage);
- that.showUploadProgressMessage(percentage);
- }
- }, false);
- xhr.upload.addEventListener("load", function(e){
- console.log('loaded 100%');
- that.showFilePublishUpdate("Your file has been loaded, and is now being published to the blockchain. Sit tight...")
- }, false);
- xhr.open("POST", uri, true);
- xhr.onreadystatechange = function() {
- if (xhr.readyState == 4) {
- console.log('publish response:', xhr.response)
- if (xhr.status == 200) {
- console.log('publish complete!');
- that.showFilePublishComplete(JSON.parse(xhr.response).message);
- } else if (xhr.status == 502){
- that.showFilePublishFailure('Spee.ch was not able to get a response from the LBRY network.');
- } else {
- that.showFilePublishFailure(JSON.parse(xhr.response).message);
- }
- }
- };
- // Initiate a multipart/form-data upload
- xhr.send(fd);
- },
// Validate the publish submission and then trigger upload
- publishStagedFile: function (event) {
- event.preventDefault(); // prevent default so this script can handle submission
- const metadata = this.createMetadata();
- const that = this;
- const fileSelectionInputError = document.getElementById('input-error-file-selection');
- const claimNameError = document.getElementById('input-error-claim-name');
- const channelSelectError = document.getElementById('input-error-channel-select');
- const publishSubmitError = document.getElementById('input-error-publish-submit');
- // validate, submit, and handle response
- validationFunctions.validateFilePublishSubmission(stagedFiles, metadata)
- .then( function() {
- that.publishFile(stagedFiles[0], metadata);
- })
- .catch(error => {
- if (error.name === 'FileError') {
- validationFunctions.showError(fileSelectionInputError, error.message);
- } else if (error.name === 'NameError') {
- validationFunctions.showError(claimNameError, error.message);
- } else if (error.name === 'ChannelNameError'){
- console.log(error);
- validationFunctions.showError(channelSelectError, error.message);
- } else {
- validationFunctions.showError(publishSubmitError, error.message);
- }
- return;
- })
- },
showUploadStartedMessage: function (){
console.log('starting upload');
// hide the publish tool
diff --git a/public/assets/js/validationFunctions.js b/public/assets/js/validationFunctions.js
index d9a9c9d0..97f46862 100644
--- a/public/assets/js/validationFunctions.js
+++ b/public/assets/js/validationFunctions.js
@@ -1,53 +1,5 @@
// validation function which checks the proposed file's type, size, and name
const validationFunctions = {
- validateFile: function (file) {
- if (!file) {
- console.log('no file found');
- throw new Error('no file provided');
- }
- if (/'/.test(file.name)) {
- console.log('file name had apostrophe in it');
- throw new Error('apostrophes are not allowed in the file name');
- }
- // validate size and type
- switch (file.type) {
- case 'image/jpeg':
- case 'image/jpg':
- case 'image/png':
- if (file.size > 10000000) {
- console.log('file was too big');
- throw new Error('Sorry, images are limited to 10 megabytes.');
- }
- break;
- case 'image/gif':
- if (file.size > 50000000) {
- console.log('file was too big');
- throw new Error('Sorry, .gifs are limited to 50 megabytes.');
- }
- break;
- case 'video/mp4':
- if (file.size > 50000000) {
- console.log('file was too big');
- throw new Error('Sorry, videos are limited to 50 megabytes.');
- }
- break;
- default:
- console.log('file type is not supported');
- throw new Error(file.type + ' is not a supported file type. Only, .jpeg, .png, .gif, and .mp4 files are currently supported.')
- }
- },
- // validation function that checks to make sure the claim name is valid
- validateClaimName: function (name) {
- // ensure a name was entered
- if (name.length < 1) {
- throw new NameError("You must enter a name for your url");
- }
- // validate the characters in the 'name' field
- const invalidCharacters = /[^A-Za-z0-9,-]/g.exec(name);
- if (invalidCharacters) {
- throw new NameError('"' + invalidCharacters + '" characters are not allowed');
- }
- },
validateChannelName: function (name) {
name = name.substring(name.indexOf('@') + 1);
// ensure a name was entered
@@ -117,54 +69,6 @@ const validationFunctions = {
name = `@${name}`;
this.checkAvailability(name, successDisplayElement, errorDisplayElement, this.validateChannelName, 'Sorry, that name is already taken', '/api/channel-is-available/');
},
- // validation function which checks all aspects of the publish submission
- validateFilePublishSubmission: function (stagedFiles, metadata) {
- const channelName = metadata.channelName;
- const claimName = metadata.name;
- var that = this;
- return new Promise(function (resolve, reject) {
- // 1. make sure 1 file was staged
- if (!stagedFiles) {
- reject(new FileError("Please select a file"));
- return;
- } else if (stagedFiles.length > 1) {
- reject(new FileError("Only one file is allowed at a time"));
- return;
- }
- // 2. validate the file's name, type, and size
- try {
- that.validateFile(stagedFiles[0]);
- } catch (error) {
- reject(error);
- return;
- }
- // 3. validate that a channel was chosen
- if (channelName === 'new' || channelName === 'login') {
- reject(new ChannelNameError("Please log in to a channel"));
- return;
- }
- ;
- // 4. validate the claim name
- try {
- that.validateClaimName(claimName);
- } catch (error) {
- reject(error);
- return;
- }
- // if all validation passes, check availability of the name (note: do we need to re-validate channel name vs. credentials as well?)
- return that.isNameAvailable(claimName, '/api/claim-is-available/')
- .then(result => {
- if (result) {
- resolve();
- } else {
- reject(new NameError('Sorry, that ending is already taken'));
- }
- })
- .catch(error => {
- reject(error);
- });
- });
- },
// validation function which checks all aspects of a new channel submission
validateNewChannelSubmission: function (userName, password) {
const channelName = `@${userName}`;
diff --git a/react/actions/index.js b/react/actions/index.js
index 4bed823d..45926bd1 100644
--- a/react/actions/index.js
+++ b/react/actions/index.js
@@ -5,6 +5,7 @@ export const METADATA_UPDATE = 'METADATA_UPDATE';
export const CLAIM_UPDATE = 'CLAIM_UPDATE';
export const CHANNEL_UPDATE = 'CHANNEL_UPDATE';
export const SET_PUBLISH_IN_CHANNEL = 'SET_PUBLISH_IN_CHANNEL';
+export const PUBLISH_STATUS_UPDATE = 'PUBLISH_STATUS_UPDATE';
// export action creators
export function selectFile (file) {
@@ -44,9 +45,16 @@ export function updateLoggedInChannel (name, shortId, longId) {
};
};
-export function setPublishInChannel (value) {
+export function setPublishInChannel (channel) {
return {
type: SET_PUBLISH_IN_CHANNEL,
- value,
+ channel,
};
-}
+};
+
+export function updatePublishStatus (status) {
+ return {
+ type: PUBLISH_STATUS_UPDATE,
+ status,
+ };
+};
diff --git a/react/components/Preview.jsx b/react/components/Preview.jsx
index e6a8248f..23bd19e2 100644
--- a/react/components/Preview.jsx
+++ b/react/components/Preview.jsx
@@ -18,7 +18,6 @@ class Preview extends React.Component {
this.previewFile(newProps.file);
}
previewFile (file) {
- console.log('previewFile', file)
const that = this;
if (file.type !== 'video/mp4') {
const previewReader = new FileReader();
diff --git a/react/containers/PublishForm.jsx b/react/containers/PublishForm.jsx
index 8c211313..81b9451c 100644
--- a/react/containers/PublishForm.jsx
+++ b/react/containers/PublishForm.jsx
@@ -6,18 +6,19 @@ import PublishUrlInput from './PublishUrlInput.jsx';
import PublishThumbnailInput from './PublishThumbnailInput.jsx';
import PublishMetadataInputs from './PublishMetadataInputs.jsx';
import AnonymousOrChannelSelect from './AnonymousOrChannelSelect.jsx';
-
-import { selectFile, clearFile, updateLoggedInChannel } from '../actions/index';
import { connect } from 'react-redux';
import { getCookie } from '../utils/cookies.js';
+import { selectFile, clearFile, updateLoggedInChannel, updatePublishStatus } from '../actions';
class PublishForm extends React.Component {
constructor (props) {
super(props);
// set defaults
this.state = {
- error: null,
+ publishRequestError: null,
};
+ this.validatePublishRequest = this.validatePublishRequest.bind(this);
+ this.makePublishRequest = this.makePublishRequest.bind(this);
this.publish = this.publish.bind(this);
}
componentWillMount () {
@@ -28,8 +29,102 @@ class PublishForm extends React.Component {
console.log(`channel cookies found: ${loggedInChannelName} ${loggedInChannelShortId} ${loggedInChannelLongId}`);
this.props.onChannelLogin(loggedInChannelName, loggedInChannelShortId, loggedInChannelLongId);
}
+ validatePublishRequest () {
+ // make sure all required data is provided
+ return new Promise((resolve, reject) => {
+ // is there a file?
+ if (!this.props.file) {
+ return reject(new Error('Please choose a file'));
+ }
+ // is there a claim chosen?
+ if (!this.props.claim) {
+ return reject(new Error('Please enter a claim name'));
+ }
+ // if publishInChannel is true, is a channel logged in (or selected)
+ if (this.props.publishInChannel && !this.props.loggedInChannel.name) {
+ return reject(new Error('Select Anonymous or log in to a channel'));
+ }
+ // tbd: is the claim available?
+ resolve();
+ });
+ }
+ makePublishRequest (file, metadata) {
+ const uri = '/api/claim-publish';
+ const xhr = new XMLHttpRequest();
+ const fd = this.appendDataToFormData(file, metadata);
+ const that = this;
+ xhr.upload.addEventListener('loadstart', function () {
+ that.props.onPublishStatusChange('upload started');
+ });
+ xhr.upload.addEventListener('progress', function (e) {
+ if (e.lengthComputable) {
+ const percentage = Math.round((e.loaded * 100) / e.total);
+ that.props.onPublishStatusChange(`upload progress: ${percentage}%`);
+ console.log('progress:', percentage);
+ }
+ }, false);
+ xhr.upload.addEventListener('load', function () {
+ console.log('loaded 100%');
+ that.props.onPublishStatusChange(`Upload complete. Your file is now being published on the blockchain...`);
+ }, false);
+ xhr.open('POST', uri, true);
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState === 4) {
+ console.log('publish response:', xhr.response);
+ if (xhr.status === 200) {
+ console.log('publish complete!');
+ that.props.onPublishStatusChange(JSON.parse(xhr.response).message);
+ } else if (xhr.status === 502) {
+ that.props.onPublishStatusChange('Spee.ch was not able to get a response from the LBRY network.');
+ } else {
+ that.props.onPublishStatusChange(JSON.parse(xhr.response).message);
+ }
+ }
+ };
+ // Initiate a multipart/form-data upload
+ xhr.send(fd);
+ }
+ createMetadata () {
+ let metadata = {
+ name : this.props.claim,
+ title : this.props.title,
+ description: this.props.description,
+ license : this.props.license,
+ nsfw : this.props.nsfw,
+ type : this.props.file.type,
+ thumbnail : this.props.thumbnail,
+ };
+ if (this.props.publishInChannel) {
+ metadata['channelName'] = this.props.loggedInChannel.name;
+ }
+ return metadata;
+ }
+ appendDataToFormData (file, metadata) {
+ var fd = new FormData();
+ fd.append('file', file);
+ for (var key in metadata) {
+ if (metadata.hasOwnProperty(key)) {
+ console.log(key, metadata[key]);
+ fd.append(key, metadata[key]);
+ }
+ }
+ return fd;
+ }
publish () {
// publish the asset
+ const that = this;
+ this.validatePublishRequest()
+ .then(() => {
+ const metadata = that.createMetadata();
+ // publish the claim
+ return that.makePublishRequest(this.props.file, metadata);
+ })
+ .then(() => {
+ that.props.onPublishStatusChange('publish request made');
+ })
+ .catch((error) => {
+ that.setState({publishRequestError: error.message});
+ });
}
render () {
return (
@@ -61,14 +156,18 @@ class PublishForm extends React.Component {