diff --git a/client/src/actions/publish.js b/client/src/actions/publish.js index 91e44fd5..552e2aff 100644 --- a/client/src/actions/publish.js +++ b/client/src/actions/publish.js @@ -14,19 +14,6 @@ export function clearFile () { }; } -export function setUpdateTrue () { - return { - type: actions.SET_UPDATE_TRUE, - }; -} - -export function setHasChanged (status) { - return { - type: actions.SET_HAS_CHANGED, - data: status, - }; -} - export function updateMetadata (name, value) { return { type: actions.METADATA_UPDATE, @@ -44,13 +31,6 @@ export function updateClaim (value) { }; }; -export function abandonClaim (data) { - return { - type: actions.ABANDON_CLAIM, - data, - }; -}; - export function setPublishInChannel (channel) { return { type: actions.SET_PUBLISH_IN_CHANNEL, diff --git a/client/src/actions/show.js b/client/src/actions/show.js index 807d4f02..1bac1310 100644 --- a/client/src/actions/show.js +++ b/client/src/actions/show.js @@ -105,13 +105,6 @@ export function updateAssetViewsInList (id, claimId, claimViews) { }; } -export function removeAsset (data) { - return { - type: actions.ASSET_REMOVE, - data, - }; -} - // channel actions export function addNewChannelToChannelList (id, name, shortId, longId, claimsData) { @@ -136,7 +129,7 @@ export function onUpdateChannelClaims (channelKey, name, longId, page) { export function updateChannelClaims (channelListId, claimsData) { return { - type: actions.CHANNEL_CLAIMS_UPDATE_SUCCEEDED, + type: actions.CHANNEL_CLAIMS_UPDATE_SUCCESS, data: {channelListId, claimsData}, }; } diff --git a/client/src/api/assetApi.js b/client/src/api/assetApi.js index 0750b572..5290d19f 100644 --- a/client/src/api/assetApi.js +++ b/client/src/api/assetApi.js @@ -42,15 +42,3 @@ export function getClaimViews (claimId) { const url = `/api/claim/views/${claimId}`; return Request(url); } - -export function doAbandonClaim (claimId) { - const params = { - method : 'POST', - body : JSON.stringify({claimId}), - headers: new Headers({ - 'Content-Type': 'application/json', - }), - credentials: 'include', - }; - return Request('/api/claim/abandon', params); -} diff --git a/client/src/app.js b/client/src/app.js index e2bfd46e..c4456ffe 100644 --- a/client/src/app.js +++ b/client/src/app.js @@ -10,7 +10,6 @@ import ContentPageWrapper from '@pages/ContentPageWrapper'; import FourOhFourPage from '@pages/FourOhFourPage'; import MultisitePage from '@pages/MultisitePage'; import PopularPage from '@pages/PopularPage'; -import EditPage from '@pages/EditPage'; const App = () => { return ( @@ -22,7 +21,6 @@ const App = () => { - diff --git a/client/src/channels/publish.js b/client/src/channels/publish.js index 0a89feb4..bdbfbf19 100644 --- a/client/src/channels/publish.js +++ b/client/src/channels/publish.js @@ -1,8 +1,8 @@ import {buffers, END, eventChannel} from 'redux-saga'; -export const makePublishRequestChannel = (fd, isUpdate) => { +export const makePublishRequestChannel = (fd) => { return eventChannel(emitter => { - const uri = `/api/claim/${isUpdate ? 'update' : 'publish'}`; + const uri = '/api/claim/publish'; const xhr = new XMLHttpRequest(); // add event listeners const onLoadStart = () => { diff --git a/client/src/components/DropzoneInstructionsDisplay/index.jsx b/client/src/components/DropzoneInstructionsDisplay/index.jsx index eb49ae98..3f13c69f 100644 --- a/client/src/components/DropzoneInstructionsDisplay/index.jsx +++ b/client/src/components/DropzoneInstructionsDisplay/index.jsx @@ -2,14 +2,11 @@ import React from 'react'; import FormFeedbackDisplay from '@components/FormFeedbackDisplay'; import Row from '@components/Row'; -const DropzoneInstructionsDisplay = ({fileError, message}) => { - if (!message) { - message = 'Drag & drop image or video here to publish'; - } +const DropzoneInstructionsDisplay = ({fileError}) => { return (
-

{message}

+

Drag & drop image or video here to publish

OR

diff --git a/client/src/components/DropzonePreviewImage/index.jsx b/client/src/components/DropzonePreviewImage/index.jsx index d62abaeb..d94d976a 100644 --- a/client/src/components/DropzonePreviewImage/index.jsx +++ b/client/src/components/DropzonePreviewImage/index.jsx @@ -10,12 +10,7 @@ class PublishPreview extends React.Component { }; } componentDidMount () { - const { isUpdate, sourceUrl, file } = this.props; - if (isUpdate && sourceUrl) { - this.setState({ imgSource: sourceUrl }); - } else { - this.setPreviewImageSource(file); - } + this.setPreviewImageSource(this.props.file); } componentWillReceiveProps (newProps) { if (newProps.file !== this.props.file) { @@ -59,10 +54,8 @@ class PublishPreview extends React.Component { PublishPreview.propTypes = { dimPreview: PropTypes.bool.isRequired, - file : PropTypes.object, + file : PropTypes.object.isRequired, thumbnail : PropTypes.object, - isUpdate : PropTypes.bool, - sourceUrl : PropTypes.string, }; export default PublishPreview; diff --git a/client/src/components/PublishLicenseInput/index.jsx b/client/src/components/PublishLicenseInput/index.jsx index 6ef59418..c4ee43f5 100644 --- a/client/src/components/PublishLicenseInput/index.jsx +++ b/client/src/components/PublishLicenseInput/index.jsx @@ -16,7 +16,7 @@ const PublishLicenseInput = ({ handleSelect }) => { className='select select--primary' onChange={handleSelect} > - + diff --git a/client/src/components/PublishPreview/index.jsx b/client/src/components/PublishPreview/index.jsx index 817b5c8c..9f7240cf 100644 --- a/client/src/components/PublishPreview/index.jsx +++ b/client/src/components/PublishPreview/index.jsx @@ -7,11 +7,9 @@ import Row from '@components/Row'; class PublishPreview extends React.Component { render () { - const { isUpdate, uri } = this.props; return (
- {isUpdate && uri && (

{`Editing ${uri}`}

)}
{ - const {show} = props; +const mapStateToProps = ({ show }) => { // select error and status const error = show.displayAsset.error; const status = show.displayAsset.status; diff --git a/client/src/containers/AssetDisplay/view.jsx b/client/src/containers/AssetDisplay/view.jsx index 7d77f951..d5b37b82 100644 --- a/client/src/containers/AssetDisplay/view.jsx +++ b/client/src/containers/AssetDisplay/view.jsx @@ -2,42 +2,6 @@ import React from 'react'; import Row from '@components/Row'; import ProgressBar from '@components/ProgressBar'; import { LOCAL_CHECK, UNAVAILABLE, ERROR, AVAILABLE } from '../../constants/asset_display_states'; -import createCanonicalLink from '../../../../utils/createCanonicalLink'; - -class AvailableContent extends React.Component { - render () { - const {contentType, sourceUrl, name, thumbnail} = this.props; - switch (contentType) { - case 'image/jpeg': - case 'image/jpg': - case 'image/png': - case 'image/gif': - return ( - {name} - ); - case 'video/mp4': - return ( - - ); - default: - return ( -

Unsupported content type

- ); - } - } -} class AssetDisplay extends React.Component { componentDidMount () { @@ -45,15 +9,8 @@ class AssetDisplay extends React.Component { this.props.onFileRequest(name, claimId); } render () { - const { status, error, asset } = this.props; - const { name, claimData: { claimId, contentType, thumbnail, outpoint } } = asset; - // the outpoint is added to force the browser to re-download the asset after an update - // issue: https://github.com/lbryio/spee.ch/issues/607 - let fileExt; - if (typeof contentType === 'string') { - fileExt = contentType.split('/')[1] || 'jpg'; - } - const sourceUrl = `${createCanonicalLink({ asset: asset.claimData })}.${fileExt}?${outpoint}`; + const { status, error, asset: { claimData: { name, claimId, contentType, fileExt, thumbnail } } } = this.props; + const sourceUrl = `/${claimId}/${name}.${fileExt}`; return (
{(status === LOCAL_CHECK) && @@ -79,12 +36,37 @@ class AssetDisplay extends React.Component {
} {(status === AVAILABLE) && - + (() => { + switch (contentType) { + case 'image/jpeg': + case 'image/jpg': + case 'image/png': + case 'image/gif': + return ( + {name} + ); + case 'video/mp4': + return ( + + ); + default: + return ( +

Unsupported content type

+ ); + } + })() }
); diff --git a/client/src/containers/AssetInfo/index.js b/client/src/containers/AssetInfo/index.js index c4f34eb6..e2eb3a68 100644 --- a/client/src/containers/AssetInfo/index.js +++ b/client/src/containers/AssetInfo/index.js @@ -2,20 +2,12 @@ import { connect } from 'react-redux'; import View from './view'; import { selectAsset } from '../../selectors/show'; -const mapStateToProps = (props) => { - const {show} = props; +const mapStateToProps = ({ show }) => { // select asset const asset = selectAsset(show); - const editable = Boolean( - asset && - asset.claimData && - asset.claimData.channelName && - props.channel.loggedInChannel.name === asset.claimData.channelName - ); // return props return { asset, - editable, }; }; diff --git a/client/src/containers/AssetInfo/view.jsx b/client/src/containers/AssetInfo/view.jsx index 625d3f82..af742617 100644 --- a/client/src/containers/AssetInfo/view.jsx +++ b/client/src/containers/AssetInfo/view.jsx @@ -13,11 +13,10 @@ import createCanonicalLink from '../../../../utils/createCanonicalLink'; class AssetInfo extends React.Component { render () { - const { editable, asset } = this.props; - const { claimViews, claimData } = asset; - const { channelName, claimId, channelShortId, description, name, fileExt, contentType, host } = claimData; + const { asset } = this.props; + const { claimViews, claimData: { channelName, channelShortId, description, name, fileExt, contentType, thumbnail, host } } = asset; - const canonicalUrl = createCanonicalLink({ asset: { ...claimData, shortId: asset.shortId }}); + const canonicalUrl = createCanonicalLink({ asset: { ...asset.claimData, shortId: asset.shortId }}); const assetCanonicalUrl = `${host}${canonicalUrl}`; let channelCanonicalUrl; @@ -30,15 +29,6 @@ class AssetInfo extends React.Component { } return (
- {editable && ( - - } - content={{name}} - /> - - )} - {channelName && ( { - const { claimData: { title } } = selectAsset(props.show); +const mapStateToProps = ({ show }) => { + const { claimData: { title } } = selectAsset(show); return { title, }; diff --git a/client/src/containers/AssetTitle/view.jsx b/client/src/containers/AssetTitle/view.jsx index 87e1e661..a542c762 100644 --- a/client/src/containers/AssetTitle/view.jsx +++ b/client/src/containers/AssetTitle/view.jsx @@ -1,5 +1,4 @@ import React from 'react'; -import { Link } from 'react-router-dom'; import Row from '@components/Row'; const AssetTitle = ({ title }) => { diff --git a/client/src/containers/ChannelClaimsDisplay/view.jsx b/client/src/containers/ChannelClaimsDisplay/view.jsx index 8d4fb25e..1f29b65b 100644 --- a/client/src/containers/ChannelClaimsDisplay/view.jsx +++ b/client/src/containers/ChannelClaimsDisplay/view.jsx @@ -36,7 +36,7 @@ class ChannelClaimsDisplay extends React.Component { ))}
diff --git a/client/src/containers/Dropzone/index.js b/client/src/containers/Dropzone/index.js index dfd0f8cd..13b2e5e0 100644 --- a/client/src/containers/Dropzone/index.js +++ b/client/src/containers/Dropzone/index.js @@ -1,29 +1,13 @@ import { connect } from 'react-redux'; import { selectFile, updateError, clearFile } from '../../actions/publish'; -import { selectAsset } from '../../selectors/show'; import View from './view'; -import siteConfig from '@config/siteConfig.json'; -import createCanonicalLink from '../../../../utils/createCanonicalLink'; -const { assetDefaults: { thumbnail: defaultThumbnail } } = siteConfig; - -const mapStateToProps = ({ show, publish: { file, thumbnail, fileError, isUpdate } }) => { - const obj = { file, thumbnail, fileError, isUpdate }; - let asset, name, claimId, fileExt, outpoint, sourceUrl; - if (isUpdate) { - asset = selectAsset(show); - const { claimData } = asset; - if (asset) { - obj.fileExt = claimData.contentType.split('/')[1]; - if (obj.fileExt === 'mp4') { - obj.sourceUrl = claimData.thumbnail ? claimData.thumbnail : defaultThumbnail; - } else { - ({fileExt, outpoint} = claimData); - obj.sourceUrl = `${createCanonicalLink({ asset: claimData })}.${fileExt}?${outpoint}`; - } - } - } - return obj; +const mapStateToProps = ({ publish }) => { + return { + file : publish.file, + thumbnail: publish.thumbnail, + fileError: publish.error.file, + }; }; const mapDispatchToProps = dispatch => { diff --git a/client/src/containers/Dropzone/view.jsx b/client/src/containers/Dropzone/view.jsx index 436bac99..517e9d15 100644 --- a/client/src/containers/Dropzone/view.jsx +++ b/client/src/containers/Dropzone/view.jsx @@ -81,70 +81,53 @@ class Dropzone extends React.Component { } } render () { - const { dragOver, mouseOver, dimPreview } = this.state; - const { file, thumbnail, fileError, isUpdate, sourceUrl, fileExt } = this.props; return ( -
- {isUpdate && fileExt === 'mp4' ? ( -

Video updates are currently disabled. This feature will be available soon. You can edit metadata.

- ) : ( -
-
- + + +
+
+ {this.props.file ? ( +
+ - -
- {file || isUpdate ? ( -
- {file ? ( - - ) : ( - - )} -
- { dragOver ? : null } - { mouseOver ? ( - - ) : null } -
-
- ) : ( - dragOver ? : ( +
+ { this.state.dragOver ? : null } + { this.state.mouseOver ? ( - ) - )} + ) : null } +
-
- )} + ) : ( + this.state.dragOver ? : ( + + ) + )} +
); } diff --git a/client/src/containers/PublishDetails/index.js b/client/src/containers/PublishDetails/index.js index 8c8eede0..7b880782 100644 --- a/client/src/containers/PublishDetails/index.js +++ b/client/src/containers/PublishDetails/index.js @@ -1,21 +1,16 @@ import { connect } from 'react-redux'; -import { clearFile, startPublish, abandonClaim } from '../../actions/publish'; -import { selectAsset } from '../../selectors/show'; +import { clearFile, startPublish } from '../../actions/publish'; import View from './view'; -const mapStateToProps = ({ show, publish }) => { +const mapStateToProps = ({ channel, publish }) => { return { file: publish.file, - isUpdate: publish.isUpdate, - hasChanged: publish.hasChanged, - asset: selectAsset(show), }; }; const mapDispatchToProps = { clearFile, startPublish, - abandonClaim, }; export default connect(mapStateToProps, mapDispatchToProps)(View); diff --git a/client/src/containers/PublishDetails/view.jsx b/client/src/containers/PublishDetails/view.jsx index 95a79edd..ac55e226 100644 --- a/client/src/containers/PublishDetails/view.jsx +++ b/client/src/containers/PublishDetails/view.jsx @@ -1,76 +1,35 @@ import React from 'react'; -import {Link, withRouter} from 'react-router-dom'; +import { withRouter } from 'react-router-dom'; import PublishUrlInput from '@containers/PublishUrlInput'; import PublishThumbnailInput from '@containers/PublishThumbnailInput'; import PublishMetadataInputs from '@containers/PublishMetadataInputs'; import ChannelSelect from '@containers/ChannelSelect'; import Row from '@components/Row'; -import Label from '@components/Label'; -import RowLabeled from '@components/RowLabeled'; import ButtonPrimaryJumbo from '@components/ButtonPrimaryJumbo'; import ButtonTertiary from '@components/ButtonTertiary'; -import ButtonSecondary from '@components/ButtonSecondary'; import SpaceAround from '@components/SpaceAround'; import PublishFinePrint from '@components/PublishFinePrint'; -import { SAVE } from '../../constants/confirmation_messages'; class PublishDetails extends React.Component { constructor (props) { super(props); this.onPublishSubmit = this.onPublishSubmit.bind(this); - this.abandonClaim = this.abandonClaim.bind(this); - this.onCancel = this.onCancel.bind(this); } onPublishSubmit () { this.props.startPublish(this.props.history); } - abandonClaim () { - const {asset, history} = this.props; - if (asset) { - const {claimData} = asset; - this.props.abandonClaim({claimData, history}); - } - } - onCancel () { - const { isUpdate, hasChanged, clearFile, history } = this.props; - if (isUpdate || !hasChanged) { - history.push('/'); - } else { - if (confirm(SAVE)) { - clearFile(); - } - } - } render () { - const {file, isUpdate, asset} = this.props; return (
- {isUpdate ? (asset && ( - - - } - content={ - - {asset.claimData.channelName} - - } - /> - - )) : ( - - - - + + + - - - - - )} + + + - { file && file.type === 'video/mp4' && ( + { this.props.file.type === 'video/mp4' && ( @@ -82,27 +41,16 @@ class PublishDetails extends React.Component { - {isUpdate && ( - - - - - - )} - diff --git a/client/src/containers/PublishMetadataInputs/index.js b/client/src/containers/PublishMetadataInputs/index.js index 1c5b462a..b00b6f09 100644 --- a/client/src/containers/PublishMetadataInputs/index.js +++ b/client/src/containers/PublishMetadataInputs/index.js @@ -8,7 +8,6 @@ const mapStateToProps = ({ publish }) => { description : publish.metadata.description, license : publish.metadata.license, nsfw : publish.metadata.nsfw, - isUpdate : publish.isUpdate, }; }; diff --git a/client/src/containers/PublishMetadataInputs/view.jsx b/client/src/containers/PublishMetadataInputs/view.jsx index d5bfb3d9..10d8a793 100644 --- a/client/src/containers/PublishMetadataInputs/view.jsx +++ b/client/src/containers/PublishMetadataInputs/view.jsx @@ -26,30 +26,27 @@ class PublishMetadataInputs extends React.Component { this.props.onMetadataChange(name, selectedOption); } render () { - const { showMetadataInputs, description, isUpdate, nsfw } = this.props; return (
- {(showMetadataInputs || isUpdate) && ( + {this.props.showMetadataInputs && (
)} - {!isUpdate && ( - - )} +
); } diff --git a/client/src/containers/PublishStatus/view.jsx b/client/src/containers/PublishStatus/view.jsx index 73212fba..71c04e7e 100644 --- a/client/src/containers/PublishStatus/view.jsx +++ b/client/src/containers/PublishStatus/view.jsx @@ -12,7 +12,7 @@ class PublishStatus extends React.Component { {status === publishStates.LOAD_START &&
-

File is loading to server

+

le is loading to server

0%

@@ -42,7 +42,7 @@ class PublishStatus extends React.Component {
} - {status === publishStates.SUCCEEDED && + {status === publishStates.SUCCESS &&

Your publish is complete! You are being redirected to it now.

@@ -71,13 +71,6 @@ class PublishStatus extends React.Component {
} - {status === publishStates.ABANDONING && -
- -

Your claim is being abandoned.

-
-
- }
); } diff --git a/client/src/containers/PublishTool/index.js b/client/src/containers/PublishTool/index.js index 86a4b6b3..9258d560 100644 --- a/client/src/containers/PublishTool/index.js +++ b/client/src/containers/PublishTool/index.js @@ -1,22 +1,11 @@ import {connect} from 'react-redux'; import View from './view'; -import {selectAsset} from "../../selectors/show"; -import {buildURI} from "../../utils/buildURI"; -const mapStateToProps = props => { - const { show, publish } = props; - const asset = selectAsset(show); - let uri; - if (asset) { - uri = `lbry://${buildURI(asset)}`; - } +const mapStateToProps = ({ publish }) => { return { disabled: publish.disabled, - file: publish.file, - status: publish.status.status, - isUpdate: publish.isUpdate, - hasChanged: publish.hasChanged, - uri, + file : publish.file, + status : publish.status.status, }; }; diff --git a/client/src/containers/PublishTool/view.jsx b/client/src/containers/PublishTool/view.jsx index 86e4c2b2..b628911a 100644 --- a/client/src/containers/PublishTool/view.jsx +++ b/client/src/containers/PublishTool/view.jsx @@ -1,34 +1,23 @@ import React from 'react'; -import { withRouter, Prompt } from 'react-router'; import Dropzone from '@containers/Dropzone'; import PublishPreview from '@components/PublishPreview'; import PublishStatus from '@containers/PublishStatus'; import PublishDisabledMessage from '@containers/PublishDisabledMessage'; -import { SAVE } from '../../constants/confirmation_messages'; class PublishTool extends React.Component { render () { - const {disabled, file, isUpdate, hasChanged, uri, status, location: currentLocation} = this.props; - if (disabled) { + if (this.props.disabled) { return ( ); } else { - if (file || isUpdate) { - if (status) { + if (this.props.file) { + if (this.props.status) { return ( ); } else { - return ( - - location.pathname === currentLocation.pathname ? false : SAVE} - /> - - - ); + return ; } } return ; @@ -36,4 +25,4 @@ class PublishTool extends React.Component { } }; -export default withRouter(PublishTool); +export default PublishTool; diff --git a/client/src/pages/AboutPage/index.jsx b/client/src/pages/AboutPage/index.jsx index 621f27b7..887e17f9 100644 --- a/client/src/pages/AboutPage/index.jsx +++ b/client/src/pages/AboutPage/index.jsx @@ -1,5 +1,4 @@ import React from 'react'; -import { withRouter } from 'react-router'; import PageLayout from '@components/PageLayout'; import HorizontalSplit from '@components/HorizontalSplit'; import AboutSpeechOverview from '@components/AboutSpeechOverview'; @@ -21,4 +20,4 @@ class AboutPage extends React.Component { } } -export default withRouter(AboutPage); +export default AboutPage; diff --git a/client/src/pages/EditPage/index.js b/client/src/pages/EditPage/index.js deleted file mode 100644 index d7ca7b25..00000000 --- a/client/src/pages/EditPage/index.js +++ /dev/null @@ -1,24 +0,0 @@ -import { connect } from 'react-redux'; -import { setUpdateTrue, setHasChanged, updateMetadata, clearFile } from '../../actions/publish'; -import { onHandleShowPageUri } from '../../actions/show'; -import { selectAsset } from '../../selectors/show'; -import View from './view'; - -const mapStateToProps = (props) => { - const { show } = props; - return { - asset : selectAsset(show), - myChannel: props.channel.loggedInChannel.name, - isUpdate : props.publish.isUpdate, - }; -}; - -const mapDispatchToProps = { - updateMetadata, - onHandleShowPageUri, - setUpdateTrue, - setHasChanged, - clearFile, -}; - -export default connect(mapStateToProps, mapDispatchToProps)(View); diff --git a/client/src/pages/EditPage/view.jsx b/client/src/pages/EditPage/view.jsx deleted file mode 100644 index 60b07900..00000000 --- a/client/src/pages/EditPage/view.jsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import PageLayout from '@components/PageLayout'; -import { Redirect } from 'react-router-dom'; -import PublishTool from '@containers/PublishTool'; - -class EditPage extends React.Component { - componentDidMount () { - const {asset, match, onHandleShowPageUri, setUpdateTrue, setHasChanged, updateMetadata} = this.props; - onHandleShowPageUri(match.params); - setUpdateTrue(); - if (asset) { - ['title', 'description', 'license', 'nsfw'].forEach(meta => updateMetadata(meta, asset.claimData[meta])); - } - setHasChanged(false); - } - componentWillUnmount () { - this.props.clearFile(); - } - render () { - const { myChannel, asset } = this.props; - // redirect if user does not own this claim - if ( - !myChannel || ( - asset && - asset.claimsData && - asset.claimsData.channelName && - asset.claimsData.channelName !== myChannel - ) - ) { - return (); - } - return ( - - - - ); - } -}; - -export default EditPage; diff --git a/client/src/pages/HomePage/index.js b/client/src/pages/HomePage/index.jsx similarity index 75% rename from client/src/pages/HomePage/index.js rename to client/src/pages/HomePage/index.jsx index 4695ef62..bdff3cab 100644 --- a/client/src/pages/HomePage/index.js +++ b/client/src/pages/HomePage/index.jsx @@ -1,20 +1,17 @@ import { connect } from 'react-redux'; import { onHandleShowHomepage } from '../../actions/show'; -import { clearFile } from '../../actions/publish'; import View from './view'; -const mapStateToProps = ({ show, site, channel, publish }) => { +const mapStateToProps = ({ show, site, channel }) => { return { error : show.request.error, requestType: show.request.type, homeChannel: site.publishOnlyApproved && !channel.loggedInChannel.name ? `${site.approvedChannels[0].name}:${site.approvedChannels[0].longId}` : null, - isUpdate : publish.isUpdate, }; }; const mapDispatchToProps = { onHandleShowHomepage, - clearFile, }; export default connect(mapStateToProps, mapDispatchToProps)(View); diff --git a/client/src/pages/HomePage/view.jsx b/client/src/pages/HomePage/view.jsx index 36b8a78e..491d00a1 100644 --- a/client/src/pages/HomePage/view.jsx +++ b/client/src/pages/HomePage/view.jsx @@ -4,9 +4,16 @@ import PublishTool from '@containers/PublishTool'; import ContentPageWrapper from '@pages/ContentPageWrapper'; class HomePage extends React.Component { - componentWillUnmount () { - this.props.clearFile(); + componentDidMount () { + this.props.onHandleShowHomepage(this.props.match.params); } + + componentWillReceiveProps (nextProps) { + if (nextProps.match.params !== this.props.match.params) { + this.props.onHandleShowHomepage(nextProps.match.params); + } + } + render () { const { homeChannel } = this.props; return homeChannel ? ( diff --git a/client/src/pages/ShowAssetDetails/index.js b/client/src/pages/ShowAssetDetails/index.js index cabb5046..0af0073c 100644 --- a/client/src/pages/ShowAssetDetails/index.js +++ b/client/src/pages/ShowAssetDetails/index.js @@ -1,10 +1,20 @@ import { connect } from 'react-redux'; -import { selectAsset } from '../../selectors/show'; import View from './view'; const mapStateToProps = ({ show }) => { + // select request info + const requestId = show.request.id; + // select asset info + let asset; + const request = show.requestList[requestId] || null; + const assetList = show.assetList; + if (request && assetList) { + const assetKey = request.key; // note: just store this in the request + asset = assetList[assetKey] || null; + }; + // return props return { - asset: selectAsset(show), + asset, }; }; diff --git a/client/src/pages/ShowAssetDetails/view.jsx b/client/src/pages/ShowAssetDetails/view.jsx index ed26c436..98c09372 100644 --- a/client/src/pages/ShowAssetDetails/view.jsx +++ b/client/src/pages/ShowAssetDetails/view.jsx @@ -1,5 +1,6 @@ import React from 'react'; import PageLayout from '@components/PageLayout'; + import HorizontalSplit from '@components/HorizontalSplit'; import AssetTitle from '@containers/AssetTitle'; import AssetDisplay from '@containers/AssetDisplay'; diff --git a/client/src/reducers/publish.js b/client/src/reducers/publish.js index 3282a722..29a31d7d 100644 --- a/client/src/reducers/publish.js +++ b/client/src/reducers/publish.js @@ -41,8 +41,6 @@ const initialState = { license : '', nsfw : false, }, - isUpdate: false, - hasChanged: false, thumbnail: null, thumbnailChannel, thumbnailChannelId, @@ -51,9 +49,8 @@ const initialState = { export default function (state = initialState, action) { switch (action.type) { case actions.FILE_SELECTED: - return Object.assign({}, state.isUpdate ? state : initialState, { // note: clears to initial state + return Object.assign({}, initialState, { // note: clears to initial state file: action.data, - hasChanged: true, }); case actions.FILE_CLEAR: return initialState; @@ -62,17 +59,14 @@ export default function (state = initialState, action) { metadata: Object.assign({}, state.metadata, { [action.data.name]: action.data.value, }), - hasChanged: true, }); case actions.CLAIM_UPDATE: return Object.assign({}, state, { claim: action.data, - hasChanged: true, }); case actions.SET_PUBLISH_IN_CHANNEL: return Object.assign({}, state, { publishInChannel: action.channel, - hasChanged: true, }); case actions.PUBLISH_STATUS_UPDATE: return Object.assign({}, state, { @@ -89,26 +83,13 @@ export default function (state = initialState, action) { selectedChannel: action.data, }); case actions.TOGGLE_METADATA_INPUTS: - return { - ...state, + return Object.assign({}, state, { showMetadataInputs: action.data, - }; + }); case actions.THUMBNAIL_NEW: - return { - ...state, + return Object.assign({}, state, { thumbnail: action.data, - hasChanged: true, - }; - case actions.SET_UPDATE_TRUE: - return { - ...state, - isUpdate: true, - }; - case actions.SET_HAS_CHANGED: - return { - ...state, - hasChanged: action.data, - }; + }); default: return state; } diff --git a/client/src/reducers/show.js b/client/src/reducers/show.js index a93da58b..91177370 100644 --- a/client/src/reducers/show.js +++ b/client/src/reducers/show.js @@ -65,43 +65,6 @@ export default function (state = initialState, action) { }, }), }); - case actions.ASSET_REMOVE: - const claim = action.data; - const newAssetList = state.assetList; - delete newAssetList[`a#${claim.name}#${claim.claimId}`]; - - const channelId = `c#${claim.channelName}#${claim.certificateId}`; - const channelClaims = state.channelList[channelId].claimsData.claims; - const newClaimsData = channelClaims.filter(c => c.claimId !== claim.claimId); - - return { - ...state, - assetList : newAssetList, - channelList: { - ...state.channelList, - [channelId]: { - ...state.channelList[channelId], - claimsData: { - ...state.channelList[channelId].claimsData, - claims: newClaimsData, - }, - }, - }, - }; - case actions.ASSET_UPDATE_CLAIMDATA: - return { - ...state, - assetList: { - ...state.assetList, - [action.data.id]: { - ...state.assetList[action.data.id], - claimData: { - ...state.assetList[action.data.id].claimData, - ...action.data.claimData, - }, - }, - }, - }; // channel data case actions.CHANNEL_ADD: return Object.assign({}, state, { @@ -114,7 +77,7 @@ export default function (state = initialState, action) { }, }), }); - case actions.CHANNEL_CLAIMS_UPDATE_SUCCEEDED: + case actions.CHANNEL_CLAIMS_UPDATE_SUCCESS: return Object.assign({}, state, { channelList: Object.assign({}, state.channelList, { [action.data.channelListId]: Object.assign({}, state.channelList[action.data.channelListId], { diff --git a/client/src/sagas/abandon.js b/client/src/sagas/abandon.js deleted file mode 100644 index db290274..00000000 --- a/client/src/sagas/abandon.js +++ /dev/null @@ -1,30 +0,0 @@ -import { call, put, takeLatest } from 'redux-saga/effects'; -import * as actions from '../constants/publish_action_types'; -import * as publishStates from '../constants/publish_claim_states'; -import { updatePublishStatus, clearFile } from '../actions/publish'; -import { removeAsset } from '../actions/show'; -import { doAbandonClaim } from '../api/assetApi'; - -function * abandonClaim (action) { - const { claimData, history } = action.data; - const { claimId } = claimData; - - const confirm = window.confirm('Are you sure you want to abandon this claim? This action cannot be undone.'); - if (!confirm) return; - - yield put(updatePublishStatus(publishStates.ABANDONING, 'Your claim is being abandoned...')); - - try { - yield call(doAbandonClaim, claimId); - } catch (error) { - return console.log('abandon error:', error.message); - } - - yield put(clearFile()); - yield put(removeAsset(claimData)); - return history.push('/'); -} - -export function * watchAbandonClaim () { - yield takeLatest(actions.ABANDON_CLAIM, abandonClaim); -}; diff --git a/client/src/sagas/publish.js b/client/src/sagas/publish.js index 7e61cda7..62157eca 100644 --- a/client/src/sagas/publish.js +++ b/client/src/sagas/publish.js @@ -5,57 +5,37 @@ import { updateError, updatePublishStatus, clearFile } from '../actions/publish' import { selectPublishState } from '../selectors/publish'; import { selectChannelState } from '../selectors/channel'; import { selectSiteState } from '../selectors/site'; -import { selectShowState, selectAsset } from '../selectors/show'; import { validateChannelSelection, validateNoPublishErrors } from '../utils/validate'; import { createPublishMetadata, createPublishFormData, createThumbnailUrl } from '../utils/publish'; import { makePublishRequestChannel } from '../channels/publish'; function * publishFile (action) { const { history } = action.data; - const publishState = yield select(selectPublishState); - const { publishInChannel, selectedChannel, file, claim, metadata, thumbnailChannel, thumbnailChannelId, thumbnail, isUpdate, error: publishToolErrors } = publishState; + const { publishInChannel, selectedChannel, file, claim, metadata, thumbnailChannel, thumbnailChannelId, thumbnail, error: publishToolErrors } = yield select(selectPublishState); const { loggedInChannel } = yield select(selectChannelState); const { host } = yield select(selectSiteState); - - let show, asset; - if (isUpdate) { - show = yield select(selectShowState); - asset = selectAsset(show); - } // validate the channel selection try { validateChannelSelection(publishInChannel, selectedChannel, loggedInChannel); } catch (error) { return yield put(updateError('channel', error.message)); - } + }; // validate publish parameters try { validateNoPublishErrors(publishToolErrors); } catch (error) { return console.log('publish error:', error.message); } - - let publishMetadata, publishFormData, publishChannel; // create metadata - publishMetadata = createPublishMetadata( - isUpdate ? asset.name : claim, - isUpdate ? {type: asset.claimData.contentType} : file, - metadata, - publishInChannel, - selectedChannel - ); - if (isUpdate) { - publishMetadata['channelName'] = asset.claimData.channelName; - } + let publishMetadata = createPublishMetadata(claim, file, metadata, publishInChannel, selectedChannel); if (thumbnail) { // add thumbnail to publish metadata - publishMetadata['thumbnail'] = createThumbnailUrl(thumbnailChannel, thumbnailChannelId, claim, host); + publishMetadata['thumbnail'] = createThumbnailUrl(thumbnailChannel, thumbnailChannelId, claim, host); } // create form data for main publish - publishFormData = createPublishFormData(file, thumbnail, publishMetadata); + const publishFormData = createPublishFormData(file, thumbnail, publishMetadata); // make the publish request - publishChannel = yield call(makePublishRequestChannel, publishFormData, isUpdate); - + const publishChannel = yield call(makePublishRequestChannel, publishFormData); while (true) { const {loadStart, progress, load, success, error: publishError} = yield take(publishChannel); if (publishError) { @@ -63,21 +43,7 @@ function * publishFile (action) { } if (success) { yield put(clearFile()); - if (isUpdate) { - yield put({ - type: 'ASSET_UPDATE_CLAIMDATA', - data: { - id : `a#${success.data.name}#${success.data.claimId}`, - claimData: success.data.claimData, - }, - }); - } - if (success.data.claimId) { - return history.push(success.data.pushTo); - } else { - // this returns to the homepage, needs work - return yield put(updatePublishStatus(publishStates.FAILED, 'ERROR')); - } + return history.push(`/${success.data.claimId}/${success.data.name}`); } if (loadStart) { yield put(updatePublishStatus(publishStates.LOAD_START, null)); @@ -89,7 +55,7 @@ function * publishFile (action) { yield put(updatePublishStatus(publishStates.PUBLISHING, null)); } } -} +}; export function * watchPublishStart () { yield takeLatest(actions.PUBLISH_START, publishFile); diff --git a/client/src/sagas/rootSaga.js b/client/src/sagas/rootSaga.js index 39481bca..05a5c471 100644 --- a/client/src/sagas/rootSaga.js +++ b/client/src/sagas/rootSaga.js @@ -10,7 +10,6 @@ import { watchUpdateChannelAvailability } from './updateChannelAvailability'; import { watchChannelCreate } from './createChannel'; import { watchChannelLoginCheck } from './checkForLoggedInChannel'; import { watchChannelLogout } from './logoutChannel'; -import { watchAbandonClaim } from './abandon'; export function * rootSaga () { yield all([ @@ -28,6 +27,5 @@ export function * rootSaga () { watchChannelLoginCheck(), watchChannelLogout(), watchUpdateAssetViews(), - watchAbandonClaim(), ]); } diff --git a/client/src/selectors/show.js b/client/src/selectors/show.js index d7358e8e..b3b5ba92 100644 --- a/client/src/selectors/show.js +++ b/client/src/selectors/show.js @@ -1,13 +1,7 @@ -export const selectAsset = show => { - const requestId = show.request.id; - let asset; - const request = show.requestList[requestId] || null; - const assetList = show.assetList; - if (request && assetList) { - const assetKey = request.key; // note: just store this in the request - asset = assetList[assetKey] || null; - } - return asset; +export const selectAsset = (show) => { + const request = show.requestList[show.request.id]; + const assetKey = request.key; + return show.assetList[assetKey]; }; export const selectShowState = (state) => { diff --git a/client/src/utils/buildURI.js b/client/src/utils/buildURI.js deleted file mode 100644 index b6fb599c..00000000 --- a/client/src/utils/buildURI.js +++ /dev/null @@ -1,10 +0,0 @@ -export const buildURI = asset => { - let channelName, certificateId, name, claimId; - if (asset.claimData) { - ({ channelName, certificateId, name, claimId } = asset.claimData); - } - if (channelName) { - return `${channelName}:${certificateId}/${name}`; - } - return `${claimId}/${name}`; -}; diff --git a/client/src/utils/publish.js b/client/src/utils/publish.js index 00ac2240..ecce371f 100644 --- a/client/src/utils/publish.js +++ b/client/src/utils/publish.js @@ -16,9 +16,7 @@ export const createPublishMetadata = (claim, { type }, { title, description, lic export const createPublishFormData = (file, thumbnail, metadata) => { let fd = new FormData(); // append file - if (file) { - fd.append('file', file); - } + fd.append('file', file); // append thumbnail if (thumbnail) { fd.append('thumbnail', thumbnail); @@ -33,5 +31,5 @@ export const createPublishFormData = (file, thumbnail, metadata) => { }; export const createThumbnailUrl = (channel, channelId, claim, host) => { - return `${host}/${channel}:${channelId}/${claim}-thumb.jpg`; + return `${host}/${channel}:${channelId}/${claim}-thumb.png`; }; diff --git a/server/chainquery/bundle.js b/server/chainquery/bundle.js index e97ae49a..2b51ddb8 100644 --- a/server/chainquery/bundle.js +++ b/server/chainquery/bundle.js @@ -850,7 +850,7 @@ var claimQueries = (db, table, sequelize) => ({ }); }, - getShortClaimIdFromLongClaimId: async (claimId, claimName, pendingClaim) => { + getShortClaimIdFromLongClaimId: async (claimId, claimName) => { logger$1.debug(`claim.getShortClaimIdFromLongClaimId for ${claimName}#${claimId}`); return await table.findAll({ where: { name: claimName }, @@ -860,12 +860,7 @@ var claimQueries = (db, table, sequelize) => ({ throw new Error('No claim(s) found with that claim name'); } - let list = result.map(claim => claim.dataValues); - if (pendingClaim) { - list = list.concat(pendingClaim); - } - - return returnShortId(list, claimId); + return returnShortId(result, claimId); }); }, @@ -986,24 +981,6 @@ var claimQueries = (db, table, sequelize) => ({ }); }, - resolveClaimInChannel: async (claimName, channelId) => { - logger$1.debug(`Claim.resolveClaimByNames: ${claimName} in ${channelId}`); - return table.findAll({ - where: { - name: claimName, - publisher_id: channelId, - }, - }).then(claimArray => { - if (claimArray.length === 0) { - return null; - } else if (claimArray.length !== 1) { - logger$1.warn(`more than one record matches ${claimName} in ${channelId}`); - } - - return claimArray[0]; - }); - }, - getOutpoint: async (name, claimId) => { logger$1.debug(`finding outpoint for ${name}#${claimId}`); diff --git a/server/chainquery/queries/claimQueries.js b/server/chainquery/queries/claimQueries.js index 185959ae..d8deb21c 100644 --- a/server/chainquery/queries/claimQueries.js +++ b/server/chainquery/queries/claimQueries.js @@ -49,7 +49,7 @@ export default (db, table, sequelize) => ({ }); }, - getShortClaimIdFromLongClaimId: async (claimId, claimName, pendingClaim) => { + getShortClaimIdFromLongClaimId: async (claimId, claimName) => { logger.debug(`claim.getShortClaimIdFromLongClaimId for ${claimName}#${claimId}`); return await table.findAll({ where: { name: claimName }, @@ -59,12 +59,7 @@ export default (db, table, sequelize) => ({ throw new Error('No claim(s) found with that claim name'); } - let list = result.map(claim => claim.dataValues); - if (pendingClaim) { - list = list.concat(pendingClaim); - } - - return returnShortId(list, claimId); + return returnShortId(result, claimId); }); }, @@ -185,24 +180,6 @@ export default (db, table, sequelize) => ({ }); }, - resolveClaimInChannel: async (claimName, channelId) => { - logger.debug(`Claim.resolveClaimByNames: ${claimName} in ${channelId}`); - return table.findAll({ - where: { - name: claimName, - publisher_id: channelId, - }, - }).then(claimArray => { - if (claimArray.length === 0) { - return null; - } else if (claimArray.length !== 1) { - logger.warn(`more than one record matches ${claimName} in ${channelId}`); - } - - return claimArray[0]; - }); - }, - getOutpoint: async (name, claimId) => { logger.debug(`finding outpoint for ${name}#${claimId}`); diff --git a/server/controllers/api/channel/claims/getChannelClaims.js b/server/controllers/api/channel/claims/getChannelClaims.js index 90a9c2c7..d1ff3b96 100644 --- a/server/controllers/api/channel/claims/getChannelClaims.js +++ b/server/controllers/api/channel/claims/getChannelClaims.js @@ -5,11 +5,7 @@ const { returnPaginatedChannelClaims } = require('./channelPagination.js'); const getChannelClaims = async (channelName, channelShortId, page) => { const channelId = await chainquery.claim.queries.getLongClaimId(channelName, channelShortId); - - let channelClaims; - if (channelId) { - channelClaims = await chainquery.claim.queries.getAllChannelClaims(channelId); - } + const channelClaims = await chainquery.claim.queries.getAllChannelClaims(channelId); const processingChannelClaims = channelClaims ? channelClaims.map((claim) => getClaimData(claim)) : []; const processedChannelClaims = await Promise.all(processingChannelClaims); diff --git a/server/controllers/api/claim/abandon/index.js b/server/controllers/api/claim/abandon/index.js deleted file mode 100644 index 08a6505f..00000000 --- a/server/controllers/api/claim/abandon/index.js +++ /dev/null @@ -1,44 +0,0 @@ -const logger = require('winston'); -const db = require('server/models'); -const { abandonClaim } = require('server/lbrynet'); -const deleteFile = require('../publish/deleteFile.js'); -const authenticateUser = require('../publish/authentication.js'); - -/* - route to abandon a claim through the daemon -*/ - -const claimAbandon = async (req, res) => { - const {claimId} = req.body; - const {user} = req; - try { - const [channel, claim] = await Promise.all([ - authenticateUser(user.channelName, null, null, user), - db.Claim.findOne({where: {claimId}}), - ]); - - if (!claim) throw new Error('That channel does not exist'); - if (!channel.channelName) throw new Error('You don\'t own this channel'); - - await abandonClaim({claimId}); - const file = await db.File.findOne({where: {claimId}}); - await Promise.all([ - deleteFile(file.filePath), - db.File.destroy({where: {claimId}}), - db.Claim.destroy({where: {claimId}}), - ]); - logger.debug(`Claim abandoned: ${claimId}`); - res.status(200).json({ - success: true, - message: `Claim with id ${claimId} abandonded`, - }); - } catch (error) { - logger.error('abandon claim error:', error); - res.status(400).json({ - success: false, - message: error.message, - }); - } -}; - -module.exports = claimAbandon; diff --git a/server/controllers/api/claim/data/index.js b/server/controllers/api/claim/data/index.js index 95146c37..6efe4e83 100644 --- a/server/controllers/api/claim/data/index.js +++ b/server/controllers/api/claim/data/index.js @@ -1,8 +1,8 @@ const { handleErrorResponse } = require('../../../utils/errorHandlers.js'); const getClaimData = require('server/utils/getClaimData'); -const fetchClaimData = require('server/utils/fetchClaimData'); const chainquery = require('chainquery'); const db = require('server/models'); + /* route to return data for a claim @@ -10,9 +10,16 @@ const db = require('server/models'); */ const claimData = async ({ ip, originalUrl, body, params }, res) => { + const claimName = params.claimName; + let claimId = params.claimId; + if (claimId === 'none') claimId = null; try { - const resolvedClaim = await fetchClaimData(params); + let resolvedClaim = await chainquery.claim.queries.resolveClaim(claimName, claimId).catch(() => {}); + + if(!resolvedClaim) { + resolvedClaim = await db.Claim.resolveClaim(claimName, claimId); + } if (!resolvedClaim) { return res.status(404).json({ diff --git a/server/controllers/api/claim/publish/createPublishParams.js b/server/controllers/api/claim/publish/createPublishParams.js index 364e831a..242f4312 100644 --- a/server/controllers/api/claim/publish/createPublishParams.js +++ b/server/controllers/api/claim/publish/createPublishParams.js @@ -11,7 +11,7 @@ const createPublishParams = (filePath, name, title, description, license, nsfw, } // provide default for license if (license === null || license.trim() === '') { - license = ''; // default to empty string + license = ' '; // default to empty string } // create the basic publish params const publishParams = { diff --git a/server/controllers/api/claim/publish/index.js b/server/controllers/api/claim/publish/index.js index cee6c2bc..f51d4055 100644 --- a/server/controllers/api/claim/publish/index.js +++ b/server/controllers/api/claim/publish/index.js @@ -17,9 +17,6 @@ const parsePublishApiRequestBody = require('./parsePublishApiRequestBody.js'); const parsePublishApiRequestFiles = require('./parsePublishApiRequestFiles.js'); const authenticateUser = require('./authentication.js'); -const chainquery = require('chainquery'); -const createCanonicalLink = require('../../../../../utils/createCanonicalLink'); - const CLAIM_TAKEN = 'CLAIM_TAKEN'; const UNAPPROVED_CHANNEL = 'UNAPPROVED_CHANNEL'; @@ -45,25 +42,7 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res) }); } // define variables - let channelName, - channelId, - channelPassword, - description, - fileName, - filePath, - fileExtension, - fileType, - gaStartTime, - license, - name, - nsfw, - thumbnail, - thumbnailFileName, - thumbnailFilePath, - thumbnailFileType, - title, - claimData, - claimId; + let channelName, channelId, channelPassword, description, fileName, filePath, fileExtension, fileType, gaStartTime, license, name, nsfw, thumbnail, thumbnailFileName, thumbnailFilePath, thumbnailFileType, title; // record the start time of the request gaStartTime = Date.now(); // validate the body and files of the request @@ -85,7 +64,6 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res) }; throw error; } - return Promise.all([ checkClaimAvailability(name), createPublishParams(filePath, name, title, description, license, nsfw, thumbnail, channelName, channelClaimId), @@ -105,40 +83,19 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res) publish(thumbnailPublishParams, thumbnailFileName, thumbnailFileType); } // publish the asset - return publish(publishParams, fileName, fileType, filePath); + return publish(publishParams, fileName, fileType); }) - .then(publishResults => { - logger.info('Publish success >', publishResults); - claimData = publishResults; - ({claimId} = claimData); - - if (channelName) { - return chainquery.claim.queries.getShortClaimIdFromLongClaimId(claimData.certificateId, channelName); - } else { - return chainquery.claim.queries.getShortClaimIdFromLongClaimId(claimId, name, claimData).catch(error => { - return claimId.slice(0, 1); - }); - } - }) - .then(shortId => { - let canonicalUrl; - if (channelName) { - canonicalUrl = createCanonicalLink({ asset: { ...claimData, channelShortId: shortId } }); - } else { - canonicalUrl = createCanonicalLink({ asset: { ...claimData, shortId } }) - } - + .then(result => { res.status(200).json({ success: true, message: 'publish completed successfully', data : { name, - claimId, - url : `${host}${canonicalUrl}`, // for backwards compatability with app - showUrl : `${host}${canonicalUrl}`, - serveUrl: `${host}${canonicalUrl}${fileExtension}`, - pushTo : canonicalUrl, - claimData, + claimId : result.claim_id, + url : `${host}/${result.claim_id}/${name}`, // for backwards compatability with app + showUrl : `${host}/${result.claim_id}/${name}`, + serveUrl: `${host}/${result.claim_id}/${name}${fileExtension}`, + lbryTx : result, }, }); // record the publish end time and send to google analytics diff --git a/server/controllers/api/claim/publish/parsePublishApiRequestFiles.js b/server/controllers/api/claim/publish/parsePublishApiRequestFiles.js index 6e1f3409..3e99ad20 100644 --- a/server/controllers/api/claim/publish/parsePublishApiRequestFiles.js +++ b/server/controllers/api/claim/publish/parsePublishApiRequestFiles.js @@ -1,19 +1,9 @@ const path = require('path'); const validateFileTypeAndSize = require('./validateFileTypeAndSize.js'); -const parsePublishApiRequestFiles = ({file, thumbnail}, isUpdate) => { +const parsePublishApiRequestFiles = ({file, thumbnail}) => { // make sure a file was provided if (!file) { - if (isUpdate) { - if (thumbnail) { - const obj = {}; - obj.thumbnailFileName = thumbnail.name; - obj.thumbnailFilePath = thumbnail.path; - obj.thumbnailFileType = thumbnail.type; - return obj; - } - return {}; - } throw new Error('no file with key of [file] found in request'); } if (!file.path) { @@ -38,24 +28,18 @@ const parsePublishApiRequestFiles = ({file, thumbnail}, isUpdate) => { if (/'/.test(file.name)) { throw new Error('apostrophes are not allowed in the file name'); } - // validate the file - if (file) validateFileTypeAndSize(file); + validateFileTypeAndSize(file); // return results - const obj = { - fileName : file.name, - filePath : file.path, - fileExtension: path.extname(file.path), - fileType : file.type, + return { + fileName : file.name, + filePath : file.path, + fileExtension : path.extname(file.path), + fileType : file.type, + thumbnailFileName: (thumbnail ? thumbnail.name : null), + thumbnailFilePath: (thumbnail ? thumbnail.path : null), + thumbnailFileType: (thumbnail ? thumbnail.type : null), }; - - if (thumbnail) { - obj.thumbnailFileName = thumbnail.name; - obj.thumbnailFilePath = thumbnail.path; - obj.thumbnailFileType = thumbnail.type; - } - - return obj; }; module.exports = parsePublishApiRequestFiles; diff --git a/server/controllers/api/claim/publish/publish.js b/server/controllers/api/claim/publish/publish.js index b0589ece..21de83bd 100644 --- a/server/controllers/api/claim/publish/publish.js +++ b/server/controllers/api/claim/publish/publish.js @@ -1,72 +1,81 @@ const logger = require('winston'); -const db = require('../../../../models'); const { publishClaim } = require('../../../../lbrynet'); +const db = require('../../../../models'); const { createFileRecordDataAfterPublish } = require('../../../../models/utils/createFileRecordData.js'); const { createClaimRecordDataAfterPublish } = require('../../../../models/utils/createClaimRecordData.js'); const deleteFile = require('./deleteFile.js'); -const publish = async (publishParams, fileName, fileType) => { - let publishResults; - let channel; - let fileRecord; - let newFile = Boolean(publishParams.file_path); +const publish = (publishParams, fileName, fileType) => { + return new Promise((resolve, reject) => { + let publishResults, certificateId, channelName; + // publish the file + return publishClaim(publishParams) + .then(result => { + logger.info(`Successfully published ${publishParams.name} ${fileName}`, result); - try { - publishResults = await publishClaim(publishParams); - logger.info(`Successfully published ${publishParams.name} ${fileName}`, publishResults); - const outpoint = `${publishResults.output.txid}:${publishResults.output.nout}`; - // get the channel information - if (publishParams.channel_name) { - logger.debug(`this claim was published in channel: ${publishParams.channel_name}`); - channel = await db.Channel.findOne({ - where: { - channelName: publishParams.channel_name, - }, + // Support new daemon, TODO: remove + publishResults = result.output && result.output.claim_id ? result.output : result; + + // get the channel information + if (publishParams.channel_name) { + logger.debug(`this claim was published in channel: ${publishParams.channel_name}`); + return db.Channel.findOne({ + where: { + channelName: publishParams.channel_name, + }, + }); + } else { + logger.debug('this claim was not published in a channel'); + return null; + } + }) + .then(channel => { + // set channel information + certificateId = null; + channelName = null; + if (channel) { + certificateId = channel.channelClaimId; + channelName = channel.channelName; + } + logger.debug(`certificateId: ${certificateId}`); + }) + .then(() => { + return Promise.all([ + createFileRecordDataAfterPublish(fileName, fileType, publishParams, publishResults), + createClaimRecordDataAfterPublish(certificateId, channelName, fileName, fileType, publishParams, publishResults), + ]); + }) + .then(([fileRecord, claimRecord]) => { + // upsert the records + const {name} = publishParams; + const {claim_id: claimId} = publishResults; + const upsertCriteria = { + name, + claimId, + }; + return Promise.all([ + db.upsert(db.File, fileRecord, upsertCriteria, 'File'), + db.upsert(db.Claim, claimRecord, upsertCriteria, 'Claim'), + ]); + }) + .then(([file, claim]) => { + logger.debug('File and Claim records successfully created'); + return Promise.all([ + file.setClaim(claim), + claim.setFile(file), + ]); + }) + .then(() => { + logger.debug('File and Claim records successfully associated'); + // resolve the promise with the result from lbryApi publishClaim; + resolve(publishResults); + }) + .catch(error => { + logger.error('PUBLISH ERROR', error); + deleteFile(publishParams.file_path); // delete the local file + reject(error); }); - } else { - channel = null; - } - const certificateId = channel ? channel.channelClaimId : null; - const channelName = channel ? channel.channelName : null; - - const claimRecord = await createClaimRecordDataAfterPublish(certificateId, channelName, fileName, fileType, publishParams, publishResults); - const {claimId} = claimRecord; - const upsertCriteria = {name: publishParams.name, claimId}; - if (newFile) { - // this is the problem - // - fileRecord = await createFileRecordDataAfterPublish(fileName, fileType, publishParams, publishResults); - } else { - fileRecord = await db.File.findOne({where: {claimId}}).then(result => result.dataValues); - } - - const [file, claim] = await Promise.all([ - db.upsert(db.File, fileRecord, upsertCriteria, 'File'), - db.upsert(db.Claim, claimRecord, upsertCriteria, 'Claim'), - ]); - logger.info(`File and Claim records successfully created (${publishParams.name})`); - - await Promise.all([ - file.setClaim(claim), - claim.setFile(file), - ]); - logger.info(`File and Claim records successfully associated (${publishParams.name})`); - - return Object.assign({}, claimRecord, {outpoint}); - } catch (err) { - // parse daemon response when err is a string - // this needs work - logger.info('publish/publish err:', err); - const error = typeof err === 'string' ? JSON.parse(err) : err; - if (publishParams.file_path) { - await deleteFile(publishParams.file_path); - } - const message = error.error && error.error.message ? error.error.message : 'Unknown publish error'; - return { - error: true, - message, - }; - } + }); }; module.exports = publish; diff --git a/server/controllers/api/claim/update/index.js b/server/controllers/api/claim/update/index.js deleted file mode 100644 index c1df4fb8..00000000 --- a/server/controllers/api/claim/update/index.js +++ /dev/null @@ -1,199 +0,0 @@ -const logger = require('winston'); -const db = require('server/models'); -const { details, publishing: { disabled, disabledMessage, primaryClaimAddress } } = require('@config/siteConfig'); -const { resolveUri } = require('server/lbrynet'); -const { sendGATimingEvent } = require('../../../../utils/googleAnalytics.js'); -const { handleErrorResponse } = require('../../../utils/errorHandlers.js'); -const publish = require('../publish/publish.js'); -const parsePublishApiRequestBody = require('../publish/parsePublishApiRequestBody'); -const parsePublishApiRequestFiles = require('../publish/parsePublishApiRequestFiles.js'); -const authenticateUser = require('../publish/authentication.js'); -const createThumbnailPublishParams = require('../publish/createThumbnailPublishParams.js'); -const chainquery = require('chainquery'); -const createCanonicalLink = require('../../../../../utils/createCanonicalLink'); - -/* - route to update a claim through the daemon -*/ - -const updateMetadata = ({nsfw, license, title, description}) => { - const update = {}; - if (nsfw) update['nsfw'] = nsfw; - if (license) update['license'] = license; - if (title) update['title'] = title; - if (description) update['description'] = description; - return update; -}; - -const rando = () => { - let text = ''; - const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for (let i = 0; i < 6; i += 1) text += possible.charAt(Math.floor(Math.random() * 62)); - return text; -}; - -const claimUpdate = ({ body, files, headers, ip, originalUrl, user, tor }, res) => { - // logging - logger.info('Claim update request:', { - ip, - headers, - body, - files, - user, - }); - - // check for disabled publishing - if (disabled) { - return res.status(503).json({ - success: false, - message: disabledMessage, - }); - } - - // define variables - let channelName, - channelId, - channelPassword, - description, - fileName, - filePath, - fileType, - gaStartTime, - thumbnail, - fileExtension, - license, - name, - nsfw, - thumbnailFileName, - thumbnailFilePath, - thumbnailFileType, - title, - claimRecord, - metadata, - publishResult, - thumbnailUpdate = false; - // record the start time of the request - gaStartTime = Date.now(); - - try { - ({name, nsfw, license, title, description, thumbnail} = parsePublishApiRequestBody(body)); - ({fileName, filePath, fileExtension, fileType, thumbnailFileName, thumbnailFilePath, thumbnailFileType} = parsePublishApiRequestFiles(files, true)); - ({channelName, channelId, channelPassword} = body); - } catch (error) { - return res.status(400).json({success: false, message: error.message}); - } - - // check channel authorization - authenticateUser(channelName, channelId, channelPassword, user) - .then(({ channelName, channelClaimId }) => { - if (!channelId) { - channelId = channelClaimId; - } - return chainquery.claim.queries.resolveClaimInChannel(name, channelClaimId).then(claim => claim.dataValues); - }) - .then(claim => { - claimRecord = claim; - if (claimRecord.content_type === 'video/mp4' && files.file) { - thumbnailUpdate = true; - } - - if (!files.file || thumbnailUpdate) { - return Promise.all([ - db.File.findOne({ where: { name, claimId: claim.claim_id } }), - resolveUri(`${claim.name}#${claim.claim_id}`), - ]); - } - - return [null, null]; - }) - .then(([fileResult, resolution]) => { - - metadata = Object.assign({}, { - title : claimRecord.title, - description: claimRecord.description, - nsfw : claimRecord.nsfw, - license : claimRecord.license, - language : 'en', - author : details.title, - }, updateMetadata({title, description, nsfw, license})); - const publishParams = { - name, - bid : '0.01', - claim_address: primaryClaimAddress, - channel_name : channelName, - channel_id : channelId, - metadata, - }; - - if (files.file) { - if (thumbnailUpdate) { - // publish new thumbnail - const newThumbnailName = `${name}-${rando()}`; - const newThumbnailParams = createThumbnailPublishParams(filePath, newThumbnailName, license, nsfw); - newThumbnailParams['file_path'] = filePath; - publish(newThumbnailParams, fileName, fileType); - - publishParams['sources'] = resolution.claim.value.stream.source; - publishParams['thumbnail'] = `${details.host}/${newThumbnailParams.channel_name}:${newThumbnailParams.channel_id}/${newThumbnailName}-thumb.jpg`; - } else { - publishParams['file_path'] = filePath; - } - } else { - fileName = fileResult.fileName; - fileType = fileResult.fileType; - publishParams['sources'] = resolution.claim.value.stream.source; - publishParams['thumbnail'] = claimRecord.thumbnail_url; - } - - const fp = files && files.file && files.file.path ? files.file.path : undefined; - return publish(publishParams, fileName, fileType, fp); - }) - .then(result => { - publishResult = result; - - if (channelName) { - return chainquery.claim.queries.getShortClaimIdFromLongClaimId(result.certificateId, channelName); - } else { - return chainquery.claim.queries.getShortClaimIdFromLongClaimId(result.claimId, name, result).catch(error => { - return result.claimId.slice(0, 1); - }); - } - }) - .then(shortId => { - let canonicalUrl; - if (channelName) { - canonicalUrl = createCanonicalLink({ asset: { ...publishResult, channelShortId: shortId } }); - } else { - canonicalUrl = createCanonicalLink({ asset: { ...publishResult, shortId } }) - } - - if (publishResult.error) { - res.status(400).json({ - success: false, - message: publishResult.message, - }); - } - - const {claimId} = publishResult; - res.status(200).json({ - success: true, - message: 'update successful', - data : { - name, - claimId, - url : `${details.host}${canonicalUrl}`, // for backwards compatability with app - showUrl : `${details.host}${canonicalUrl}`, - serveUrl: `${details.host}${canonicalUrl}${fileExtension}`, - pushTo : canonicalUrl, - claimData: publishResult, - }, - }); - // record the publish end time and send to google analytics - sendGATimingEvent('end-to-end', 'update', fileType, gaStartTime, Date.now()); - }) - .catch(error => { - handleErrorResponse(originalUrl, ip, error, res); - }); -}; - -module.exports = claimUpdate; diff --git a/server/lbrynet/index.js b/server/lbrynet/index.js index 3b4eafcd..1b914682 100644 --- a/server/lbrynet/index.js +++ b/server/lbrynet/index.js @@ -2,7 +2,6 @@ const axios = require('axios'); const logger = require('winston'); const { apiHost, apiPort, getTimeout } = require('@config/lbryConfig'); const lbrynetUri = 'http://' + apiHost + ':' + apiPort; -const db = require('../models'); const { chooseGaLbrynetPublishLabel, sendGATimingEvent } = require('../utils/googleAnalytics.js'); const handleLbrynetResponse = require('./utils/handleLbrynetResponse.js'); const { publishing } = require('@config/siteConfig'); @@ -47,21 +46,6 @@ module.exports = { }); }); }, - async abandonClaim ({claimId}) { - logger.debug(`lbryApi >> Abandon claim "${claimId}"`); - const gaStartTime = Date.now(); - try { - const abandon = await axios.post(lbrynetUri, { - method: 'claim_abandon', - params: { claim_id: claimId }, - }); - sendGATimingEvent('lbrynet', 'abandonClaim', 'ABANDON_CLAIM', gaStartTime, Date.now()); - return abandon.data; - } catch (error) { - logger.error(error); - return error; - } - }, getClaimList (claimName) { logger.debug(`lbryApi >> Getting claim_list for "${claimName}"`); const gaStartTime = Date.now(); @@ -91,13 +75,7 @@ module.exports = { }) .then(({ data }) => { sendGATimingEvent('lbrynet', 'resolveUri', 'RESOLVE', gaStartTime, Date.now()); - if (Object.keys(data.result).length === 0 && data.result.constructor === Object) { - // workaround for daemon returning empty result object - // https://github.com/lbryio/lbry/issues/1485 - db.Claim.findOne({ where: { claimId: uri.split('#')[1] } }) - .then(() => reject('This claim has not yet been confirmed on the LBRY blockchain')) - .catch(() => reject(`Claim ${uri} does not exist`)); - } else if (data.result[uri].error) { // check for errors + if (data.result[uri].error) { // check for errors reject(data.result[uri].error); } else { // if no errors, resolve resolve(data.result[uri]); diff --git a/server/middleware/logMetricsMiddleware.js b/server/middleware/logMetricsMiddleware.js index 4dc5ed47..3008900e 100644 --- a/server/middleware/logMetricsMiddleware.js +++ b/server/middleware/logMetricsMiddleware.js @@ -10,14 +10,8 @@ function logMetricsMiddleware(req, res, next) { let referrer = req.get('referrer'); if(referrer && referrer.length > 255) { - try { - // Attempt to "safely" clamp long URLs - referrer = /(.*?)#.*/.exec(referrer)[1]; - } catch(e) { - // Cheap forced string conversion & clamp - referrer = new String(referrer); - referrer = referrer.substr(0, 255); - } + // Attempt to "safely" clamp long URLs + referrer = /(.*?)#.*/.exec(referrer)[1]; if(referrer.length > 255) { logger.warn('Request refferer exceeds 255 characters:', referrer); diff --git a/server/models/utils/createFileRecordData.js b/server/models/utils/createFileRecordData.js index fdcb9ce0..aa0802cf 100644 --- a/server/models/utils/createFileRecordData.js +++ b/server/models/utils/createFileRecordData.js @@ -28,7 +28,7 @@ async function createFileRecordDataAfterGet (resolveResult, getResult) { filePath, fileType, }; -} +}; async function createFileRecordDataAfterPublish (fileName, fileType, publishParams, publishResults) { const { diff --git a/server/routes/api/index.js b/server/routes/api/index.js index 26706bd5..71b673eb 100644 --- a/server/routes/api/index.js +++ b/server/routes/api/index.js @@ -13,8 +13,6 @@ const claimGet = require('../../controllers/api/claim/get'); const claimList = require('../../controllers/api/claim/list'); const claimLongId = require('../../controllers/api/claim/longId'); const claimPublish = require('../../controllers/api/claim/publish'); -const claimAbandon = require('../../controllers/api/claim/abandon'); -const claimUpdate = require('../../controllers/api/claim/update'); const claimResolve = require('../../controllers/api/claim/resolve'); const claimShortId = require('../../controllers/api/claim/shortId'); const claimViews = require('../../controllers/api/claim/views'); @@ -31,10 +29,12 @@ const getOEmbedData = require('../../controllers/api/oEmbed'); module.exports = { // homepage routes '/api/homepage/data/channels': { controller: [ torCheckMiddleware, channelData ] }, + // channel routes '/api/channel/availability/:name': { controller: [ torCheckMiddleware, channelAvailability ] }, '/api/channel/short-id/:longId/:name': { controller: [ torCheckMiddleware, channelShortId ] }, '/api/channel/data/:channelName/:channelClaimId': { controller: [ torCheckMiddleware, channelData ] }, + '/api/channel/data/:channelName/:channelClaimId': { controller: [ torCheckMiddleware, channelData ] }, '/api/channel/claims/:channelName/:channelClaimId/:page': { controller: [ torCheckMiddleware, channelClaims ] }, // sepcial routes @@ -47,8 +47,6 @@ module.exports = { '/api/claim/list/:name': { controller: [ torCheckMiddleware, claimList ] }, '/api/claim/long-id': { method: 'post', controller: [ torCheckMiddleware, claimLongId ] }, // note: should be a 'get' '/api/claim/publish': { method: 'post', controller: [ torCheckMiddleware, autoblockPublishMiddleware, multipartMiddleware, autoblockPublishBodyMiddleware, claimPublish ] }, - '/api/claim/update': { method: 'post', controller: [ torCheckMiddleware, multipartMiddleware, claimUpdate ] }, - '/api/claim/abandon': { method: 'post', controller: [ torCheckMiddleware, multipartMiddleware, claimAbandon ] }, '/api/claim/resolve/:name/:claimId': { controller: [ torCheckMiddleware, claimResolve ] }, '/api/claim/short-id/:longId/:name': { controller: [ torCheckMiddleware, claimShortId ] }, '/api/claim/views/:claimId': { controller: [ torCheckMiddleware, claimViews ] }, diff --git a/server/routes/pages/index.js b/server/routes/pages/index.js index 858a1898..fc742b42 100644 --- a/server/routes/pages/index.js +++ b/server/routes/pages/index.js @@ -15,7 +15,6 @@ module.exports = { '/trending': { controller: redirect('/popular') }, '/popular': { controller: handlePageRequest }, '/new': { controller: handlePageRequest }, - '/edit/:claimId': { controller: handlePageRequest }, '/multisite': { controller: handlePageRequest }, '/video-embed/:name/:claimId/:config?': { controller: handleVideoEmbedRequest }, // for twitter }; diff --git a/server/utils/fetchClaimData.js b/server/utils/fetchClaimData.js deleted file mode 100644 index aeaec8f3..00000000 --- a/server/utils/fetchClaimData.js +++ /dev/null @@ -1,25 +0,0 @@ -const chainquery = require('chainquery'); -const db = require('server/models'); - -const fetchClaimData = async (params) => { - let { claimId, claimName: name } = params; - if (claimId === 'none') claimId = null; - - const [cq, local] = await Promise.all([ - chainquery.claim.queries.resolveClaim(name, claimId).then(res => res.dataValues).catch(() => {}), - db.Claim.resolveClaim(name, claimId).catch(() => {}), - ]); - - if (!cq && !local) { - return null; - } - if (cq && cq.name === name && !local) { - return cq; - } - if (local && local.name === name && !cq) { - return local; - } - return local.updatedAt > cq.modified_at ? local : cq; -}; - -module.exports = fetchClaimData; diff --git a/server/utils/getClaimData.js b/server/utils/getClaimData.js index 2e77a4ee..f247a4d3 100644 --- a/server/utils/getClaimData.js +++ b/server/utils/getClaimData.js @@ -25,7 +25,7 @@ module.exports = async (data) => { claimId: data.claim_id || data.claimId, fileExt: data.generated_extension || data.fileExt, description: data.description, - thumbnail: data.generated_thumbnail || data.thumbnail_url || data.thumbnail, + thumbnail: data.generated_thumbnail || data.thumbnail, outpoint: data.transaction_hash_id || data.outpoint, host, }) diff --git a/site/client_custom/scss/.gitkeep b/site/custom/scss/.gitkeep similarity index 100% rename from site/client_custom/scss/.gitkeep rename to site/custom/scss/.gitkeep diff --git a/site/client_custom/src/components/.gitkeep b/site/custom/src/components/.gitkeep similarity index 100% rename from site/client_custom/src/components/.gitkeep rename to site/custom/src/components/.gitkeep diff --git a/site/client_custom/src/containers/.gitkeep b/site/custom/src/containers/.gitkeep similarity index 100% rename from site/client_custom/src/containers/.gitkeep rename to site/custom/src/containers/.gitkeep diff --git a/site/client_custom/src/pages/.gitkeep b/site/custom/src/pages/.gitkeep similarity index 100% rename from site/client_custom/src/pages/.gitkeep rename to site/custom/src/pages/.gitkeep