Merge branch 'speech-as-a-package' of github.com:lbryio/spee.ch into folder-structure
This commit is contained in:
commit
149dca21d2
68 changed files with 567 additions and 383 deletions
|
@ -1,3 +1,4 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
public/
|
public/bundle
|
||||||
|
index.js
|
||||||
test
|
test
|
||||||
|
|
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -1,7 +1,4 @@
|
||||||
node_modules
|
node_modules
|
||||||
.idea
|
.idea
|
||||||
config/sequelizeCliConfig.js
|
/devConfig/sequelizeCliConfig.js
|
||||||
config/speechConfig.js
|
/devConfig/testingConfig.js
|
||||||
public/bundle
|
|
||||||
server.js
|
|
||||||
webpack.config.js
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
'config': path.resolve('config', 'sequelizeCliConfig.js'),
|
'config': path.resolve('devConfig', 'sequelizeCliConfig.js'),
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
# Spee.ch
|
# Spee.ch
|
||||||
Spee.ch is a web app that reads and publishes images and videos to and from the [LBRY](https://lbry.io/) blockchain.
|
Spee.ch is a web app that reads and publishes images and videos to and from the [LBRY](https://lbry.io/) blockchain.
|
||||||
|
|
||||||
## How to run this repository locally
|
##Installation
|
||||||
* start mysql
|
* start mysql
|
||||||
* install mysql
|
* install mysql
|
||||||
* create a database called `lbry`
|
* create a database called `lbry`
|
||||||
|
@ -12,7 +12,8 @@ Spee.ch is a web app that reads and publishes images and videos to and from the
|
||||||
* start spee.ch
|
* start spee.ch
|
||||||
* clone this repo
|
* clone this repo
|
||||||
* run `npm install`
|
* run `npm install`
|
||||||
* create your `speechConfig.js` file
|
* create your `
|
||||||
|
speechConfig.js` file
|
||||||
* copy `speechConfig.js.example` and name it `speechConfig.js`
|
* copy `speechConfig.js.example` and name it `speechConfig.js`
|
||||||
* replace the `null` values in the config file with the appropriate values for your environment
|
* replace the `null` values in the config file with the appropriate values for your environment
|
||||||
* build the app by running `npm run build-prod`
|
* build the app by running `npm run build-prod`
|
||||||
|
|
8
config/lbryConfig.js
Normal file
8
config/lbryConfig.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
const lbryConfig = {
|
||||||
|
api: {
|
||||||
|
apiHost: 'localhost',
|
||||||
|
apiPort: '5279',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = lbryConfig;
|
|
@ -1,21 +1,5 @@
|
||||||
module.exports = (winston, logLevel) => {
|
const loggerConfig = {
|
||||||
winston.configure({
|
logLevel: 'debug', // options: silly, debug, verbose, info
|
||||||
transports: [
|
|
||||||
new (winston.transports.Console)({
|
|
||||||
level : logLevel,
|
|
||||||
timestamp : false,
|
|
||||||
colorize : true,
|
|
||||||
prettyPrint : true,
|
|
||||||
handleExceptions : true,
|
|
||||||
humanReadableUnhandledException: true,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
winston.error('Level 0');
|
|
||||||
winston.warn('Level 1');
|
|
||||||
winston.info('Level 2');
|
|
||||||
winston.verbose('Level 3');
|
|
||||||
winston.debug('Level 4');
|
|
||||||
winston.silly('Level 5');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports = loggerConfig;
|
||||||
|
|
16
config/mysqlConfig.js
Normal file
16
config/mysqlConfig.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
function MysqlConfig () {
|
||||||
|
this.database = 'default';
|
||||||
|
this.username = 'default';
|
||||||
|
this.password = 'default';
|
||||||
|
this.configure = (config) => {
|
||||||
|
if (!config) {
|
||||||
|
return console.log('No MySQL config received.');
|
||||||
|
}
|
||||||
|
const {database, username, password} = config;
|
||||||
|
this.database = database;
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = new MysqlConfig();
|
42
config/siteConfig.js
Normal file
42
config/siteConfig.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
function SiteConfig () {
|
||||||
|
this.analytics = {
|
||||||
|
googleId: 'default',
|
||||||
|
};
|
||||||
|
this.assetDefaults = {
|
||||||
|
description: 'An asset published on Spee.ch',
|
||||||
|
thumbnail : 'https://spee.ch/assets/img/video_thumb_default.png',
|
||||||
|
title : 'Spee.ch',
|
||||||
|
};
|
||||||
|
this.auth = {
|
||||||
|
sessionKey: 'default',
|
||||||
|
};
|
||||||
|
this.details = {
|
||||||
|
description: 'Open-source, decentralized image and video sharing.',
|
||||||
|
host : 'default',
|
||||||
|
port : 3000,
|
||||||
|
title : 'Spee.ch',
|
||||||
|
twitter : '@spee_ch',
|
||||||
|
};
|
||||||
|
this.publishing = {
|
||||||
|
additionalClaimAddresses: [],
|
||||||
|
disabled : false,
|
||||||
|
disabledMessage : 'Please check back soon.',
|
||||||
|
primaryClaimAddress : 'default',
|
||||||
|
thumbnailChannel : 'default',
|
||||||
|
thumbnailChannelId : 'default',
|
||||||
|
uploadDirectory : '/home/lbry/Uploads',
|
||||||
|
};
|
||||||
|
this.configure = (config) => {
|
||||||
|
if (!config) {
|
||||||
|
return console.log('No site config received.');
|
||||||
|
}
|
||||||
|
const { analytics, assetDefaults, auth, details, publishing } = config;
|
||||||
|
this.analytics = analytics;
|
||||||
|
this.assetDefaults = assetDefaults;
|
||||||
|
this.auth = auth;
|
||||||
|
this.details = details;
|
||||||
|
this.publishing = publishing;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = new SiteConfig();
|
|
@ -1,34 +1,16 @@
|
||||||
const { logging } = require('./speechConfig.js');
|
function SlackConfig () {
|
||||||
const { slackWebHook, slackErrorChannel, slackInfoChannel } = logging;
|
this.slackWebHook = 'default';
|
||||||
const winstonSlackWebHook = require('winston-slack-webhook').SlackWebHook;
|
this.slackErrorChannel = 'default';
|
||||||
|
this.slackInfoChannel = 'default';
|
||||||
module.exports = (winston) => {
|
this.configure = (config) => {
|
||||||
if (slackWebHook) {
|
if (!config) {
|
||||||
// add a transport for errors to slack
|
return console.log('No slack config received.');
|
||||||
if (slackErrorChannel) {
|
}
|
||||||
winston.add(winstonSlackWebHook, {
|
const {slackWebHook, slackErrorChannel, slackInfoChannel} = config;
|
||||||
name : 'slack-errors-transport',
|
this.slackWebHook = slackWebHook;
|
||||||
level : 'warn',
|
this.slackErrorChannel = slackErrorChannel;
|
||||||
webhookUrl: slackWebHook,
|
this.slackInfoChannel = slackInfoChannel;
|
||||||
channel : slackErrorChannel,
|
};
|
||||||
username : 'spee.ch',
|
|
||||||
iconEmoji : ':face_with_head_bandage:',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
if (slackInfoChannel) {
|
|
||||||
winston.add(winstonSlackWebHook, {
|
|
||||||
name : 'slack-info-transport',
|
|
||||||
level : 'info',
|
|
||||||
webhookUrl: slackWebHook,
|
|
||||||
channel : slackInfoChannel,
|
|
||||||
username : 'spee.ch',
|
|
||||||
iconEmoji : ':nerd_face:',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// send test message
|
|
||||||
winston.error('Slack "error" logging is online.');
|
|
||||||
winston.info('Slack "info" logging is online.');
|
|
||||||
} else {
|
|
||||||
winston.warn('Slack logging is not enabled because no slackWebHook config var provided.');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports = new SlackConfig();
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
analytics: {
|
|
||||||
googleId: null, // google id for analytics tracking; leave `null` if not applicable
|
|
||||||
},
|
|
||||||
sql: {
|
|
||||||
database: 'lbry',
|
|
||||||
username: null, // username for mysql
|
|
||||||
password: null, // password for mysql
|
|
||||||
},
|
|
||||||
logging: {
|
|
||||||
logLevel : 'debug', // options: silly, debug, verbose, info
|
|
||||||
slackWebHook : null, // enter a webhook if you wish to push logs to slack; otherwise leave as `null`
|
|
||||||
slackErrorChannel: null, // enter a slack channel (#example) for errors to be sent to; otherwise leave null
|
|
||||||
slackInfoChannel : null, // enter a slack channel (#info) for info level logs to be sent to otherwise leave null
|
|
||||||
},
|
|
||||||
session: {
|
|
||||||
sessionKey: null, // enter a secret key to be used for session encryption
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
uploadDirectory: null, // enter file path to where uploads/publishes should be stored
|
|
||||||
},
|
|
||||||
site: {
|
|
||||||
title : 'Spee.ch',
|
|
||||||
name : 'Spee.ch',
|
|
||||||
host : 'https://spee.ch',
|
|
||||||
description: 'Open-source, decentralized image and video sharing.',
|
|
||||||
},
|
|
||||||
publish: {
|
|
||||||
additionalClaimAddresses: [], // // optional: add previously used claim addresses
|
|
||||||
disabled : false,
|
|
||||||
primaryClaimAddress : null, // choose any address from your lbry wallet
|
|
||||||
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',
|
|
||||||
defaultThumbnail : 'https://spee.ch/assets/img/video_thumb_default.png',
|
|
||||||
defaultDescription: 'Open-source, decentralized image and video sharing.',
|
|
||||||
},
|
|
||||||
testing: {
|
|
||||||
testChannel : '@testpublishchannel', // a channel to make test publishes in
|
|
||||||
testChannelId : 'xyz123...', // the claim id for the test channel
|
|
||||||
testChannelPassword: 'password', // password for the test channel
|
|
||||||
},
|
|
||||||
api: {
|
|
||||||
apiHost: 'localhost',
|
|
||||||
apiPort: '5279',
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -2,7 +2,7 @@ const logger = require('winston');
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const lbryApi = require('../helpers/lbryApi.js');
|
const lbryApi = require('../helpers/lbryApi.js');
|
||||||
const publishHelpers = require('../helpers/publishHelpers.js');
|
const publishHelpers = require('../helpers/publishHelpers.js');
|
||||||
const { publish : { primaryClaimAddress, additionalClaimAddresses } } = require('../config/speechConfig.js');
|
const { publishing: { primaryClaimAddress, additionalClaimAddresses } } = require('../config/siteConfig.js');
|
||||||
const Sequelize = require('sequelize');
|
const Sequelize = require('sequelize');
|
||||||
const Op = Sequelize.Op;
|
const Op = Sequelize.Op;
|
||||||
|
|
||||||
|
|
|
@ -2,28 +2,6 @@ const logger = require('winston');
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getTrendingClaims (startDate) {
|
|
||||||
logger.debug('retrieving trending');
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// get the raw requests data
|
|
||||||
db.getTrendingFiles(startDate)
|
|
||||||
.then(fileArray => {
|
|
||||||
let claimsPromiseArray = [];
|
|
||||||
if (fileArray) {
|
|
||||||
fileArray.forEach(file => {
|
|
||||||
claimsPromiseArray.push(db.Claim.resolveClaim(file.name, file.claimId));
|
|
||||||
});
|
|
||||||
return Promise.all(claimsPromiseArray);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(claimsArray => {
|
|
||||||
resolve(claimsArray);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getRecentClaims () {
|
getRecentClaims () {
|
||||||
logger.debug('retrieving most recent claims');
|
logger.debug('retrieving most recent claims');
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
25
devConfig/sequelizeCliConfig.js
Normal file
25
devConfig/sequelizeCliConfig.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
const sequelizeCliConfig = {
|
||||||
|
development: {
|
||||||
|
username: 'lbry',
|
||||||
|
password: 'yYa5B6f7WuGq1613q9D7UWP3HT',
|
||||||
|
database: 'lbry',
|
||||||
|
host : '127.0.0.1',
|
||||||
|
dialect : 'mysql',
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
username: 'lbry',
|
||||||
|
password: 'yYa5B6f7WuGq1613q9D7UWP3HT',
|
||||||
|
database: 'lbry',
|
||||||
|
host : '127.0.0.1',
|
||||||
|
dialect : 'mysql',
|
||||||
|
},
|
||||||
|
production: {
|
||||||
|
username: 'lbry',
|
||||||
|
password: 'yYa5B6f7WuGq1613q9D7UWP3HT',
|
||||||
|
database: 'lbry',
|
||||||
|
host : '127.0.0.1',
|
||||||
|
dialect : 'mysql',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = sequelizeCliConfig;
|
5
devConfig/testingConfig.example.js
Normal file
5
devConfig/testingConfig.example.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
testChannel : null, // a channel to make test publishes in
|
||||||
|
testChannelId : null, // the claim id for the test channel
|
||||||
|
testChannelPassword: null, // password for the test channel
|
||||||
|
};
|
|
@ -1,4 +1,3 @@
|
||||||
// const db = require('../models'); // require our models for syncing
|
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
const config = require('../config/speechConfig.js');
|
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = (config) => {
|
||||||
// get the config file
|
// get the config file
|
||||||
|
|
||||||
for (let configCategoryKey in config) {
|
for (let configCategoryKey in config) {
|
||||||
if (config.hasOwnProperty(configCategoryKey)) {
|
if (config.hasOwnProperty(configCategoryKey)) {
|
||||||
// get the final variables for each config category
|
// get the final variables for each config category
|
||||||
|
|
24
helpers/configureLogger.js
Normal file
24
helpers/configureLogger.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
const { logLevel } = require('../config/loggerConfig');
|
||||||
|
|
||||||
|
module.exports = (winston) => {
|
||||||
|
// configure
|
||||||
|
winston.configure({
|
||||||
|
transports: [
|
||||||
|
new (winston.transports.Console)({
|
||||||
|
level : logLevel,
|
||||||
|
timestamp : false,
|
||||||
|
colorize : true,
|
||||||
|
prettyPrint : true,
|
||||||
|
handleExceptions : true,
|
||||||
|
humanReadableUnhandledException: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
// test all the log levels
|
||||||
|
winston.error('Level 0');
|
||||||
|
winston.warn('Level 1');
|
||||||
|
winston.info('Level 2');
|
||||||
|
winston.verbose('Level 3');
|
||||||
|
winston.debug('Level 4');
|
||||||
|
winston.silly('Level 5');
|
||||||
|
};
|
34
helpers/configureSlack.js
Normal file
34
helpers/configureSlack.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
const winstonSlackWebHook = require('winston-slack-webhook').SlackWebHook;
|
||||||
|
const slackConfig = require('../config/slackConfig.js');
|
||||||
|
|
||||||
|
module.exports = (winston) => {
|
||||||
|
const {slackWebHook, slackErrorChannel, slackInfoChannel} = slackConfig;
|
||||||
|
if (slackWebHook) {
|
||||||
|
// add a transport for errors to slack
|
||||||
|
if (slackErrorChannel) {
|
||||||
|
winston.add(winstonSlackWebHook, {
|
||||||
|
name : 'slack-errors-transport',
|
||||||
|
level : 'warn',
|
||||||
|
webhookUrl: slackWebHook,
|
||||||
|
channel : slackErrorChannel,
|
||||||
|
username : 'spee.ch',
|
||||||
|
iconEmoji : ':face_with_head_bandage:',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (slackInfoChannel) {
|
||||||
|
winston.add(winstonSlackWebHook, {
|
||||||
|
name : 'slack-info-transport',
|
||||||
|
level : 'info',
|
||||||
|
webhookUrl: slackWebHook,
|
||||||
|
channel : slackInfoChannel,
|
||||||
|
username : 'spee.ch',
|
||||||
|
iconEmoji : ':nerd_face:',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// send test message
|
||||||
|
winston.error('Slack "error" logging is online.');
|
||||||
|
winston.info('Slack "info" logging is online.');
|
||||||
|
} else {
|
||||||
|
winston.warn('Slack logging is not enabled because no slackWebHook config var provided.');
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,6 +1,6 @@
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const ua = require('universal-analytics');
|
const ua = require('universal-analytics');
|
||||||
const { analytics : { googleId }, site: { name: siteName } } = require('../config/speechConfig.js');
|
const { analytics : { googleId }, details: { title } } = require('../config/siteConfig.js');
|
||||||
|
|
||||||
function createServeEventParams (headers, ip, originalUrl) {
|
function createServeEventParams (headers, ip, originalUrl) {
|
||||||
return {
|
return {
|
||||||
|
@ -49,7 +49,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
sendGATimingEvent (category, variable, label, startTime, endTime) {
|
sendGATimingEvent (category, variable, label, startTime, endTime) {
|
||||||
const params = createPublishTimingEventParams(category, variable, label, startTime, endTime);
|
const params = createPublishTimingEventParams(category, variable, label, startTime, endTime);
|
||||||
sendGoogleAnalyticsTiming(siteName, params);
|
sendGoogleAnalyticsTiming(title, params);
|
||||||
},
|
},
|
||||||
chooseGaLbrynetPublishLabel ({ channel_name: channelName, channel_id: channelId }) {
|
chooseGaLbrynetPublishLabel ({ channel_name: channelName, channel_id: channelId }) {
|
||||||
return (channelName || channelId ? 'PUBLISH_IN_CHANNEL_CLAIM' : 'PUBLISH_ANONYMOUS_CLAIM');
|
return (channelName || channelId ? 'PUBLISH_IN_CHANNEL_CLAIM' : 'PUBLISH_ANONYMOUS_CLAIM');
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const config = require('../config/speechConfig.js');
|
const { api: { apiHost, apiPort } } = require('../config/lbryConfig.js');
|
||||||
const { apiHost, apiPort } = config.api;
|
|
||||||
const lbryApiUri = 'http://' + apiHost + ':' + apiPort;
|
const lbryApiUri = 'http://' + apiHost + ':' + apiPort;
|
||||||
const { chooseGaLbrynetPublishLabel, sendGATimingEvent } = require('./googleAnalytics.js');
|
const { chooseGaLbrynetPublishLabel, sendGATimingEvent } = require('./googleAnalytics.js');
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { site, publish } = require('../config/speechConfig.js');
|
|
||||||
|
const { details, publishing } = require('../config/siteConfig.js');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
parsePublishApiRequestBody ({name, nsfw, license, title, description, thumbnail}) {
|
parsePublishApiRequestBody ({name, nsfw, license, title, description, thumbnail}) {
|
||||||
|
@ -109,12 +110,12 @@ module.exports = {
|
||||||
metadata : {
|
metadata : {
|
||||||
description,
|
description,
|
||||||
title,
|
title,
|
||||||
author : site.title,
|
author : details.title,
|
||||||
language: 'en',
|
language: 'en',
|
||||||
license,
|
license,
|
||||||
nsfw,
|
nsfw,
|
||||||
},
|
},
|
||||||
claim_address: publish.primaryClaimAddress,
|
claim_address: publishing.primaryClaimAddress,
|
||||||
};
|
};
|
||||||
// add thumbnail to channel if video
|
// add thumbnail to channel if video
|
||||||
if (thumbnail) {
|
if (thumbnail) {
|
||||||
|
@ -135,14 +136,14 @@ module.exports = {
|
||||||
metadata : {
|
metadata : {
|
||||||
title : `${claimName} thumbnail`,
|
title : `${claimName} thumbnail`,
|
||||||
description: `a thumbnail for ${claimName}`,
|
description: `a thumbnail for ${claimName}`,
|
||||||
author : site.title,
|
author : details.title,
|
||||||
language : 'en',
|
language : 'en',
|
||||||
license,
|
license,
|
||||||
nsfw,
|
nsfw,
|
||||||
},
|
},
|
||||||
claim_address: publish.primaryClaimAddress,
|
claim_address: publishing.primaryClaimAddress,
|
||||||
channel_name : publish.thumbnailChannel,
|
channel_name : publishing.thumbnailChannel,
|
||||||
channel_id : publish.thumbnailChannelId,
|
channel_id : publishing.thumbnailChannelId,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
deleteTemporaryFile (filePath) {
|
deleteTemporaryFile (filePath) {
|
||||||
|
|
86
index.js
86
index.js
File diff suppressed because one or more lines are too long
1
index.js.map
Normal file
1
index.js.map
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,6 @@
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const { returnShortId } = require('../helpers/sequelizeHelpers.js');
|
const { returnShortId } = require('../helpers/sequelizeHelpers.js');
|
||||||
const { claim, site } = require('../config/speechConfig.js');
|
const { assetDefaults: { thumbnail: defaultThumbnail }, details: { host } } = require('../config/siteConfig.js');
|
||||||
const { defaultThumbnail } = claim;
|
|
||||||
|
|
||||||
function determineFileExtensionFromContentType (contentType) {
|
function determineFileExtensionFromContentType (contentType) {
|
||||||
switch (contentType) {
|
switch (contentType) {
|
||||||
|
@ -31,7 +30,7 @@ function prepareClaimData (claim) {
|
||||||
// logger.debug('preparing claim data based on resolved data:', claim);
|
// logger.debug('preparing claim data based on resolved data:', claim);
|
||||||
claim['thumbnail'] = determineThumbnail(claim.thumbnail, defaultThumbnail);
|
claim['thumbnail'] = determineThumbnail(claim.thumbnail, defaultThumbnail);
|
||||||
claim['fileExt'] = determineFileExtensionFromContentType(claim.contentType);
|
claim['fileExt'] = determineFileExtensionFromContentType(claim.contentType);
|
||||||
claim['host'] = site.host;
|
claim['host'] = host;
|
||||||
return claim;
|
return claim;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
const Sequelize = require('sequelize');
|
const Sequelize = require('sequelize');
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const config = require('../config/speechConfig.js');
|
|
||||||
const { database, username, password } = config.sql;
|
|
||||||
const db = {};
|
|
||||||
|
|
||||||
|
console.log('exporting sequelize models');
|
||||||
|
const { database, username, password } = require('../config/mysqlConfig');
|
||||||
|
const db = {};
|
||||||
// set sequelize options
|
// set sequelize options
|
||||||
const sequelize = new Sequelize(database, username, password, {
|
const sequelize = new Sequelize(database, username, password, {
|
||||||
host : 'localhost',
|
host : 'localhost',
|
||||||
|
@ -18,6 +18,7 @@ const sequelize = new Sequelize(database, username, password, {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// establish mysql connection
|
||||||
sequelize
|
sequelize
|
||||||
.authenticate()
|
.authenticate()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -27,7 +28,7 @@ sequelize
|
||||||
logger.error('Sequelize was unable to connect to the database:', err);
|
logger.error('Sequelize was unable to connect to the database:', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
// manually add each model to the db
|
// manually add each model to the db object
|
||||||
const Certificate = require('./certificate.js');
|
const Certificate = require('./certificate.js');
|
||||||
const Channel = require('./channel.js');
|
const Channel = require('./channel.js');
|
||||||
const Claim = require('./claim.js');
|
const Claim = require('./claim.js');
|
||||||
|
@ -55,7 +56,9 @@ db.Sequelize = Sequelize;
|
||||||
// add an 'upsert' method to the db object
|
// add an 'upsert' method to the db object
|
||||||
db.upsert = (Model, values, condition, tableName) => {
|
db.upsert = (Model, values, condition, tableName) => {
|
||||||
return Model
|
return Model
|
||||||
.findOne({ where: condition })
|
.findOne({
|
||||||
|
where: condition,
|
||||||
|
})
|
||||||
.then(obj => {
|
.then(obj => {
|
||||||
if (obj) { // update
|
if (obj) { // update
|
||||||
logger.debug(`updating record in db.${tableName}`);
|
logger.debug(`updating record in db.${tableName}`);
|
||||||
|
@ -71,9 +74,4 @@ db.upsert = (Model, values, condition, tableName) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// add a 'getTrendingFiles' method to the db object. note: change this to get claims directly. might need new association between Request and Claim
|
|
||||||
db.getTrendingFiles = (startDate) => {
|
|
||||||
return db.sequelize.query(`SELECT COUNT(*), File.* FROM Request LEFT JOIN File ON Request.FileId = File.id WHERE FileId IS NOT NULL AND nsfw != 1 AND trendingEligible = 1 AND Request.createdAt > "${startDate}" GROUP BY FileId ORDER BY COUNT(*) DESC LIMIT 25;`, { type: db.sequelize.QueryTypes.SELECT });
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = db;
|
module.exports = db;
|
||||||
|
|
13
package.json
13
package.json
|
@ -1,19 +1,19 @@
|
||||||
{
|
{
|
||||||
"name": "spee.ch",
|
"name": "spee.ch",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "a single-serving site that reads and publishes images to and from the LBRY blockchain",
|
"description": "a web application that reads and publishes images to and from the LBRY blockchain",
|
||||||
"main": "speech.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "mocha --recursive",
|
"test": "mocha --recursive",
|
||||||
"test-all": "mocha --recursive",
|
"test-all": "mocha --recursive",
|
||||||
"start": "node server.js",
|
"start": "node index.js",
|
||||||
"start-dev": "nodemon server.js",
|
"start-dev": "nodemon index.js",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"fix": "eslint . --fix",
|
"fix": "eslint . --fix",
|
||||||
"precommit": "eslint .",
|
"precommit": "eslint .",
|
||||||
"babel": "babel",
|
"babel": "babel",
|
||||||
"build-dev": "webpack --config webpack.dev.js",
|
"build-dev": "webpack --config webpack.dev.js",
|
||||||
"build-prod": "webpack --config webpack.prod.js"
|
"build": "webpack --config webpack.prod.js"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -34,6 +34,7 @@
|
||||||
"axios": "^0.16.1",
|
"axios": "^0.16.1",
|
||||||
"bcrypt": "^1.0.3",
|
"bcrypt": "^1.0.3",
|
||||||
"body-parser": "^1.17.1",
|
"body-parser": "^1.17.1",
|
||||||
|
"babel-polyfill": "^6.26.0",
|
||||||
"config": "^1.26.1",
|
"config": "^1.26.1",
|
||||||
"connect-multiparty": "^2.0.0",
|
"connect-multiparty": "^2.0.0",
|
||||||
"cookie-session": "^2.0.0-beta.3",
|
"cookie-session": "^2.0.0-beta.3",
|
||||||
|
@ -59,7 +60,6 @@
|
||||||
"request-promise": "^4.2.2",
|
"request-promise": "^4.2.2",
|
||||||
"sequelize": "^4.1.0",
|
"sequelize": "^4.1.0",
|
||||||
"sequelize-cli": "^3.0.0-3",
|
"sequelize-cli": "^3.0.0-3",
|
||||||
"sleep": "^5.1.1",
|
|
||||||
"universal-analytics": "^0.4.13",
|
"universal-analytics": "^0.4.13",
|
||||||
"webpack-node-externals": "^1.6.0",
|
"webpack-node-externals": "^1.6.0",
|
||||||
"whatwg-fetch": "^2.0.3",
|
"whatwg-fetch": "^2.0.3",
|
||||||
|
@ -70,7 +70,6 @@
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.0",
|
||||||
"babel-loader": "^7.1.2",
|
"babel-loader": "^7.1.2",
|
||||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||||
"babel-polyfill": "^6.26.0",
|
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
"babel-preset-stage-2": "^6.24.1",
|
"babel-preset-stage-2": "^6.24.1",
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
const PassportLocalStrategy = require('passport-local').Strategy;
|
const PassportLocalStrategy = require('passport-local').Strategy;
|
||||||
const db = require('../models');
|
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
|
const db = require('../models');
|
||||||
|
|
||||||
function returnUserAndChannelInfo (userInstance) {
|
const returnUserAndChannelInfo = (userInstance) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let userInfo = {};
|
let userInfo = {};
|
||||||
userInfo['id'] = userInstance.id;
|
userInfo['id'] = userInstance.id;
|
||||||
|
@ -22,7 +22,7 @@ function returnUserAndChannelInfo (userInstance) {
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = new PassportLocalStrategy(
|
module.exports = new PassportLocalStrategy(
|
||||||
{
|
{
|
||||||
|
@ -61,5 +61,5 @@ module.exports = new PassportLocalStrategy(
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
return done(error);
|
return done(error);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const db = require('../models');
|
|
||||||
const PassportLocalStrategy = require('passport-local').Strategy;
|
const PassportLocalStrategy = require('passport-local').Strategy;
|
||||||
const lbryApi = require('../helpers/lbryApi.js');
|
const lbryApi = require('../helpers/lbryApi.js');
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
|
const db = require('../models');
|
||||||
|
|
||||||
module.exports = new PassportLocalStrategy(
|
module.exports = new PassportLocalStrategy(
|
||||||
{
|
{
|
||||||
|
|
28
public/bundle/bundle.js
Normal file
28
public/bundle/bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
public/bundle/bundle.js.map
Normal file
1
public/bundle/bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,6 @@
|
||||||
import Request from 'utils/request';
|
import Request from 'utils/request';
|
||||||
const { site: { host } } = require('../../config/speechConfig.js');
|
|
||||||
|
|
||||||
export function getLongClaimId (name, modifier) {
|
export function getLongClaimId (host, name, modifier) {
|
||||||
let body = {};
|
let body = {};
|
||||||
// create request params
|
// create request params
|
||||||
if (modifier) {
|
if (modifier) {
|
||||||
|
@ -24,12 +23,12 @@ export function getLongClaimId (name, modifier) {
|
||||||
return Request(url, params);
|
return Request(url, params);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getShortId (name, claimId) {
|
export function getShortId (host, name, claimId) {
|
||||||
const url = `${host}/api/claim/short-id/${claimId}/${name}`;
|
const url = `${host}/api/claim/short-id/${claimId}/${name}`;
|
||||||
return Request(url);
|
return Request(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getClaimData (name, claimId) {
|
export function getClaimData (host, name, claimId) {
|
||||||
const url = `${host}/api/claim/data/${name}/${claimId}`;
|
const url = `${host}/api/claim/data/${name}/${claimId}`;
|
||||||
return Request(url);
|
return Request(url);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import Request from 'utils/request';
|
import Request from 'utils/request';
|
||||||
const { site: { host } } = require('../../config/speechConfig.js');
|
|
||||||
|
|
||||||
export function getChannelData (name, id) {
|
export function getChannelData (host, id, name) {
|
||||||
if (!id) id = 'none';
|
if (!id) id = 'none';
|
||||||
const url = `${host}/api/channel/data/${name}/${id}`;
|
const url = `${host}/api/channel/data/${name}/${id}`;
|
||||||
return Request(url);
|
return Request(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getChannelClaims (name, longId, page) {
|
export function getChannelClaims (host, longId, name, page) {
|
||||||
if (!page) page = 1;
|
if (!page) page = 1;
|
||||||
const url = `${host}/api/channel/claims/${name}/${longId}/${page}`;
|
const url = `${host}/api/channel/claims/${name}/${longId}/${page}`;
|
||||||
return Request(url);
|
return Request(url);
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import Request from 'utils/request';
|
import Request from 'utils/request';
|
||||||
const { site: { host } } = require('../../config/speechConfig.js');
|
|
||||||
|
|
||||||
export function checkFileAvailability (name, claimId) {
|
export function checkFileAvailability (claimId, host, name) {
|
||||||
const url = `${host}/api/file/availability/${name}/${claimId}`;
|
const url = `${host}/api/file/availability/${name}/${claimId}`;
|
||||||
return Request(url);
|
return Request(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function triggerClaimGet (name, claimId) {
|
export function triggerClaimGet (claimId, host, name) {
|
||||||
const url = `${host}/api/claim/get/${name}/${claimId}`;
|
const url = `${host}/api/claim/get/${name}/${claimId}`;
|
||||||
return Request(url);
|
return Request(url);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import HomePage from 'components/HomePage';
|
||||||
import AboutPage from 'components/AboutPage';
|
import AboutPage from 'components/AboutPage';
|
||||||
import LoginPage from 'containers/LoginPage';
|
import LoginPage from 'containers/LoginPage';
|
||||||
import ShowPage from 'containers/ShowPage';
|
import ShowPage from 'containers/ShowPage';
|
||||||
import FourOhFourPage from 'components/FourOhFourPage';
|
import FourOhFourPage from 'containers/FourOhFourPage';
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
return (
|
return (
|
||||||
|
|
10
react/components/AssetPreview/index.js
Normal file
10
react/components/AssetPreview/index.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import View from './view';
|
||||||
|
|
||||||
|
const mapStateToProps = ({site: {defaults: { defaultThumbnail }}}) => {
|
||||||
|
return {
|
||||||
|
defaultThumbnail,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(View);
|
|
@ -1,8 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
const { claim: { defaultThumbnail } } = require('../../../config/speechConfig.js');
|
|
||||||
|
|
||||||
const AssetPreview = ({ claimData: { name, claimId, fileExt, contentType, thumbnail } }) => {
|
const AssetPreview = ({ defaultThumbnail, claimData: { name, claimId, fileExt, contentType, thumbnail } }) => {
|
||||||
const directSourceLink = `${claimId}/${name}.${fileExt}`;
|
const directSourceLink = `${claimId}/${name}.${fileExt}`;
|
||||||
const showUrlLink = `/${claimId}/${name}`;
|
const showUrlLink = `/${claimId}/${name}`;
|
||||||
return (
|
return (
|
|
@ -1,10 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import GoogleAnalytics from 'react-ga';
|
import GoogleAnalytics from 'react-ga';
|
||||||
import { withRouter } from 'react-router-dom';
|
import { withRouter } from 'react-router-dom';
|
||||||
const config = require('../../../config/speechConfig.js');
|
const { analytics: { googleId } } = require('../../../config/siteConfig.js');
|
||||||
const googleApiKey = config.analytics.googleId;
|
|
||||||
|
|
||||||
GoogleAnalytics.initialize(googleApiKey);
|
GoogleAnalytics.initialize(googleId);
|
||||||
|
|
||||||
class GAListener extends React.Component {
|
class GAListener extends React.Component {
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
class Preview extends React.Component {
|
class PublishPreview extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -53,10 +53,10 @@ class Preview extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Preview.propTypes = {
|
PublishPreview.propTypes = {
|
||||||
dimPreview: PropTypes.bool.isRequired,
|
dimPreview: PropTypes.bool.isRequired,
|
||||||
file : PropTypes.object.isRequired,
|
file : PropTypes.object.isRequired,
|
||||||
thumbnail : PropTypes.object,
|
thumbnail : PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Preview;
|
export default PublishPreview;
|
16
react/components/SEO/index.js
Normal file
16
react/components/SEO/index.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import View from './view';
|
||||||
|
|
||||||
|
const mapStateToProps = ({ site }) => {
|
||||||
|
const { defaultDescription, defaultThumbnail, description: siteDescription, host: siteHost, title: siteTitle, twitter: siteTwitter } = site;
|
||||||
|
return {
|
||||||
|
defaultDescription,
|
||||||
|
defaultThumbnail,
|
||||||
|
siteDescription,
|
||||||
|
siteHost,
|
||||||
|
siteTitle,
|
||||||
|
siteTwitter,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(View);
|
|
@ -8,10 +8,16 @@ import { createCanonicalLink } from 'utils/canonicalLink';
|
||||||
|
|
||||||
class SEO extends React.Component {
|
class SEO extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
let { pageTitle, asset, channel, pageUri } = this.props;
|
// props from state
|
||||||
pageTitle = createPageTitle(pageTitle);
|
const { defaultDescription, defaultThumbnail, siteDescription, siteHost, siteTitle, siteTwitter } = this.props;
|
||||||
const metaTags = createMetaTags(asset, channel);
|
// props from parent
|
||||||
const canonicalLink = createCanonicalLink(asset, channel, pageUri);
|
const { asset, channel, pageUri } = this.props;
|
||||||
|
let { pageTitle } = this.props;
|
||||||
|
// create page title, tags, and canonical link
|
||||||
|
pageTitle = createPageTitle(siteTitle, pageTitle);
|
||||||
|
const metaTags = createMetaTags(siteDescription, siteHost, siteTitle, siteTwitter, asset, channel, defaultDescription, defaultThumbnail);
|
||||||
|
const canonicalLink = createCanonicalLink(asset, channel, pageUri, siteHost);
|
||||||
|
// render results
|
||||||
return (
|
return (
|
||||||
<Helmet
|
<Helmet
|
||||||
title={pageTitle}
|
title={pageTitle}
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { validateFile } from 'utils/file';
|
import { validateFile } from 'utils/file';
|
||||||
import Preview from 'components/Preview';
|
import PublishPreview from 'components/PublishPreview';
|
||||||
|
|
||||||
class Dropzone extends React.Component {
|
class Dropzone extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
|
@ -87,7 +87,7 @@ class Dropzone extends React.Component {
|
||||||
<div id='preview-dropzone' className={'row row--padded row--tall dropzone' + (this.state.dragOver ? ' dropzone--drag-over' : '')} onDrop={this.handleDrop} onDragOver={this.handleDragOver} onDragEnd={this.handleDragEnd} onDragEnter={this.handleDragEnter} onDragLeave={this.handleDragLeave} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} onClick={this.handleClick}>
|
<div id='preview-dropzone' className={'row row--padded row--tall dropzone' + (this.state.dragOver ? ' dropzone--drag-over' : '')} onDrop={this.handleDrop} onDragOver={this.handleDragOver} onDragEnd={this.handleDragEnd} onDragEnter={this.handleDragEnter} onDragLeave={this.handleDragLeave} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} onClick={this.handleClick}>
|
||||||
{this.props.file ? (
|
{this.props.file ? (
|
||||||
<div>
|
<div>
|
||||||
<Preview
|
<PublishPreview
|
||||||
dimPreview={this.state.dimPreview}
|
dimPreview={this.state.dimPreview}
|
||||||
file={this.props.file}
|
file={this.props.file}
|
||||||
thumbnail={this.props.thumbnail}
|
thumbnail={this.props.thumbnail}
|
||||||
|
|
11
react/containers/FourOhFourPage/index.jsx
Normal file
11
react/containers/FourOhFourPage/index.jsx
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import View from './view';
|
||||||
|
|
||||||
|
const mapStateToProps = ({ site: { host, title } }) => {
|
||||||
|
return {
|
||||||
|
host,
|
||||||
|
title,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(View);
|
|
@ -1,10 +1,10 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import NavBar from 'containers/NavBar';
|
import NavBar from 'containers/NavBar';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
const { site: { title, host } } = require('../../../config/speechConfig.js');
|
|
||||||
|
|
||||||
class FourOhForPage extends React.Component {
|
class FourOhForPage extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
|
const {title, host} = this.props;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Helmet>
|
<Helmet>
|
|
@ -1,13 +1,14 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { updateLoggedInChannel } from 'actions/channel';
|
import { updateLoggedInChannel } from 'actions/channel';
|
||||||
|
import {updateSelectedChannel} from 'actions/publish';
|
||||||
import View from './view';
|
import View from './view';
|
||||||
import {updateSelectedChannel} from '../../actions/publish';
|
|
||||||
|
|
||||||
const mapStateToProps = ({ channel }) => {
|
const mapStateToProps = ({ channel, site }) => {
|
||||||
return {
|
return {
|
||||||
channelName : channel.loggedInChannel.name,
|
channelName : channel.loggedInChannel.name,
|
||||||
channelShortId: channel.loggedInChannel.shortId,
|
channelShortId: channel.loggedInChannel.shortId,
|
||||||
channelLongId : channel.loggedInChannel.longId,
|
channelLongId : channel.loggedInChannel.longId,
|
||||||
|
siteDescription: site.description,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,12 +53,13 @@ class NavBar extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
|
const { siteDescription } = this.props;
|
||||||
return (
|
return (
|
||||||
<div className='row row--wide nav-bar'>
|
<div className='row row--wide nav-bar'>
|
||||||
<div className='row row--padded row--short flex-container--row flex-container--space-between-center'>
|
<div className='row row--padded row--short flex-container--row flex-container--space-between-center'>
|
||||||
<Logo />
|
<Logo />
|
||||||
<div className='nav-bar--center'>
|
<div className='nav-bar--center'>
|
||||||
<span className='nav-bar-tagline'>Open-source, decentralized image and video sharing.</span>
|
<span className='nav-bar-tagline'>{siteDescription}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className='nav-bar--right'>
|
<div className='nav-bar--right'>
|
||||||
<NavLink className='nav-bar-link link--nav' activeClassName='link--nav-active' to='/' exact>Publish</NavLink>
|
<NavLink className='nav-bar-link link--nav' activeClassName='link--nav-active' to='/' exact>Publish</NavLink>
|
||||||
|
|
10
react/containers/PublishDisabledMessage/index.js
Normal file
10
react/containers/PublishDisabledMessage/index.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import View from './view';
|
||||||
|
|
||||||
|
const mapStateToProps = ({ publish }) => {
|
||||||
|
return {
|
||||||
|
message: publish.disabledMessage,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(View);
|
16
react/containers/PublishDisabledMessage/view.jsx
Normal file
16
react/containers/PublishDisabledMessage/view.jsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class PublishDisabledMessage extends React.Component {
|
||||||
|
render () {
|
||||||
|
const message = this.props.message;
|
||||||
|
console.log('this.props.message:', message);
|
||||||
|
return (
|
||||||
|
<div className='row dropzone--disabled row--tall flex-container--column flex-container--center-center'>
|
||||||
|
<p className='text--disabled'>Publishing is currently disabled.</p>
|
||||||
|
<p className='text--disabled'>{message}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PublishDisabledMessage;
|
|
@ -2,27 +2,28 @@ import React from 'react';
|
||||||
import Dropzone from 'containers/Dropzone';
|
import Dropzone from 'containers/Dropzone';
|
||||||
import PublishDetails from 'containers/PublishDetails';
|
import PublishDetails from 'containers/PublishDetails';
|
||||||
import PublishStatus from 'containers/PublishStatus';
|
import PublishStatus from 'containers/PublishStatus';
|
||||||
|
import PublishDisabledMessage from 'containers/PublishDisabledMessage';
|
||||||
|
|
||||||
class PublishTool extends React.Component {
|
class PublishTool extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
if (this.props.disabled) {
|
if (this.props.disabled) {
|
||||||
|
console.log('publish is disabled');
|
||||||
return (
|
return (
|
||||||
<div className='row dropzone--disabled row--tall flex-container--column flex-container--center-center'>
|
<PublishDisabledMessage />
|
||||||
<p className='text--disabled'>Publishing is temporarily disabled.</p>
|
|
||||||
<p className='text--disabled'>Please check back soon or join our <a className='link--disabled-text' href='https://discord.gg/YjYbwhS'>discord channel</a> for updates.</p>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
if (this.props.file) {
|
console.log('publish is not disabled');
|
||||||
if (this.props.status) {
|
if (this.props.file) {
|
||||||
return (
|
if (this.props.status) {
|
||||||
<PublishStatus />
|
return (
|
||||||
);
|
<PublishStatus />
|
||||||
} else {
|
);
|
||||||
return <PublishDetails />;
|
} else {
|
||||||
|
return <PublishDetails />;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return <Dropzone />;
|
||||||
}
|
}
|
||||||
return <Dropzone />;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import * as actions from 'constants/publish_action_types';
|
import * as actions from 'constants/publish_action_types';
|
||||||
import { LOGIN } from 'constants/publish_channel_select_states';
|
import { LOGIN } from 'constants/publish_channel_select_states';
|
||||||
const { publish } = require('../../config/speechConfig.js');
|
const { publishing } = require('../../config/siteConfig.js');
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
disabled : publish.disabled,
|
disabled : publishing.disabled,
|
||||||
|
disabledMessage : publishing.disabledMessage,
|
||||||
publishInChannel : false,
|
publishInChannel : false,
|
||||||
selectedChannel : LOGIN,
|
selectedChannel : LOGIN,
|
||||||
showMetadataInputs: false,
|
showMetadataInputs: false,
|
||||||
|
@ -25,9 +26,7 @@ const initialState = {
|
||||||
license : '',
|
license : '',
|
||||||
nsfw : false,
|
nsfw : false,
|
||||||
},
|
},
|
||||||
thumbnailChannel : publish.thumbnailChannel,
|
thumbnail: null,
|
||||||
thumbnailChannelId: publish.thumbnailChannelId,
|
|
||||||
thumbnail : null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function (state = initialState, action) {
|
export default function (state = initialState, action) {
|
||||||
|
|
|
@ -1,7 +1,29 @@
|
||||||
const { site } = require('../../config/speechConfig.js');
|
const siteConfig = require('../../config/siteConfig.js');
|
||||||
|
|
||||||
|
const {
|
||||||
|
analytics: {
|
||||||
|
googleId: googleAnalyticsId,
|
||||||
|
},
|
||||||
|
assetDefaults: {
|
||||||
|
thumbnail: defaultThumbnail,
|
||||||
|
description: defaultDescription,
|
||||||
|
},
|
||||||
|
details: {
|
||||||
|
description,
|
||||||
|
host,
|
||||||
|
title,
|
||||||
|
twitter,
|
||||||
|
},
|
||||||
|
} = siteConfig;
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
host: site.host,
|
description,
|
||||||
|
googleAnalyticsId,
|
||||||
|
host,
|
||||||
|
title,
|
||||||
|
twitter,
|
||||||
|
defaultDescription,
|
||||||
|
defaultThumbnail,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function (state = initialState, action) {
|
export default function (state = initialState, action) {
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import { call, put, takeLatest } from 'redux-saga/effects';
|
import {call, put, select, takeLatest} from 'redux-saga/effects';
|
||||||
import * as actions from 'constants/show_action_types';
|
import * as actions from 'constants/show_action_types';
|
||||||
import { updateFileAvailability, updateDisplayAssetError } from 'actions/show';
|
import { updateFileAvailability, updateDisplayAssetError } from 'actions/show';
|
||||||
import { UNAVAILABLE, AVAILABLE } from 'constants/asset_display_states';
|
import { UNAVAILABLE, AVAILABLE } from 'constants/asset_display_states';
|
||||||
import { checkFileAvailability, triggerClaimGet } from 'api/fileApi';
|
import { checkFileAvailability, triggerClaimGet } from 'api/fileApi';
|
||||||
|
import { selectSiteHost } from 'selectors/site';
|
||||||
|
|
||||||
function * retrieveFile (action) {
|
function * retrieveFile (action) {
|
||||||
const name = action.data.name;
|
const name = action.data.name;
|
||||||
const claimId = action.data.claimId;
|
const claimId = action.data.claimId;
|
||||||
|
const host = yield select(selectSiteHost);
|
||||||
// see if the file is available
|
// see if the file is available
|
||||||
let isAvailable;
|
let isAvailable;
|
||||||
try {
|
try {
|
||||||
({ data: isAvailable } = yield call(checkFileAvailability, name, claimId));
|
({ data: isAvailable } = yield call(checkFileAvailability, claimId, host, name));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return yield put(updateDisplayAssetError(error.message));
|
return yield put(updateDisplayAssetError(error.message));
|
||||||
};
|
};
|
||||||
|
@ -21,7 +23,7 @@ function * retrieveFile (action) {
|
||||||
yield put(updateFileAvailability(UNAVAILABLE));
|
yield put(updateFileAvailability(UNAVAILABLE));
|
||||||
// initiate get request for the file
|
// initiate get request for the file
|
||||||
try {
|
try {
|
||||||
yield call(triggerClaimGet, name, claimId);
|
yield call(triggerClaimGet, claimId, host, name);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return yield put(updateDisplayAssetError(error.message));
|
return yield put(updateDisplayAssetError(error.message));
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ import * as actions from 'constants/show_action_types';
|
||||||
import { addRequestToRequestList, onRequestError, onRequestUpdate, addAssetToAssetList } from 'actions/show';
|
import { addRequestToRequestList, onRequestError, onRequestUpdate, addAssetToAssetList } from 'actions/show';
|
||||||
import { getLongClaimId, getShortId, getClaimData } from 'api/assetApi';
|
import { getLongClaimId, getShortId, getClaimData } from 'api/assetApi';
|
||||||
import { selectShowState } from 'selectors/show';
|
import { selectShowState } from 'selectors/show';
|
||||||
|
import { selectSiteHost } from 'selectors/site';
|
||||||
|
|
||||||
export function * newAssetRequest (action) {
|
export function * newAssetRequest (action) {
|
||||||
const { requestType, requestId, name, modifier } = action.data;
|
const { requestType, requestId, name, modifier } = action.data;
|
||||||
|
@ -11,13 +12,14 @@ export function * newAssetRequest (action) {
|
||||||
// is this an existing request?
|
// is this an existing request?
|
||||||
// If this uri is in the request list, it's already been fetched
|
// If this uri is in the request list, it's already been fetched
|
||||||
const state = yield select(selectShowState);
|
const state = yield select(selectShowState);
|
||||||
|
const host = yield select(selectSiteHost);
|
||||||
if (state.requestList[requestId]) {
|
if (state.requestList[requestId]) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// get long id && add request to request list
|
// get long id && add request to request list
|
||||||
let longId;
|
let longId;
|
||||||
try {
|
try {
|
||||||
({data: longId} = yield call(getLongClaimId, name, modifier));
|
({data: longId} = yield call(getLongClaimId, host, name, modifier));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return yield put(onRequestError(error.message));
|
return yield put(onRequestError(error.message));
|
||||||
}
|
}
|
||||||
|
@ -31,14 +33,14 @@ export function * newAssetRequest (action) {
|
||||||
// get short Id
|
// get short Id
|
||||||
let shortId;
|
let shortId;
|
||||||
try {
|
try {
|
||||||
({data: shortId} = yield call(getShortId, name, longId));
|
({data: shortId} = yield call(getShortId, host, name, longId));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return yield put(onRequestError(error.message));
|
return yield put(onRequestError(error.message));
|
||||||
}
|
}
|
||||||
// get asset claim data
|
// get asset claim data
|
||||||
let claimData;
|
let claimData;
|
||||||
try {
|
try {
|
||||||
({data: claimData} = yield call(getClaimData, name, longId));
|
({data: claimData} = yield call(getClaimData, host, name, longId));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return yield put(onRequestError(error.message));
|
return yield put(onRequestError(error.message));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import * as actions from 'constants/show_action_types';
|
||||||
import { addNewChannelToChannelList, addRequestToRequestList, onRequestError, onRequestUpdate, updateChannelClaims } from 'actions/show';
|
import { addNewChannelToChannelList, addRequestToRequestList, onRequestError, onRequestUpdate, updateChannelClaims } from 'actions/show';
|
||||||
import { getChannelClaims, getChannelData } from 'api/channelApi';
|
import { getChannelClaims, getChannelData } from 'api/channelApi';
|
||||||
import { selectShowState } from 'selectors/show';
|
import { selectShowState } from 'selectors/show';
|
||||||
|
import { selectSiteHost } from 'selectors/site';
|
||||||
|
|
||||||
export function * newChannelRequest (action) {
|
export function * newChannelRequest (action) {
|
||||||
const { requestType, requestId, channelName, channelId } = action.data;
|
const { requestType, requestId, channelName, channelId } = action.data;
|
||||||
|
@ -11,13 +12,14 @@ export function * newChannelRequest (action) {
|
||||||
// is this an existing request?
|
// is this an existing request?
|
||||||
// If this uri is in the request list, it's already been fetched
|
// If this uri is in the request list, it's already been fetched
|
||||||
const state = yield select(selectShowState);
|
const state = yield select(selectShowState);
|
||||||
|
const host = yield select(selectSiteHost);
|
||||||
if (state.requestList[requestId]) {
|
if (state.requestList[requestId]) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// get channel long id
|
// get channel long id
|
||||||
let longId, shortId;
|
let longId, shortId;
|
||||||
try {
|
try {
|
||||||
({ data: {longChannelClaimId: longId, shortChannelClaimId: shortId} } = yield call(getChannelData, channelName, channelId));
|
({ data: {longChannelClaimId: longId, shortChannelClaimId: shortId} } = yield call(getChannelData, host, channelName, channelId));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return yield put(onRequestError(error.message));
|
return yield put(onRequestError(error.message));
|
||||||
}
|
}
|
||||||
|
@ -32,7 +34,7 @@ export function * newChannelRequest (action) {
|
||||||
// get channel claims data
|
// get channel claims data
|
||||||
let claimsData;
|
let claimsData;
|
||||||
try {
|
try {
|
||||||
({ data: claimsData } = yield call(getChannelClaims, channelName, longId, 1));
|
({ data: claimsData } = yield call(getChannelClaims, host, longId, channelName, 1));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return yield put(onRequestError(error.message));
|
return yield put(onRequestError(error.message));
|
||||||
}
|
}
|
||||||
|
@ -48,9 +50,10 @@ export function * watchNewChannelRequest () {
|
||||||
|
|
||||||
function * getNewClaimsAndUpdateChannel (action) {
|
function * getNewClaimsAndUpdateChannel (action) {
|
||||||
const { channelKey, name, longId, page } = action.data;
|
const { channelKey, name, longId, page } = action.data;
|
||||||
|
const host = yield select(selectSiteHost);
|
||||||
let claimsData;
|
let claimsData;
|
||||||
try {
|
try {
|
||||||
({ data: claimsData } = yield call(getChannelClaims, name, longId, page));
|
({ data: claimsData } = yield call(getChannelClaims, host, longId, name, page));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return yield put(onRequestError(error.message));
|
return yield put(onRequestError(error.message));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
export const selectSiteState = (state) => {
|
export const selectSiteState = (state) => {
|
||||||
return state.site;
|
return state.site;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const selectSiteHost = (state) => {
|
||||||
|
return state.site.host;
|
||||||
|
};
|
||||||
|
|
|
@ -1,37 +1,29 @@
|
||||||
const { site: { host } } = require('../../config/speechConfig.js');
|
const createBasicCanonicalLink = (page, siteHost) => {
|
||||||
|
return `${siteHost}/${page}`;
|
||||||
const createBasicCanonicalLink = (page) => {
|
|
||||||
if (!page) {
|
|
||||||
return `${host}`;
|
|
||||||
};
|
|
||||||
return `${host}/${page}`;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const createAssetCanonicalLink = (asset) => {
|
const createAssetCanonicalLink = (asset, siteHost) => {
|
||||||
let channelName, certificateId, name, claimId;
|
let channelName, certificateId, name, claimId;
|
||||||
if (asset.claimData) {
|
if (asset.claimData) {
|
||||||
({ channelName, certificateId, name, claimId } = asset.claimData);
|
({ channelName, certificateId, name, claimId } = asset.claimData);
|
||||||
};
|
};
|
||||||
if (channelName) {
|
if (channelName) {
|
||||||
return `${host}/${channelName}:${certificateId}/${name}`;
|
return `${siteHost}/${channelName}:${certificateId}/${name}`;
|
||||||
};
|
};
|
||||||
return `${host}/${claimId}/${name}`;
|
return `${siteHost}/${claimId}/${name}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createChannelCanonicalLink = (channel) => {
|
const createChannelCanonicalLink = (channel, siteHost) => {
|
||||||
const { name, longId } = channel;
|
const { name, longId } = channel;
|
||||||
return `${host}/${name}:${longId}`;
|
return `${siteHost}/${name}:${longId}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createCanonicalLink = (asset, channel, page) => {
|
export const createCanonicalLink = (asset, channel, page, siteHost) => {
|
||||||
if (asset) {
|
if (asset) {
|
||||||
return createAssetCanonicalLink(asset);
|
return createAssetCanonicalLink(asset, siteHost);
|
||||||
}
|
}
|
||||||
if (channel) {
|
if (channel) {
|
||||||
return createChannelCanonicalLink(channel);
|
return createChannelCanonicalLink(channel, siteHost);
|
||||||
}
|
}
|
||||||
if (page) {
|
return createBasicCanonicalLink(page, siteHost);
|
||||||
return createBasicCanonicalLink(page);
|
|
||||||
}
|
|
||||||
return createBasicCanonicalLink();
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
const { site: { title, host, description }, claim: { defaultThumbnail, defaultDescription } } = require('../../config/speechConfig.js');
|
|
||||||
|
|
||||||
const determineOgThumbnailContentType = (thumbnail) => {
|
const determineOgThumbnailContentType = (thumbnail) => {
|
||||||
if (thumbnail) {
|
if (thumbnail) {
|
||||||
const fileExt = thumbnail.substring(thumbnail.lastIndexOf('.'));
|
const fileExt = thumbnail.substring(thumbnail.lastIndexOf('.'));
|
||||||
|
@ -20,35 +18,35 @@ const determineOgThumbnailContentType = (thumbnail) => {
|
||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const createBasicMetaTags = () => {
|
const createBasicMetaTags = (siteHost, siteDescription, siteTitle, siteTwitter) => {
|
||||||
return [
|
return [
|
||||||
{property: 'og:title', content: title},
|
{property: 'og:title', content: siteTitle},
|
||||||
{property: 'og:url', content: host},
|
{property: 'og:url', content: siteHost},
|
||||||
{property: 'og:site_name', content: title},
|
{property: 'og:site_name', content: siteTitle},
|
||||||
{property: 'og:description', content: description},
|
{property: 'og:description', content: siteDescription},
|
||||||
{property: 'twitter:site', content: '@spee_ch'},
|
{property: 'twitter:site', content: siteTwitter},
|
||||||
{property: 'twitter:card', content: 'summary'},
|
{property: 'twitter:card', content: 'summary'},
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
const createChannelMetaTags = (channel) => {
|
const createChannelMetaTags = (siteTitle, siteHost, siteTwitter, channel) => {
|
||||||
const { name, longId } = channel;
|
const { name, longId } = channel;
|
||||||
return [
|
return [
|
||||||
{property: 'og:title', content: `${name} on ${title}`},
|
{property: 'og:title', content: `${name} on ${siteTitle}`},
|
||||||
{property: 'og:url', content: `${host}/${name}:${longId}`},
|
{property: 'og:url', content: `${siteHost}/${name}:${longId}`},
|
||||||
{property: 'og:site_name', content: title},
|
{property: 'og:site_name', content: siteTitle},
|
||||||
{property: 'og:description', content: `${name}, a channel on ${title}`},
|
{property: 'og:description', content: `${name}, a channel on ${siteTitle}`},
|
||||||
{property: 'twitter:site', content: '@spee_ch'},
|
{property: 'twitter:site', content: siteTwitter},
|
||||||
{property: 'twitter:card', content: 'summary'},
|
{property: 'twitter:card', content: 'summary'},
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
const createAssetMetaTags = (asset) => {
|
const createAssetMetaTags = (siteHost, siteTitle, siteTwitter, asset, defaultDescription, defaultThumbnail) => {
|
||||||
const { claimData } = asset;
|
const { claimData } = asset;
|
||||||
const { contentType } = claimData;
|
const { contentType } = claimData;
|
||||||
const embedUrl = `${host}/${claimData.claimId}/${claimData.name}`;
|
const embedUrl = `${siteHost}/${claimData.claimId}/${claimData.name}`;
|
||||||
const showUrl = `${host}/${claimData.claimId}/${claimData.name}`;
|
const showUrl = `${siteHost}/${claimData.claimId}/${claimData.name}`;
|
||||||
const source = `${host}/${claimData.claimId}/${claimData.name}.${claimData.fileExt}`;
|
const source = `${siteHost}/${claimData.claimId}/${claimData.name}.${claimData.fileExt}`;
|
||||||
const ogTitle = claimData.title || claimData.name;
|
const ogTitle = claimData.title || claimData.name;
|
||||||
const ogDescription = claimData.description || defaultDescription;
|
const ogDescription = claimData.description || defaultDescription;
|
||||||
const ogThumbnailContentType = determineOgThumbnailContentType(claimData.thumbnail);
|
const ogThumbnailContentType = determineOgThumbnailContentType(claimData.thumbnail);
|
||||||
|
@ -56,11 +54,11 @@ const createAssetMetaTags = (asset) => {
|
||||||
const metaTags = [
|
const metaTags = [
|
||||||
{property: 'og:title', content: ogTitle},
|
{property: 'og:title', content: ogTitle},
|
||||||
{property: 'og:url', content: showUrl},
|
{property: 'og:url', content: showUrl},
|
||||||
{property: 'og:site_name', content: title},
|
{property: 'og:site_name', content: siteTitle},
|
||||||
{property: 'og:description', content: ogDescription},
|
{property: 'og:description', content: ogDescription},
|
||||||
{property: 'og:image:width', content: 600},
|
{property: 'og:image:width', content: 600},
|
||||||
{property: 'og:image:height', content: 315},
|
{property: 'og:image:height', content: 315},
|
||||||
{property: 'twitter:site', content: '@spee_ch'},
|
{property: 'twitter:site', content: siteTwitter},
|
||||||
];
|
];
|
||||||
if (contentType === 'video/mp4' || contentType === 'video/webm') {
|
if (contentType === 'video/mp4' || contentType === 'video/webm') {
|
||||||
metaTags.push({property: 'og:video', content: source});
|
metaTags.push({property: 'og:video', content: source});
|
||||||
|
@ -85,12 +83,12 @@ const createAssetMetaTags = (asset) => {
|
||||||
return metaTags;
|
return metaTags;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createMetaTags = (asset, channel) => {
|
export const createMetaTags = (siteDescription, siteHost, siteTitle, siteTwitter, asset, channel, defaultDescription, defaultThumbnail) => {
|
||||||
if (asset) {
|
if (asset) {
|
||||||
return createAssetMetaTags(asset);
|
return createAssetMetaTags(siteHost, siteTitle, siteTwitter, asset, defaultDescription, defaultThumbnail);
|
||||||
};
|
};
|
||||||
if (channel) {
|
if (channel) {
|
||||||
return createChannelMetaTags(channel);
|
return createChannelMetaTags(siteHost, siteTitle, siteTwitter, channel);
|
||||||
};
|
};
|
||||||
return createBasicMetaTags();
|
return createBasicMetaTags(siteDescription, siteHost, siteTitle, siteTwitter);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
const { site: { title: siteTitle } } = require('../../config/speechConfig.js');
|
export const createPageTitle = (siteTitle, pageTitle) => {
|
||||||
|
|
||||||
export const createPageTitle = (pageTitle) => {
|
|
||||||
if (!pageTitle) {
|
if (!pageTitle) {
|
||||||
return `${siteTitle}`;
|
return `${siteTitle}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const multipart = require('connect-multiparty');
|
const multipart = require('connect-multiparty');
|
||||||
const { files, site } = require('../config/speechConfig.js');
|
const { publishing: { uploadDirectory }, details: { host } } = require('../config/siteConfig.js');
|
||||||
const multipartMiddleware = multipart({uploadDir: files.uploadDirectory});
|
const multipartMiddleware = multipart({uploadDir: uploadDirectory});
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const { claimNameIsAvailable, checkChannelAvailability, publish } = require('../controllers/publishController.js');
|
const { claimNameIsAvailable, checkChannelAvailability, publish } = require('../controllers/publishController.js');
|
||||||
const { getClaimList, resolveUri, getClaim } = require('../helpers/lbryApi.js');
|
const { getClaimList, resolveUri, getClaim } = require('../helpers/lbryApi.js');
|
||||||
|
@ -168,7 +168,7 @@ module.exports = (app) => {
|
||||||
data : {
|
data : {
|
||||||
name,
|
name,
|
||||||
claimId: result.claim_id,
|
claimId: result.claim_id,
|
||||||
url : `${site.host}/${result.claim_id}/${name}`,
|
url : `${host}/${result.claim_id}/${name}`,
|
||||||
lbryTx : result,
|
lbryTx : result,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,7 +15,6 @@ module.exports = (app) => {
|
||||||
// route for log in
|
// route for log in
|
||||||
app.post('/login', (req, res, next) => {
|
app.post('/login', (req, res, next) => {
|
||||||
passport.authenticate('local-login', (err, user, info) => {
|
passport.authenticate('local-login', (err, user, info) => {
|
||||||
logger.debug('info:', info);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const { site } = require('../config/speechConfig.js');
|
const { details: host } = require('../config/siteConfig.js');
|
||||||
const handlePageRender = require('../helpers/handlePageRender.jsx');
|
const handlePageRender = require('../helpers/handlePageRender.jsx');
|
||||||
|
|
||||||
module.exports = (app) => {
|
module.exports = (app) => {
|
||||||
|
@ -29,7 +29,6 @@ module.exports = (app) => {
|
||||||
app.get('/embed/:claimId/:name', ({ params }, res) => {
|
app.get('/embed/:claimId/:name', ({ params }, res) => {
|
||||||
const claimId = params.claimId;
|
const claimId = params.claimId;
|
||||||
const name = params.name;
|
const name = params.name;
|
||||||
const host = site.host;
|
|
||||||
// get and render the content
|
// get and render the content
|
||||||
res.status(200).render('embed', { layout: 'embed', host, claimId, name });
|
res.status(200).render('embed', { layout: 'embed', host, claimId, name });
|
||||||
});
|
});
|
||||||
|
|
106
server.js
Normal file
106
server.js
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
// app dependencies
|
||||||
|
const express = require('express');
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
const expressHandlebars = require('express-handlebars');
|
||||||
|
const Handlebars = require('handlebars');
|
||||||
|
const helmet = require('helmet');
|
||||||
|
const passport = require('passport');
|
||||||
|
const { populateLocalsDotUser, serializeSpeechUser, deserializeSpeechUser } = require('./helpers/authHelpers.js');
|
||||||
|
const cookieSession = require('cookie-session');
|
||||||
|
const http = require('http');
|
||||||
|
// logging dependencies
|
||||||
|
const logger = require('winston');
|
||||||
|
|
||||||
|
function SpeechServer ({ mysqlConfig, siteConfig, slackConfig }) {
|
||||||
|
this.start = () => {
|
||||||
|
this.configureConfigFiles();
|
||||||
|
this.configureLogging();
|
||||||
|
this.configureApp();
|
||||||
|
this.configureServer();
|
||||||
|
this.startServer();
|
||||||
|
};
|
||||||
|
this.configureConfigFiles = () => {
|
||||||
|
const mysqlAppConfig = require('./config/mysqlConfig.js');
|
||||||
|
mysqlAppConfig.configure(mysqlConfig);
|
||||||
|
const siteAppConfig = require('./config/siteConfig.js');
|
||||||
|
siteAppConfig.configure(siteConfig);
|
||||||
|
this.PORT = siteAppConfig.details.port;
|
||||||
|
const slackAppConfig = require('./config/slackConfig.js');
|
||||||
|
slackAppConfig.configure(slackConfig);
|
||||||
|
};
|
||||||
|
this.configureLogging = () => {
|
||||||
|
require('./helpers/configureLogger.js')(logger);
|
||||||
|
require('./helpers/configureSlack.js')(logger);
|
||||||
|
};
|
||||||
|
this.configureApp = () => {
|
||||||
|
const app = express(); // create an Express application
|
||||||
|
|
||||||
|
// trust the proxy to get ip address for us
|
||||||
|
app.enable('trust proxy');
|
||||||
|
|
||||||
|
// add middleware
|
||||||
|
app.use(helmet()); // set HTTP headers to protect against well-known web vulnerabilties
|
||||||
|
app.use(express.static(`${__dirname}/public`)); // 'express.static' to serve static files from public directory
|
||||||
|
app.use(bodyParser.json()); // 'body parser' for parsing application/json
|
||||||
|
app.use(bodyParser.urlencoded({ extended: true })); // 'body parser' for parsing application/x-www-form-urlencoded
|
||||||
|
app.use((req, res, next) => { // custom logging middleware to log all incoming http requests
|
||||||
|
logger.verbose(`Request on ${req.originalUrl} from ${req.ip}`);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
// configure passport
|
||||||
|
passport.serializeUser(serializeSpeechUser);
|
||||||
|
passport.deserializeUser(deserializeSpeechUser);
|
||||||
|
const localSignupStrategy = require('./passport/local-signup.js');
|
||||||
|
const localLoginStrategy = require('./passport/local-login.js');
|
||||||
|
passport.use('local-signup', localSignupStrategy);
|
||||||
|
passport.use('local-login', localLoginStrategy);
|
||||||
|
// initialize passport
|
||||||
|
app.use(cookieSession({
|
||||||
|
name : 'session',
|
||||||
|
keys : [siteConfig.auth.sessionKey],
|
||||||
|
maxAge: 24 * 60 * 60 * 1000, // i.e. 24 hours
|
||||||
|
}));
|
||||||
|
app.use(passport.initialize());
|
||||||
|
app.use(passport.session());
|
||||||
|
|
||||||
|
// configure handlebars & register it with express app
|
||||||
|
const hbs = expressHandlebars.create({
|
||||||
|
defaultLayout: 'embed',
|
||||||
|
handlebars : Handlebars,
|
||||||
|
});
|
||||||
|
app.engine('handlebars', hbs.engine);
|
||||||
|
app.set('view engine', 'handlebars');
|
||||||
|
|
||||||
|
// middleware to pass user info back to client (for handlebars access), if user is logged in
|
||||||
|
app.use(populateLocalsDotUser); // note: I don't think I need this any more?
|
||||||
|
|
||||||
|
// set the routes on the app
|
||||||
|
require('./routes/auth-routes.js')(app);
|
||||||
|
require('./routes/api-routes.js')(app);
|
||||||
|
require('./routes/page-routes.js')(app);
|
||||||
|
require('./routes/serve-routes.js')(app);
|
||||||
|
require('./routes/fallback-routes.js')(app);
|
||||||
|
|
||||||
|
this.app = app;
|
||||||
|
};
|
||||||
|
this.configureServer = () => {
|
||||||
|
this.server = http.Server(this.app);
|
||||||
|
};
|
||||||
|
this.startServer = () => {
|
||||||
|
const db = require('./models');
|
||||||
|
// sync sequelize
|
||||||
|
db.sequelize.sync()
|
||||||
|
// start the server
|
||||||
|
.then(() => {
|
||||||
|
this.server.listen(this.PORT, () => {
|
||||||
|
logger.info(`Server is listening on PORT ${this.PORT}`);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
logger.error(`Startup Error:`, error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = SpeechServer;
|
|
@ -2,9 +2,7 @@
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const db = require('../models'); // require our models for syncing
|
const db = require('../models'); // require our models for syncing
|
||||||
// configure logging
|
// configure logging
|
||||||
const config = require('../config/speechConfig.js');
|
require('../helpers/configureLogger.js')(logger);
|
||||||
const { logLevel } = config.logging;
|
|
||||||
require('../config/loggerConfig.js')(logger, logLevel);
|
|
||||||
|
|
||||||
let totalClaims = 0;
|
let totalClaims = 0;
|
||||||
let totalClaimsNoCertificate = 0;
|
let totalClaimsNoCertificate = 0;
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
// load dependencies
|
// load dependencies
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
const db = require('../models'); // require our models for syncing
|
const db = require('../models');
|
||||||
// configure logging
|
// configure logging
|
||||||
const config = require('../config/speechConfig.js');
|
require('../helpers/configureLogger.js')(logger);
|
||||||
const { logLevel } = config.logging;
|
|
||||||
require('../config/loggerConfig.js')(logger, logLevel);
|
|
||||||
|
|
||||||
const userName = process.argv[2];
|
const userName = process.argv[2];
|
||||||
logger.debug('user name:', userName);
|
logger.debug('user name:', userName);
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const chaiHttp = require('chai-http');
|
const chaiHttp = require('chai-http');
|
||||||
const { site, testing } = require('../../config/speechConfig.js');
|
const { details: { host } } = require('../../config/siteConfig.js');
|
||||||
const { host } = site;
|
const { testChannel, testChannelId, testChannelPassword } = require('../../devConfig/testingConfig.js');
|
||||||
const { testChannel, testChannelId, testChannelPassword } = testing;
|
|
||||||
const requestTimeout = 20000;
|
const requestTimeout = 20000;
|
||||||
const publishTimeout = 120000;
|
const publishTimeout = 120000;
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
7
webpack.config.js
Normal file
7
webpack.config.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
const serverBaseConfig = require('./webpack.server.common.js');
|
||||||
|
const clientBaseConfig = require('./webpack.client.common.js');
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
serverBaseConfig,
|
||||||
|
clientBaseConfig,
|
||||||
|
];
|
|
@ -8,11 +8,13 @@ module.exports = {
|
||||||
__dirname: false,
|
__dirname: false,
|
||||||
},
|
},
|
||||||
externals: [nodeExternals()],
|
externals: [nodeExternals()],
|
||||||
entry : ['babel-polyfill', 'whatwg-fetch', './index.js'],
|
entry : ['babel-polyfill', 'whatwg-fetch', './server.js'],
|
||||||
output : {
|
output : {
|
||||||
path : Path.join(__dirname, '/'),
|
path : Path.join(__dirname, '/'),
|
||||||
publicPath: '/',
|
publicPath : '/',
|
||||||
filename : 'server.js',
|
filename : 'index.js',
|
||||||
|
library : '',
|
||||||
|
libraryTarget: 'commonjs-module',
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
|
Loading…
Reference in a new issue