From 97dab8fd384725fb95cd52bbf76b84f4d7356783 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Wed, 7 Mar 2018 18:41:58 -0800 Subject: [PATCH 1/7] added GA timing event for claim availability search --- controllers/publishController.js | 6 +++++- routes/api-routes.js | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/controllers/publishController.js b/controllers/publishController.js index 18fa640e..a332fe3f 100644 --- a/controllers/publishController.js +++ b/controllers/publishController.js @@ -88,7 +88,11 @@ module.exports = { }, claimNameIsAvailable (name) { // find any records where the name is used - return db.File.findAll({ where: { name } }) + return db.Claim + .findAll({ + attributes: ['address'], + where : { name }, + }) .then(result => { if (result.length >= 1) { const claimAddress = config.wallet.lbryClaimAddress; diff --git a/routes/api-routes.js b/routes/api-routes.js index e65d0a1c..2b37dc73 100644 --- a/routes/api-routes.js +++ b/routes/api-routes.js @@ -107,10 +107,12 @@ module.exports = (app) => { }); }); // route to check whether this site published to a claim - app.get('/api/claim/availability/:name', ({ ip, originalUrl, params }, res) => { - claimNameIsAvailable(params.name) + app.get('/api/claim/availability/:name', ({ ip, originalUrl, params: { name } }, res) => { + const gaStartTime = Date.now(); + claimNameIsAvailable(name) .then(result => { res.status(200).json(result); + sendGATimingEvent('end-to-end', 'claim name availability', name, gaStartTime, Date.now()); }) .catch(error => { errorHandlers.handleErrorResponse(originalUrl, ip, error, res); @@ -128,8 +130,6 @@ module.exports = (app) => { }); // route to run a publish request on the daemon app.post('/api/claim/publish', multipartMiddleware, ({ body, files, headers, ip, originalUrl, user }, res) => { - logger.debug('api/claim/publish req.body:', body); - logger.debug('api/claim/publish req.files:', files); // define variables let channelName, channelId, channelPassword, description, fileName, filePath, fileType, gaStartTime, license, name, nsfw, thumbnail, thumbnailFileName, thumbnailFilePath, thumbnailFileType, title; // record the start time of the request From d21ab2e4b096ff2efc0b3d7ad396ab14d7f989e6 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Wed, 7 Mar 2018 18:57:35 -0800 Subject: [PATCH 2/7] updated console logs and error messages --- controllers/publishController.js | 3 +-- models/claim.js | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/controllers/publishController.js b/controllers/publishController.js index a332fe3f..55078caa 100644 --- a/controllers/publishController.js +++ b/controllers/publishController.js @@ -96,11 +96,10 @@ module.exports = { .then(result => { if (result.length >= 1) { const claimAddress = config.wallet.lbryClaimAddress; - // filter out any results that were not published from spee.ch's wallet address + // filter out any that were not published from this address const filteredResult = result.filter((claim) => { return (claim.address === claimAddress); }); - // return based on whether any non-spee.ch claims were left if (filteredResult.length >= 1) { throw new Error('That claim is already in use'); }; diff --git a/models/claim.js b/models/claim.js index 0641ab65..35d8c4bd 100644 --- a/models/claim.js +++ b/models/claim.js @@ -349,14 +349,13 @@ module.exports = (sequelize, { STRING, BOOLEAN, INTEGER, TEXT, DECIMAL }) => { where: { name, claimId }, }) .then(claimArray => { - logger.debug('claims found on resolve:', claimArray.length); switch (claimArray.length) { case 0: return resolve(null); case 1: return resolve(prepareClaimData(claimArray[0].dataValues)); default: - logger.error(`more than one entry matches that name (${name}) and claimID (${claimId})`); + logger.error(`more than one record matches ${name}#${claimId} in db.Claim`); return resolve(prepareClaimData(claimArray[0].dataValues)); } }) From 188706ca3195b3cd21c2659c993914085cc6196e Mon Sep 17 00:00:00 2001 From: bill bittner Date: Wed, 7 Mar 2018 19:39:22 -0800 Subject: [PATCH 3/7] updated the channel creation route with GA event --- controllers/publishController.js | 29 ++++++++++++--------- react/containers/ChannelCreateForm/view.jsx | 29 +++++---------------- routes/api-routes.js | 14 +++++----- 3 files changed, 28 insertions(+), 44 deletions(-) diff --git a/controllers/publishController.js b/controllers/publishController.js index 55078caa..215160d8 100644 --- a/controllers/publishController.js +++ b/controllers/publishController.js @@ -106,21 +106,24 @@ module.exports = { return name; }; return name; + }) + .catch(error => { + throw error; }); }, checkChannelAvailability (name) { - return new Promise((resolve, reject) => { - // find any records where the name is used - db.Channel.findAll({ where: { channelName: name } }) - .then(result => { - if (result.length >= 1) { - return resolve(false); - } - resolve(true); - }) - .catch(error => { - reject(error); - }); - }); + return db.Channel + .findAll({ + where: { channelName: name }, + }) + .then(result => { + if (result.length >= 1) { + throw new Error('That channel has already been claimed'); + } + return name; + }) + .catch(error => { + throw error; + }); }, }; diff --git a/react/containers/ChannelCreateForm/view.jsx b/react/containers/ChannelCreateForm/view.jsx index 269a08eb..56dbdedd 100644 --- a/react/containers/ChannelCreateForm/view.jsx +++ b/react/containers/ChannelCreateForm/view.jsx @@ -38,32 +38,13 @@ class ChannelCreateForm extends React.Component { updateIsChannelAvailable (channel) { const channelWithAtSymbol = `@${channel}`; request(`/api/channel/availability/${channelWithAtSymbol}`) - .then(isAvailable => { - if (isAvailable) { - this.setState({'error': null}); - } else { - this.setState({'error': 'That channel has already been claimed'}); - } + .then(() => { + this.setState({'error': null}); }) .catch((error) => { this.setState({'error': error.message}); }); } - checkIsChannelAvailable (channel) { - const channelWithAtSymbol = `@${channel}`; - return new Promise((resolve, reject) => { - request(`/api/channel/availability/${channelWithAtSymbol}`) - .then(isAvailable => { - if (!isAvailable) { - return reject(new Error('That channel has already been claimed')); - } - resolve(); - }) - .catch((error) => { - reject(error); - }); - }); - } checkIsPasswordProvided () { const password = this.state.password; return new Promise((resolve, reject) => { @@ -96,7 +77,9 @@ class ChannelCreateForm extends React.Component { event.preventDefault(); this.checkIsPasswordProvided() .then(() => { - return this.checkIsChannelAvailable(this.state.channel, this.state.password); + if (this.state.error) { + throw new Error(); + } }) .then(() => { this.setState({status: 'We are publishing your new channel. Sit tight...'}); @@ -107,7 +90,7 @@ class ChannelCreateForm extends React.Component { this.props.onChannelLogin(result.channelName, result.shortChannelId, result.channelClaimId); }) .catch((error) => { - this.setState({'error': error.message, status: null}); + if (error.message) this.setState({'error': error.message, status: null}); }); } render () { diff --git a/routes/api-routes.js b/routes/api-routes.js index 2b37dc73..4f75ecb3 100644 --- a/routes/api-routes.js +++ b/routes/api-routes.js @@ -16,14 +16,12 @@ const NO_CLAIM = 'NO_CLAIM'; module.exports = (app) => { // route to check whether site has published to a channel - app.get('/api/channel/availability/:name', ({ ip, originalUrl, params }, res) => { - checkChannelAvailability(params.name) - .then(result => { - if (result === true) { - res.status(200).json(true); - } else { - res.status(200).json(false); - } + app.get('/api/channel/availability/:name', ({ ip, originalUrl, params: { name } }, res) => { + const gaStartTime = Date.now(); + checkChannelAvailability(name) + .then(availableName => { + res.status(200).json(availableName); + sendGATimingEvent('end-to-end', 'claim name availability', name, gaStartTime, Date.now()); }) .catch(error => { errorHandlers.handleErrorResponse(originalUrl, ip, error, res); From d018f58d8da3a8aebf05c93990b65693615da238 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Wed, 7 Mar 2018 20:06:52 -0800 Subject: [PATCH 4/7] added availability check based on multiple claim addresses --- config/speechConfig.js.example | 9 ++++----- controllers/publishController.js | 9 +++++---- helpers/publishHelpers.js | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/config/speechConfig.js.example b/config/speechConfig.js.example index af4b1de7..21c32be5 100644 --- a/config/speechConfig.js.example +++ b/config/speechConfig.js.example @@ -1,7 +1,4 @@ module.exports = { - wallet: { - lbryClaimAddress: null, // choose an address from your lbry wallet - }, analytics: { googleId: null, // google id for analytics tracking; leave `null` if not applicable }, @@ -29,8 +26,10 @@ module.exports = { description: 'Open-source, decentralized image and video sharing.' }, publish: { - thumbnailChannel : '@channelName', // create a channel to use for thumbnail images - thumbnailChannelId: 'xyz123...', // the channel_id (claim id) for the channel above + primaryClaimAddress : null, // choose any address from your lbry wallet + additionalClaimAddresses: [], // // optional: add previously used claim addresses + thumbnailChannel : '@channelName', // create a channel to use for thumbnail images + thumbnailChannelId : 'xyz123...', // the channel_id (claim id) for the channel above } claim: { defaultTitle : 'Spee.ch', diff --git a/controllers/publishController.js b/controllers/publishController.js index 215160d8..e376ed47 100644 --- a/controllers/publishController.js +++ b/controllers/publishController.js @@ -2,7 +2,7 @@ const logger = require('winston'); const db = require('../models'); const lbryApi = require('../helpers/lbryApi.js'); const publishHelpers = require('../helpers/publishHelpers.js'); -const config = require('../config/speechConfig.js'); +const { publish : { primaryClaimAddress, additionalClaimAddresses } } = require('../config/speechConfig.js'); module.exports = { publish (publishParams, fileName, fileType) { @@ -95,10 +95,11 @@ module.exports = { }) .then(result => { if (result.length >= 1) { - const claimAddress = config.wallet.lbryClaimAddress; + const claimAddresses = additionalClaimAddresses || []; + claimAddresses.push(primaryClaimAddress); // filter out any that were not published from this address - const filteredResult = result.filter((claim) => { - return (claim.address === claimAddress); + const filteredResult = result.filter(({ address }) => { + return (claimAddresses.includes(address)); }); if (filteredResult.length >= 1) { throw new Error('That claim is already in use'); diff --git a/helpers/publishHelpers.js b/helpers/publishHelpers.js index 5e515834..1b894eea 100644 --- a/helpers/publishHelpers.js +++ b/helpers/publishHelpers.js @@ -1,6 +1,6 @@ const logger = require('winston'); const fs = require('fs'); -const { site, wallet, publish } = require('../config/speechConfig.js'); +const { site, publish } = require('../config/speechConfig.js'); module.exports = { parsePublishApiRequestBody ({name, nsfw, license, title, description, thumbnail}) { @@ -114,7 +114,7 @@ module.exports = { license, nsfw, }, - claim_address: wallet.lbryClaimAddress, + claim_address: publish.primaryClaimAddress, }; // add thumbnail to channel if video if (thumbnail) { @@ -140,7 +140,7 @@ module.exports = { license, nsfw, }, - claim_address: wallet.lbryClaimAddress, + claim_address: publish.primaryClaimAddress, channel_name : publish.thumbnailChannel, channel_id : publish.thumbnailChannelId, }; From bbd455f4a13f99dd185af8409370611e6c09463c Mon Sep 17 00:00:00 2001 From: bill bittner Date: Mon, 12 Mar 2018 11:42:52 -0700 Subject: [PATCH 5/7] updated channel creation to check name availability directly --- react/containers/ChannelCreateForm/view.jsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/react/containers/ChannelCreateForm/view.jsx b/react/containers/ChannelCreateForm/view.jsx index 56dbdedd..01fb66f8 100644 --- a/react/containers/ChannelCreateForm/view.jsx +++ b/react/containers/ChannelCreateForm/view.jsx @@ -45,6 +45,10 @@ class ChannelCreateForm extends React.Component { this.setState({'error': error.message}); }); } + checkIsChannelAvailable (channel) { + const channelWithAtSymbol = `@${channel}`; + return request(`/api/channel/availability/${channelWithAtSymbol}`); + } checkIsPasswordProvided () { const password = this.state.password; return new Promise((resolve, reject) => { @@ -77,9 +81,7 @@ class ChannelCreateForm extends React.Component { event.preventDefault(); this.checkIsPasswordProvided() .then(() => { - if (this.state.error) { - throw new Error(); - } + return this.checkIsChannelAvailable(); }) .then(() => { this.setState({status: 'We are publishing your new channel. Sit tight...'}); From 6414142f73f3c73c6226c28591ce7b2fdc4f01d8 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Mon, 12 Mar 2018 11:45:16 -0700 Subject: [PATCH 6/7] fixed check password to match check channel --- react/containers/ChannelCreateForm/view.jsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/react/containers/ChannelCreateForm/view.jsx b/react/containers/ChannelCreateForm/view.jsx index 01fb66f8..4db37a24 100644 --- a/react/containers/ChannelCreateForm/view.jsx +++ b/react/containers/ChannelCreateForm/view.jsx @@ -49,8 +49,7 @@ class ChannelCreateForm extends React.Component { const channelWithAtSymbol = `@${channel}`; return request(`/api/channel/availability/${channelWithAtSymbol}`); } - checkIsPasswordProvided () { - const password = this.state.password; + checkIsPasswordProvided (password) { return new Promise((resolve, reject) => { if (!password || password.length < 1) { return reject(new Error('Please provide a password')); @@ -79,9 +78,9 @@ class ChannelCreateForm extends React.Component { } createChannel (event) { event.preventDefault(); - this.checkIsPasswordProvided() + this.checkIsPasswordProvided(this.state.password) .then(() => { - return this.checkIsChannelAvailable(); + return this.checkIsChannelAvailable(this.state.channel); }) .then(() => { this.setState({status: 'We are publishing your new channel. Sit tight...'}); From c247a9c79e94dccbf0b015dbb5dc4c6091db76c0 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Mon, 12 Mar 2018 12:03:20 -0700 Subject: [PATCH 7/7] fixed name availability querty to use "or" --- controllers/publishController.js | 22 ++++++++++----------- models/index.js | 3 --- react/containers/ChannelCreateForm/view.jsx | 6 +++++- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/controllers/publishController.js b/controllers/publishController.js index e376ed47..8733a147 100644 --- a/controllers/publishController.js +++ b/controllers/publishController.js @@ -3,6 +3,8 @@ const db = require('../models'); const lbryApi = require('../helpers/lbryApi.js'); const publishHelpers = require('../helpers/publishHelpers.js'); const { publish : { primaryClaimAddress, additionalClaimAddresses } } = require('../config/speechConfig.js'); +const Sequelize = require('sequelize'); +const Op = Sequelize.Op; module.exports = { publish (publishParams, fileName, fileType) { @@ -87,24 +89,22 @@ module.exports = { }); }, claimNameIsAvailable (name) { + const claimAddresses = additionalClaimAddresses || []; + claimAddresses.push(primaryClaimAddress); // find any records where the name is used return db.Claim .findAll({ attributes: ['address'], - where : { name }, + where : { + name, + address: { + [Op.or]: claimAddresses, + }, + }, }) .then(result => { if (result.length >= 1) { - const claimAddresses = additionalClaimAddresses || []; - claimAddresses.push(primaryClaimAddress); - // filter out any that were not published from this address - const filteredResult = result.filter(({ address }) => { - return (claimAddresses.includes(address)); - }); - if (filteredResult.length >= 1) { - throw new Error('That claim is already in use'); - }; - return name; + throw new Error('That claim is already in use'); }; return name; }) diff --git a/models/index.js b/models/index.js index 1e6b6352..370f43ee 100644 --- a/models/index.js +++ b/models/index.js @@ -1,7 +1,4 @@ -// const fs = require('fs'); -// const path = require('path'); const Sequelize = require('sequelize'); -// const basename = path.basename(module.filename); const logger = require('winston'); const config = require('../config/speechConfig.js'); const { database, username, password } = config.sql; diff --git a/react/containers/ChannelCreateForm/view.jsx b/react/containers/ChannelCreateForm/view.jsx index 4db37a24..44336daa 100644 --- a/react/containers/ChannelCreateForm/view.jsx +++ b/react/containers/ChannelCreateForm/view.jsx @@ -91,7 +91,11 @@ class ChannelCreateForm extends React.Component { this.props.onChannelLogin(result.channelName, result.shortChannelId, result.channelClaimId); }) .catch((error) => { - if (error.message) this.setState({'error': error.message, status: null}); + if (error.message) { + this.setState({'error': error.message, status: null}); + } else { + this.setState({'error': error, status: null}); + }; }); } render () {