From 2490d709c9282c0b0cad7fb9ade853e62065c220 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Wed, 23 Aug 2017 12:21:15 -0700 Subject: [PATCH] added basic support for /@channelname --- helpers/serveHelpers.js | 135 +++++++++++++++++++++++++------------ routes/serve-routes.js | 88 ++++++++++++++++-------- views/channel.handlebars | 32 +++++++++ views/noChannel.handlebars | 8 +++ 4 files changed, 190 insertions(+), 73 deletions(-) create mode 100644 views/channel.handlebars create mode 100644 views/noChannel.handlebars diff --git a/helpers/serveHelpers.js b/helpers/serveHelpers.js index b59fa343..1829d11f 100644 --- a/helpers/serveHelpers.js +++ b/helpers/serveHelpers.js @@ -1,43 +1,14 @@ const logger = require('winston'); const db = require('../models'); -// function determineShortChannelId (name, longChannelId) { -// return new Promise((resolve, reject) => { -// logger.debug('finding short channel id'); -// db.sequelize.query(`SELECT claimId, height FROM Certificate WHERE name = '${name}' ORDER BY height;`, { type: db.sequelize.QueryTypes.SELECT }) -// .then(result => { -// switch (result.length) { -// case 0: -// return reject(new Error('That is an invalid channel name')); -// default: -// let certificateIndex; -// let shortId = longChannelId.substring(0, 1); // default sort id is the first letter -// let shortIdLength = 0; -// // find the index of this certificate -// certificateIndex = result.findIndex(element => { -// return element.claimId === longChannelId; -// }); -// if (certificateIndex < 0) { throw new Error('claimid not found in possible sorted list') } -// // get an array of all certificates with lower height -// let possibleMatches = result.slice(0, certificateIndex); -// // remove certificates with the same prefixes until none are left. -// while (possibleMatches.length > 0) { -// shortIdLength += 1; -// shortId = longChannelId.substring(0, shortIdLength); -// possibleMatches = possibleMatches.filter(element => { -// return (element.claimId.substring(0, shortIdLength) === shortId); -// }); -// } -// // return the short Id -// logger.debug('short claim id ===', shortId); -// return resolve(shortId); -// } -// }) -// .catch(error => { -// reject(error); -// }); -// }); -// } +function createOpenGraphInfo ({ fileType, claimId, name, fileName, fileExt }) { + return { + embedUrl : `https://spee.ch/embed/${claimId}/${name}`, + showUrl : `https://spee.ch/${claimId}/${name}`, + source : `https://spee.ch/${claimId}/${name}${fileExt}`, + directFileUrl: `https://spee.ch/media/${fileName}`, + }; +} function getLongChannelId (channelName, channelId) { if (channelId && (channelId.length === 40)) { // full channel id @@ -108,6 +79,24 @@ function getClaimIdByLongChannelId (channelId, claimName) { }); } +function getAllChannelClaims (channelId) { + return new Promise((resolve, reject) => { + logger.debug(`finding all claims in channel "${channelId}"`); + db.sequelize.query(`SELECT * FROM Claim WHERE certificateId = '${channelId}' ORDeR BY height DESC;`, { type: db.sequelize.QueryTypes.SELECT }) + .then(result => { + switch (result.length) { + case 0: + return resolve(null); + default: + return resolve(result); + } + }) + .catch(error => { + reject(error); + }); + }); +} + function determineShortClaimId (claimId, height, claimList) { logger.debug('determining short url based on claim id and claim list'); logger.debug('claimlist starting length:', claimList.length); @@ -155,13 +144,42 @@ function determineShortClaimId (claimId, height, claimList) { } } -function createOpenGraphInfo ({ fileType, claimId, name, fileName, fileExt }) { - return { - embedUrl : `https://spee.ch/embed/${claimId}/${name}`, - showUrl : `https://spee.ch/${claimId}/${name}`, - source : `https://spee.ch/${claimId}/${name}${fileExt}`, - directFileUrl: `https://spee.ch/media/${fileName}`, - }; +function getShortChannelId (channelName, longChannelId) { + return new Promise((resolve, reject) => { + logger.debug('finding short channel id'); + db.sequelize.query(`SELECT claimId, height FROM Certificate WHERE name = '${channelName}' ORDER BY height;`, { type: db.sequelize.QueryTypes.SELECT }) + .then(result => { + switch (result.length) { + case 0: + return reject(new Error('That is an invalid channel name')); + default: + let certificateIndex; + let shortId = longChannelId.substring(0, 1); // default sort id is the first letter + let shortIdLength = 0; + // find the index of this certificate + certificateIndex = result.findIndex(element => { + return element.claimId === longChannelId; + }); + if (certificateIndex < 0) { throw new Error('claimid not found in possible sorted list') } + // get an array of all certificates with lower height + let possibleMatches = result.slice(0, certificateIndex); + // remove certificates with the same prefixes until none are left. + while (possibleMatches.length > 0) { + shortIdLength += 1; + shortId = longChannelId.substring(0, shortIdLength); + possibleMatches = possibleMatches.filter(element => { + return (element.claimId.substring(0, shortIdLength) === shortId); + }); + } + // return the short Id + logger.debug('short claim id ===', shortId); + return resolve(shortId); + } + }) + .catch(error => { + reject(error); + }); + }); } module.exports = { @@ -300,4 +318,33 @@ module.exports = { }); }); }, + getChannelContents (channelName, channelId) { + return new Promise((resolve, reject) => { + let longChannelId; + let shortChannelId; + // 1. get the long channel Id + getLongChannelId(channelName, channelId) + // 2. get all claims for that channel + .then(result => { + longChannelId = result; + return getShortChannelId(channelName, longChannelId); + }) + .then(result => { + shortChannelId = result; + return getAllChannelClaims(longChannelId); + }) + .then(allChannelClaims => { + allChannelClaims.forEach(element => { + element['channelName'] = channelName; + element['longChannelId'] = longChannelId; + element['shortChannelId'] = shortChannelId; + element['fileExtension'] = element.contentType.substring(element.contentType.lastIndexOf('/') + 1); + }); + return resolve(allChannelClaims); + }) + .catch(error => { + reject(error); + }); + }); + }, }; diff --git a/routes/serve-routes.js b/routes/serve-routes.js index d21de474..bbde9bac 100644 --- a/routes/serve-routes.js +++ b/routes/serve-routes.js @@ -1,5 +1,5 @@ const logger = require('winston'); -const { serveFile, showFile, showFileLite, getShortIdFromClaimId, resolveAgainstClaimTable } = require('../helpers/serveHelpers.js'); +const { serveFile, showFile, showFileLite, getShortIdFromClaimId, resolveAgainstClaimTable, getChannelContents } = require('../helpers/serveHelpers.js'); const { getAssetByChannel, getAssetByShortId, getAssetByClaimId, getAssetByName } = require('../controllers/serveController.js'); const { handleRequestError } = require('../helpers/errorHandlers.js'); const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js'); @@ -169,38 +169,68 @@ module.exports = (app) => { let name = params.name; let method; let fileExtension; - if (name.indexOf('.') !== -1) { - method = SERVE; - if (headers['accept'] && headers['accept'].split(',').includes('text/html')) { - method = SHOWLITE; + let channelName = null; + let channelId = null; + if (name.charAt(0) === '@') { + channelName = name; + const channelIdIndex = channelName.indexOf(CHANNELID_INDICATOR); + if (channelIdIndex !== -1) { + channelId = channelName.substring(channelIdIndex + 1); + channelName = channelName.substring(0, channelIdIndex); } - fileExtension = name.substring(name.indexOf('.')); - name = name.substring(0, name.indexOf('.')); - logger.debug('file extension =', fileExtension); + logger.debug('channel name =', channelName); + logger.debug('channel Id =', channelId); + // 1. retrieve the channel contents + getChannelContents(channelName, channelId) + // 2. respond to the request + .then(channelContents => { + if (!channelContents) { + res.status(200).render('noChannel'); + } else { + const handlebarsData = { + channelName, + channelContents, + }; + res.status(200).render('channel', handlebarsData); + } + }) + .catch(error => { + handleRequestError('serve', originalUrl, ip, error, res); + }); } else { - method = SHOW; - if (headers['accept'] && !headers['accept'].split(',').includes('text/html')) { + if (name.indexOf('.') !== -1) { method = SERVE; - } - } - logger.debug('claim name = ', name); - logger.debug('method =', method); - // 1. retrieve the asset and information - getAsset(CLAIM_NAME, null, null, null, null, name) - // 2. serve or show - .then(fileInfo => { - if (!fileInfo) { - res.status(200).render('noClaims'); + if (headers['accept'] && headers['accept'].split(',').includes('text/html')) { + method = SHOWLITE; + } + fileExtension = name.substring(name.indexOf('.')); + name = name.substring(0, name.indexOf('.')); + logger.debug('file extension =', fileExtension); } else { - return serveOrShowAsset(fileInfo, null, method, headers, originalUrl, ip, res); + method = SHOW; + if (headers['accept'] && !headers['accept'].split(',').includes('text/html')) { + method = SERVE; + } } - }) - // 3. update the database - .then(fileInfoForUpdate => { - // if needed, this is where we would update the file - }) - .catch(error => { - handleRequestError('serve', originalUrl, ip, error, res); - }); + logger.debug('claim name = ', name); + logger.debug('method =', method); + // 1. retrieve the asset and information + getAsset(CLAIM_NAME, null, null, null, null, name) + // 2. respond to the request + .then(fileInfo => { + if (!fileInfo) { + res.status(200).render('noClaims'); + } else { + return serveOrShowAsset(fileInfo, null, method, headers, originalUrl, ip, res); + } + }) + // 3. update the database + .then(fileInfoForUpdate => { + // if needed, this is where we would update the file + }) + .catch(error => { + handleRequestError('serve', originalUrl, ip, error, res); + }); + } }); }; diff --git a/views/channel.handlebars b/views/channel.handlebars new file mode 100644 index 00000000..44ba3b20 --- /dev/null +++ b/views/channel.handlebars @@ -0,0 +1,32 @@ +
+ {{> topBar}} +
+

{{this.channelName}}

+

Below are all the free claims in this channel.

+ {{#each channelContents}} +
+ {{#ifConditional this.fileType '===' 'video/mp4'}} + + {{else}} + + {{/ifConditional}} + +
+ +
+
+ {{/each}} +
+ {{> footer}} +
\ No newline at end of file diff --git a/views/noChannel.handlebars b/views/noChannel.handlebars new file mode 100644 index 00000000..66405b50 --- /dev/null +++ b/views/noChannel.handlebars @@ -0,0 +1,8 @@ +
+ {{> topBar}} +
+

No Claims

+

There are no free, public assets on this channel.

+

If you think this message is an error, contact us in Slack!

+
+
\ No newline at end of file