diff --git a/config/production.json b/config/production.json index 05161783..6ea5cdb5 100644 --- a/config/production.json +++ b/config/production.json @@ -5,7 +5,7 @@ "LbryChangeAddress": "none" }, "AnalyticsConfig":{ - "GoogleId": "UA-60403362-2" + "GoogleId": "UA-60403362-3" }, "Database": { "MySqlConnectionUri": "none", diff --git a/controllers/statsController.js b/controllers/statsController.js index 3aac00df..0e736d66 100644 --- a/controllers/statsController.js +++ b/controllers/statsController.js @@ -1,7 +1,60 @@ const logger = require('winston'); +const ua = require('universal-analytics'); +const config = require('config'); const db = require('../models'); +const googleApiKey = config.get('AnalyticsConfig.GoogleId'); module.exports = { + postToStats: (action, url, ipAddress, result) => { + logger.silly('creating record for statistics db'); + // make sure the result is a string + if (result && (typeof result !== 'string')) { + result = result.toString(); + } + // // make sure the ip address(es) are a string + if (ipAddress && (typeof ipAddress !== 'string')) { + ipAddress = ipAddress.toString(); + } + // create record in the db + db.Stats.create({ + action, + url, + ipAddress, + result, + }) + .then() + .catch(error => { + logger.error('sequelize error', error); + }); + }, + sendGoogleAnalytics: (action, ip, originalUrl) => { + const visitorId = ip.replace(/\./g, '-'); + const visitor = ua(googleApiKey, visitorId, { strictCidFormat: false, https: true }); + switch (action) { + case 'serve': + visitor.event('serve', originalUrl, (err) => { + if (err) { + logger.error('Google Analytics Event Error >>', err); + } + }); + break; + case 'show': + visitor.pageview(originalUrl, 'https://spee.ch', 'show route', (err) => { + if (err) { + logger.error('Google Analytics Pageview Error >>', err); + } + }); + break; + case 'publish': + visitor.event('publish', originalUrl, (err) => { + if (err) { + logger.error('Google Analytics Event Error >>', err); + } + }); + break; + default: break; + } + }, getStatsSummary: () => { logger.debug('retrieving site statistics'); const deferred = new Promise((resolve, reject) => { diff --git a/helpers/libraries/errorHandlers.js b/helpers/libraries/errorHandlers.js index cc057ea5..45264a86 100644 --- a/helpers/libraries/errorHandlers.js +++ b/helpers/libraries/errorHandlers.js @@ -1,5 +1,5 @@ const logger = require('winston'); -const { postToStats } = require('./statsHelpers.js'); +const { postToStats } = require('../../controllers/statsController.js'); module.exports = { handleRequestError (action, originalUrl, ip, error, res) { diff --git a/helpers/libraries/statsHelpers.js b/helpers/libraries/statsHelpers.js deleted file mode 100644 index f008b081..00000000 --- a/helpers/libraries/statsHelpers.js +++ /dev/null @@ -1,27 +0,0 @@ -const db = require('../../models'); -const logger = require('winston'); - -module.exports = { - postToStats: (action, url, ipAddress, result) => { - logger.silly('creating record for statistics db'); - // make sure the result is a string - if (result && (typeof result !== 'string')) { - result = result.toString(); - } - // // make sure the ip address(es) are a string - if (ipAddress && (typeof ipAddress !== 'string')) { - ipAddress = ipAddress.toString(); - } - // create record in the db - db.Stats.create({ - action, - url, - ipAddress, - result, - }) - .then() - .catch(error => { - logger.error('sequelize error', error); - }); - }, -}; diff --git a/public/assets/js/claimPublish.js b/public/assets/js/claimPublish.js index 6391d8f6..eae7e5c3 100644 --- a/public/assets/js/claimPublish.js +++ b/public/assets/js/claimPublish.js @@ -128,6 +128,12 @@ uploader.addEventListener('start', function(event){ document.getElementById('publish-active-area').innerHTML = '
'; // start a progress animation createProgressBar(document.getElementById('progress-bar'), 12); + // google analytics + ga('send', { + hitType: 'event', + eventCategory: 'publish', + eventAction: name + }); }); uploader.addEventListener('progress', function(event){ var percent = event.bytesLoaded / event.file.size * 100; diff --git a/public/assets/js/memePublish.js b/public/assets/js/memePublish.js index 6cd50171..e2f4798a 100644 --- a/public/assets/js/memePublish.js +++ b/public/assets/js/memePublish.js @@ -108,6 +108,12 @@ uploader.addEventListener('start', function(event){ document.getElementById('publish-active-area').innerHTML = ''; // start a progress animation createProgressBar(document.getElementById('progress-bar'), 12); + // google analytics + ga('send', { + hitType: 'event', + eventCategory: 'publish', + eventAction: nameInput.value + }); }); uploader.addEventListener('progress', function(event){ var percent = event.bytesLoaded / event.file.size * 100; diff --git a/routes/api-routes.js b/routes/api-routes.js index 3e6cfa91..747c72de 100644 --- a/routes/api-routes.js +++ b/routes/api-routes.js @@ -5,12 +5,16 @@ const publishController = require('../controllers/publishController.js'); const lbryApi = require('../helpers/libraries/lbryApi.js'); const publishHelpers = require('../helpers/libraries/publishHelpers.js'); const errorHandlers = require('../helpers/libraries/errorHandlers.js'); -const { postToStats } = require('../helpers/libraries/statsHelpers.js'); +const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js'); module.exports = app => { // route to run a claim_list request on the daemon - app.get('/api/claim_list/:claim', ({ originalUrl, params, ip }, res) => { + app.get('/api/claim_list/:claim', ({ ip, originalUrl, params }, res) => { + // google analytics + sendGoogleAnalytics('serve', ip, originalUrl); + // log logger.verbose(`GET request on ${originalUrl} from ${ip}`); + // serve the content lbryApi .getClaimsList(params.claim) .then(claimsList => { @@ -22,8 +26,12 @@ module.exports = app => { }); }); // route to run a resolve request on the daemon - app.get('/api/resolve/:uri', ({ originalUrl, params, ip }, res) => { + app.get('/api/resolve/:uri', ({ ip, originalUrl, params }, res) => { + // google analytics + sendGoogleAnalytics('serve', ip, originalUrl); + // log logger.verbose(`GET request on ${originalUrl} from ${ip}`); + // serve content lbryApi .resolveUri(params.uri) .then(resolvedUri => { @@ -35,7 +43,10 @@ module.exports = app => { }); }); // route to run a publish request on the daemon - app.post('/api/publish', multipartMiddleware, ({ originalUrl, body, files, ip }, res) => { + app.post('/api/publish', multipartMiddleware, ({ body, files, ip, originalUrl }, res) => { + // google analytics + sendGoogleAnalytics('publish', ip, originalUrl); + // log logger.verbose(`POST request on ${originalUrl} from ${ip}`); // validate that a file was provided const file = files.speech || files.null; diff --git a/routes/home-routes.js b/routes/home-routes.js index aa9df045..f0891a01 100644 --- a/routes/home-routes.js +++ b/routes/home-routes.js @@ -1,16 +1,25 @@ const logger = require('winston'); -const { postToStats } = require('../helpers/libraries/statsHelpers.js'); +const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js'); module.exports = app => { // route for the home page - app.get('/', ({ originalUrl, ip, headers }, res) => { + app.get('/', ({ headers, ip, originalUrl }, res) => { + // google analytics + sendGoogleAnalytics('serve', ip, originalUrl); + // logging logger.verbose(`GET request on ${originalUrl} from ${ip}`); + // send response res.status(200).render('index'); }); // a catch-all route if someone visits a page that does not exist app.use('*', ({ originalUrl, ip }, res) => { + // google analytics + sendGoogleAnalytics('serve', ip, originalUrl); + // logging logger.error(`Get request on ${originalUrl} from ${ip} which was a 404`); - postToStats('post', originalUrl, ip, 'Error: 404'); + // post to stats + postToStats('show', originalUrl, ip, 'Error: 404'); + // send response res.status(404).render('fourOhFour'); }); }; diff --git a/routes/serve-routes.js b/routes/serve-routes.js index bc43b1d1..cfbf11a3 100644 --- a/routes/serve-routes.js +++ b/routes/serve-routes.js @@ -1,21 +1,7 @@ const errorHandlers = require('../helpers/libraries/errorHandlers.js'); const serveController = require('../controllers/serveController.js'); const logger = require('winston'); -const { postToStats } = require('../helpers/libraries/statsHelpers.js'); - -function sendGoogleAnalytics (ua, googleApiKey, ip, originalUrl) { - const visitorId = ip.replace(/\./g, '-'); - const visitor = ua(googleApiKey, visitorId, { strictCidFormat: false, https: true }); - visitor.pageview(originalUrl, 'https://spee.ch', 'Serve Route', (err) => { - if (err) { - logger.error('Google Analytics Pageview Error >>', err); - } - }).event('Serve', originalUrl, (err) => { - if (err) { - logger.error('Google Analytics Event Error >>', err); - } - }); -} +const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js'); function serveFile ({ fileName, fileType, filePath }, res) { logger.info(`serving file ${fileName}`); @@ -46,13 +32,17 @@ function serveFile ({ fileName, fileType, filePath }, res) { res.status(200).sendFile(filePath, options); } -module.exports = (app, ua, googleApiKey) => { +function sendAnalyticsAndLog (ip, originalUrl) { + // google analytics + sendGoogleAnalytics('serve', ip, originalUrl); + // logging + logger.verbose(`GET request on ${originalUrl} from ${ip}`); +} + +module.exports = (app) => { // route to fetch one free public claim - app.get('/:name/:claim_id', ({ originalUrl, params, ip }, res) => { - // google analytics - sendGoogleAnalytics(ua, googleApiKey, ip, originalUrl); - // logging - logger.verbose(`GET request on ${originalUrl} from ${ip}`); + app.get('/:name/:claim_id', ({ ip, originalUrl, params }, res) => { + sendAnalyticsAndLog(ip, originalUrl); // begin image-serve processes serveController .getClaimByClaimId(params.name, params.claim_id) @@ -65,11 +55,8 @@ module.exports = (app, ua, googleApiKey) => { }); }); // route to fetch one free public claim - app.get('/:name', ({ originalUrl, params, ip }, res) => { - // google analytics - sendGoogleAnalytics(ua, googleApiKey, ip, originalUrl); - // logging - logger.verbose(`GET request on ${originalUrl} from ${ip}`); + app.get('/:name', ({ ip, originalUrl, params }, res) => { + sendAnalyticsAndLog(ip, originalUrl); // begin image-serve processes serveController .getClaimByName(params.name) diff --git a/routes/show-routes.js b/routes/show-routes.js index 7b60bd5f..945fc162 100644 --- a/routes/show-routes.js +++ b/routes/show-routes.js @@ -1,16 +1,22 @@ const logger = require('winston'); const errorHandlers = require('../helpers/libraries/errorHandlers.js'); -const showController = require('../controllers/showController.js'); -const { postToStats } = require('../helpers/libraries/statsHelpers.js'); -const statsController = require('../controllers/statsController.js'); +const { getAllClaims } = require('../controllers/showController.js'); +const { getStatsSummary, postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js'); + +function sendAnalyticsAndLog (ip, originalUrl) { + // google analytics + sendGoogleAnalytics('show', ip, originalUrl); + // logging + logger.verbose(`POST request on ${originalUrl} from ${ip}`); + // get and serve the content +} module.exports = (app) => { // route to show the meme-fodder meme maker - app.get('/meme-fodder/play', ({ originalUrl, ip }, res) => { - logger.verbose(`POST request on ${originalUrl} from ${ip}`); - // get and serve the content - showController - .getAllClaims('meme-fodder') + app.get('/meme-fodder/play', ({ ip, originalUrl }, res) => { + sendAnalyticsAndLog(ip, originalUrl); + // get and render the content + getAllClaims('meme-fodder') .then(orderedFreePublicClaims => { postToStats('show', originalUrl, ip, 'success'); res.status(200).render('memeFodder', { claims: orderedFreePublicClaims }); @@ -20,11 +26,10 @@ module.exports = (app) => { }); }); // route to show statistics for spee.ch - app.get('/stats', ({ originalUrl, ip }, res) => { - logger.verbose(`POST request on ${originalUrl} from ${ip}`); - // get and serve the content - statsController - .getStatsSummary() + app.get('/stats', ({ ip, originalUrl }, res) => { + sendAnalyticsAndLog(ip, originalUrl); + // get and render the content + getStatsSummary() .then(result => { postToStats('show', originalUrl, ip, 'success'); res.status(200).render('statistics', result); @@ -34,11 +39,10 @@ module.exports = (app) => { }); }); // route to display all free public claims at a given name - app.get('/:name/all', ({ originalUrl, params, ip }, res) => { - logger.verbose(`POST request on ${originalUrl} from ${ip}`); - // get and serve the content - showController - .getAllClaims(params.name) + app.get('/:name/all', ({ ip, originalUrl, params }, res) => { + sendAnalyticsAndLog(ip, originalUrl); + // get and render the content + getAllClaims(params.name) .then(orderedFreePublicClaims => { postToStats('show', originalUrl, ip, 'success'); res.status(200).render('allClaims', { claims: orderedFreePublicClaims }); diff --git a/routes/sockets-routes.js b/routes/sockets-routes.js index dfc41b53..7ca4b092 100644 --- a/routes/sockets-routes.js +++ b/routes/sockets-routes.js @@ -2,7 +2,7 @@ const logger = require('winston'); const publishController = require('../controllers/publishController.js'); const publishHelpers = require('../helpers/libraries/publishHelpers.js'); const errorHandlers = require('../helpers/libraries/errorHandlers.js'); -const { postToStats } = require('../helpers/libraries/statsHelpers.js'); +const { postToStats } = require('../controllers/statsController.js'); module.exports = (app, siofu, hostedContentPath) => { const http = require('http').Server(app); @@ -16,6 +16,7 @@ module.exports = (app, siofu, hostedContentPath) => { uploader.listen(socket); // listener for when file upload starts uploader.on('start', ({ file }) => { + // log logger.info('client started an upload:', file.name); // server side test to make sure file is not a bad file type if (/\.exe$/.test(file.name)) { diff --git a/server.js b/server.js index 0e0cda8a..0df1158c 100644 --- a/server.js +++ b/server.js @@ -6,8 +6,7 @@ const expressHandlebars = require('express-handlebars'); const Handlebars = require('handlebars'); const config = require('config'); const winston = require('winston'); -const ua = require('universal-analytics'); -const googleApiKey = config.get('AnalyticsConfig.GoogleId'); + const hostedContentPath = config.get('Database.PublishUploadPath'); // configure logging @@ -58,7 +57,7 @@ app.set('view engine', 'handlebars'); // require express routes require('./routes/api-routes.js')(app); require('./routes/show-routes.js')(app); -require('./routes/serve-routes.js')(app, ua, googleApiKey); +require('./routes/serve-routes.js')(app); require('./routes/home-routes.js')(app); // require socket.io routes