From 7656e53606bc78631dcdfbefe3a090ea6c126523 Mon Sep 17 00:00:00 2001 From: Scott Tolksdorf Date: Mon, 3 Dec 2018 17:32:04 -0500 Subject: [PATCH] Finished stats and brew lookup on admin panel --- client/admin/admin.jsx | 37 ++-- client/admin/admin.less | 58 +++++- client/admin/brewCleanup/brewCleanup.jsx | 19 ++ client/admin/brewCleanup/brewCleanup.less | 3 + client/admin/brewLookup/brewLookup.jsx | 86 +++++++++ client/admin/brewLookup/brewLookup.less | 30 ++++ .../homebrewAdmin/brewLookup/brewLookup.jsx | 68 ------- .../homebrewAdmin/brewLookup/brewLookup.less | 8 - client/admin/homebrewAdmin/brewSearch.jsx | 66 ------- client/admin/homebrewAdmin/homebrewAdmin.jsx | 170 ------------------ client/admin/homebrewAdmin/homebrewAdmin.less | 53 ------ client/admin/stats/stats.jsx | 48 +++++ client/admin/stats/stats.less | 28 +++ server/admin.api.js | 28 ++- 14 files changed, 308 insertions(+), 394 deletions(-) create mode 100644 client/admin/brewCleanup/brewCleanup.jsx create mode 100644 client/admin/brewCleanup/brewCleanup.less create mode 100644 client/admin/brewLookup/brewLookup.jsx create mode 100644 client/admin/brewLookup/brewLookup.less delete mode 100644 client/admin/homebrewAdmin/brewLookup/brewLookup.jsx delete mode 100644 client/admin/homebrewAdmin/brewLookup/brewLookup.less delete mode 100644 client/admin/homebrewAdmin/brewSearch.jsx delete mode 100644 client/admin/homebrewAdmin/homebrewAdmin.jsx delete mode 100644 client/admin/homebrewAdmin/homebrewAdmin.less create mode 100644 client/admin/stats/stats.jsx create mode 100644 client/admin/stats/stats.less diff --git a/client/admin/admin.jsx b/client/admin/admin.jsx index 295fa9bf6..fb5f9ade7 100644 --- a/client/admin/admin.jsx +++ b/client/admin/admin.jsx @@ -1,38 +1,35 @@ const React = require('react'); const createClass = require('create-react-class'); -const _ = require('lodash'); -const cx = require('classnames'); -const HomebrewAdmin = require('./homebrewAdmin/homebrewAdmin.jsx'); + +const BrewCleanup = require('./brewCleanup/brewCleanup.jsx'); +const BrewLookup = require('./brewLookup/brewLookup.jsx'); +const Stats = require('./stats/stats.jsx'); const Admin = createClass({ getDefaultProps : function() { return { - url : '', - admin_key : '', - homebrews : [], + adminKey : '' }; }, render : function(){ - return ( -
- -
-
- - naturalcrit admin -
-
+ return
+
- - + + homebrewery admin
- - +
+
+ +
+ +
+
- ); +
} }); diff --git a/client/admin/admin.less b/client/admin/admin.less index c13063a01..84ffc9838 100644 --- a/client/admin/admin.less +++ b/client/admin/admin.less @@ -36,4 +36,60 @@ body{ } } -} \ No newline at end of file + + +} + +/*.homebrewAdmin{ + margin-bottom: 80px; + .brewTable{ + table{ + + th{ + padding : 10px; + font-weight : 800; + } + tr:nth-child(even){ + background-color : fade(@green, 10%); + } + tr.isEmpty{ + background-color : fade(@red, 30%); + } + td{ + min-width : 100px; + padding : 10px; + text-align : center; + + &.preview{ + position : relative; + &:hover{ + .content{ + display : block; + } + } + .content{ + position : absolute; + display : none; + top : 100%; + left : 0px; + z-index : 1000; + max-height : 500px; + width : 300px; + padding : 30px; + background-color : white; + font-family : monospace; + text-align : left; + pointer-events : none; + } + } + } + } + } + .deleteButton{ + cursor: pointer; + } + button.clearOldButton{ + float : right; + } +} +*/ \ No newline at end of file diff --git a/client/admin/brewCleanup/brewCleanup.jsx b/client/admin/brewCleanup/brewCleanup.jsx new file mode 100644 index 000000000..b70fbdb1f --- /dev/null +++ b/client/admin/brewCleanup/brewCleanup.jsx @@ -0,0 +1,19 @@ +const React = require('react'); +const createClass = require('create-react-class'); +const cx = require('classnames'); + + +const BrewCleanup = createClass({ + displayName : 'BrewCleanup', + getDefaultProps(){ + return { + }; + }, + render(){ + return
+ BrewCleanup Component Ready. +
; + } +}); + +module.exports = BrewCleanup; \ No newline at end of file diff --git a/client/admin/brewCleanup/brewCleanup.less b/client/admin/brewCleanup/brewCleanup.less new file mode 100644 index 000000000..d3313d4c0 --- /dev/null +++ b/client/admin/brewCleanup/brewCleanup.less @@ -0,0 +1,3 @@ +.BrewCleanup{ + +} \ No newline at end of file diff --git a/client/admin/brewLookup/brewLookup.jsx b/client/admin/brewLookup/brewLookup.jsx new file mode 100644 index 000000000..80016b50a --- /dev/null +++ b/client/admin/brewLookup/brewLookup.jsx @@ -0,0 +1,86 @@ +const React = require('react'); +const createClass = require('create-react-class'); +const _ = require('lodash'); +const cx = require('classnames'); + +const request = require('superagent'); +const Moment = require('moment'); + + +const BrewLookup = createClass({ + getDefaultProps() { + return { + adminKey : '', + }; + }, + getInitialState() { + return { + query : '', + foundBrew : null, + searching : false, + error : null + }; + }, + + handleChange(e){ + this.setState({ query : e.target.value }); + }, + lookup(){ + this.setState({ searching: true, error: null }); + + request.get(`/admin/lookup/${this.state.query}`) + .query({ admin_key: this.props.adminKey }) + .then((res)=> this.setState({foundBrew : res.body})) + .catch((err)=>this.setState({ error : err })) + .finally(()=>this.setState({ searching : false })) + }, + + renderFoundBrew(){ + const brew = this.state.foundBrew; + return
+
+
Title
+
{brew.title}
+ +
Authors
+
{brew.authors.join(', ')}
+ +
Edit Link
+
/edit/{brew.editId}
+ +
Share Link
+
/share/{brew.shareId}
+ +
Last Updated
+
{Moment(brew.updatedAt).fromNow()}
+ +
Num of Views
+
{brew.views}
+
+
; + }, + + render(){ + return
+

Brew Lookup

+ + + + {this.state.error + &&
{this.state.error}
+ } + + {this.state.foundBrew + ? this.renderFoundBrew() + :
No brew found.
+ } +
; + } +}); + +module.exports = BrewLookup; diff --git a/client/admin/brewLookup/brewLookup.less b/client/admin/brewLookup/brewLookup.less new file mode 100644 index 000000000..61eeec424 --- /dev/null +++ b/client/admin/brewLookup/brewLookup.less @@ -0,0 +1,30 @@ + +.brewLookup{ + input{ + height : 33px; + margin-bottom : 20px; + padding : 0px 10px; + font-family : monospace; + } + button{ + vertical-align : middle; + height : 37px; + } + dl{ + @maxItemWidth : 132px; + dt{ + float : left; + clear : left; + width : @maxItemWidth; + text-align : right; + &::after { + content: " : "; + } + } + dd{ + height : 1em; + margin-left : @maxItemWidth + 6px; + padding : 0 0 0.5em 0; + } + } +} \ No newline at end of file diff --git a/client/admin/homebrewAdmin/brewLookup/brewLookup.jsx b/client/admin/homebrewAdmin/brewLookup/brewLookup.jsx deleted file mode 100644 index 15f01286d..000000000 --- a/client/admin/homebrewAdmin/brewLookup/brewLookup.jsx +++ /dev/null @@ -1,68 +0,0 @@ -const React = require('react'); -const createClass = require('create-react-class'); -const _ = require('lodash'); -const cx = require('classnames'); - -const request = require('superagent'); -const Moment = require('moment'); - - -const BrewLookup = createClass({ - getDefaultProps : function() { - return { - adminKey : '', - }; - }, - getInitialState : function() { - return { - query : '', - resultBrew : null, - searching : false - }; - }, - - handleChange : function(e){ - this.setState({ - query : e.target.value - }); - }, - lookup : function(){ - this.setState({ searching: true }); - - request.get(`/admin/lookup/${this.state.query}`) - .query({ admin_key: this.props.adminKey }) - .end((err, res)=>{ - this.setState({ - searching : false, - resultBrew : (err ? null : res.body) - }); - }); - }, - - renderFoundBrew : function(){ - if(this.state.searching) return
; - if(!this.state.resultBrew) return
No brew found.
; - - const brew = this.state.resultBrew; - return
-
{brew.title}
-
{brew.authors.join(', ')}
- - -
{Moment(brew.updatedAt).fromNow()}
-
{brew.views}
-
; - }, - - render : function(){ - return
-

Brew Lookup

- - - - {this.renderFoundBrew()} -
; - } -}); - -module.exports = BrewLookup; diff --git a/client/admin/homebrewAdmin/brewLookup/brewLookup.less b/client/admin/homebrewAdmin/brewLookup/brewLookup.less deleted file mode 100644 index 071028c20..000000000 --- a/client/admin/homebrewAdmin/brewLookup/brewLookup.less +++ /dev/null @@ -1,8 +0,0 @@ -.brewLookup{ - height : 200px; - input{ - height : 33px; - padding : 0px 10px; - margin-bottom: 20px; - } -} \ No newline at end of file diff --git a/client/admin/homebrewAdmin/brewSearch.jsx b/client/admin/homebrewAdmin/brewSearch.jsx deleted file mode 100644 index 365f61a05..000000000 --- a/client/admin/homebrewAdmin/brewSearch.jsx +++ /dev/null @@ -1,66 +0,0 @@ -const React = require('react'); -const createClass = require('create-react-class'); -const _ = require('lodash'); -const cx = require('classnames'); - -const request = require('superagent'); - -const BrewSearch = createClass({ - - getDefaultProps : function() { - return { - admin_key : '' - }; - }, - - getInitialState : function() { - return { - searchTerm : '', - brew : null, - }; - }, - - - search : function(){ - request.get(`/homebrew/api/search?id=${this.state.searchTerm}`) - .query({ - admin_key : this.props.admin_key, - }) - .end((err, res)=>{ - console.log(err, res, res.body.brews[0]); - this.setState({ - brew : res.body.brews[0], - }); - }); - }, - - handleChange : function(e){ - this.setState({ - searchTerm : e.target.value - }); - }, - handleSearchClick : function(){ - this.search(); - }, - - renderBrew : function(){ - if(!this.state.brew) return null; - return
-
Edit id : {this.state.brew.editId}
-
Share id : {this.state.brew.shareId}
-
; - }, - - render : function(){ - return
- - - - - {this.renderBrew()} -
; - }, - -}); - -module.exports = BrewSearch; \ No newline at end of file diff --git a/client/admin/homebrewAdmin/homebrewAdmin.jsx b/client/admin/homebrewAdmin/homebrewAdmin.jsx deleted file mode 100644 index 218793141..000000000 --- a/client/admin/homebrewAdmin/homebrewAdmin.jsx +++ /dev/null @@ -1,170 +0,0 @@ -const React = require('react'); -const createClass = require('create-react-class'); -const _ = require('lodash'); -const cx = require('classnames'); -const request = require('superagent'); - -const Moment = require('moment'); - - -const BrewLookup = require('./brewLookup/brewLookup.jsx'); - - -const HomebrewAdmin = createClass({ - getDefaultProps : function() { - return { - admin_key : '' - }; - }, - - getInitialState : function() { - return { - page : 0, - count : 20, - brewCache : {}, - total : 0, - }; - }, - - - fetchBrews : function(page){ - request.get('/api/search') - .query({ - admin_key : this.props.admin_key, - count : this.state.count, - page : page - }) - .end((err, res)=>{ - if(err || !res.body || !res.body.brews) return; - const newCache = _.extend({}, this.state.brewCache); - newCache[page] = res.body.brews; - this.setState({ - brewCache : newCache, - total : res.body.total, - count : res.body.count - }); - }); - }, - - componentDidMount : function() { - this.fetchBrews(this.state.page); - }, - - changePageTo : function(page){ - if(!this.state.brewCache[page]){ - this.fetchBrews(page); - } - this.setState({ - page : page - }); - }, - - - clearInvalidBrews : function(){ - request.get('/api/invalid') - .query({ admin_key: this.props.admin_key }) - .end((err, res)=>{ - if(!confirm(`This will remove ${res.body.count} brews. Are you sure?`)) return; - request.get('/api/invalid') - .query({ admin_key: this.props.admin_key, do_it: true }) - .end((err, res)=>{ - alert('Done!'); - }); - }); - }, - - - deleteBrew : function(brewId){ - if(!confirm(`Are you sure you want to delete '${brewId}'?`)) return; - request.get(`/api/remove/${brewId}`) - .query({ admin_key: this.props.admin_key }) - .end(function(err, res){ - window.location.reload(); - }); - }, - - handlePageChange : function(dir){ - this.changePageTo(this.state.page + dir); - }, - - - renderPagnination : function(){ - let outOf; - if(this.state.total){ - outOf = `${this.state.page} / ${Math.round(this.state.total/this.state.count)}`; - } - return
- this.handlePageChange(-1)}/> - {outOf} - this.handlePageChange(1)}/> -
; - }, - - - renderBrews : function(){ - const brews = this.state.brewCache[this.state.page] || _.times(this.state.count); - return _.map(brews, (brew)=>{ - return - {brew.editId} - {brew.shareId} - {Moment(brew.createdAt).fromNow()} - {Moment(brew.updatedAt).fromNow()} - {Moment(brew.lastViewed).fromNow()} - {brew.views} - -
this.deleteBrew(brew.editId)}> - -
- - ; - }); - }, - - renderBrewTable : function(){ - return
- - - - - - - - - - - - - {this.renderBrews()} - -
Edit IdShare IdCreated AtLast UpdatedLast ViewedViews
-
; - }, - - render : function(){ - return
- - - - {/* -

- Homebrews - {this.state.total} -

- - - - - - {this.renderPagnination()} - {this.renderBrewTable()} - - - - - */} -
; - } -}); - -module.exports = HomebrewAdmin; diff --git a/client/admin/homebrewAdmin/homebrewAdmin.less b/client/admin/homebrewAdmin/homebrewAdmin.less deleted file mode 100644 index 6cfc3d5a0..000000000 --- a/client/admin/homebrewAdmin/homebrewAdmin.less +++ /dev/null @@ -1,53 +0,0 @@ - -.homebrewAdmin{ - margin-bottom: 80px; - .brewTable{ - table{ - - th{ - padding : 10px; - font-weight : 800; - } - tr:nth-child(even){ - background-color : fade(@green, 10%); - } - tr.isEmpty{ - background-color : fade(@red, 30%); - } - td{ - min-width : 100px; - padding : 10px; - text-align : center; - - &.preview{ - position : relative; - &:hover{ - .content{ - display : block; - } - } - .content{ - position : absolute; - display : none; - top : 100%; - left : 0px; - z-index : 1000; - max-height : 500px; - width : 300px; - padding : 30px; - background-color : white; - font-family : monospace; - text-align : left; - pointer-events : none; - } - } - } - } - } - .deleteButton{ - cursor: pointer; - } - button.clearOldButton{ - float : right; - } -} \ No newline at end of file diff --git a/client/admin/stats/stats.jsx b/client/admin/stats/stats.jsx new file mode 100644 index 000000000..cf67bd1d1 --- /dev/null +++ b/client/admin/stats/stats.jsx @@ -0,0 +1,48 @@ +const React = require('react'); +const createClass = require('create-react-class'); +const cx = require('classnames'); + +const request = require('superagent'); + + +const Stats = createClass({ + displayName : 'Stats', + getDefaultProps(){ + return { + adminKey : '' + }; + }, + getInitialState(){ + return { + stats : { + totalBrews : 0 + }, + fetching : false + } + }, + componentDidMount(){ + this.fetchStats(); + }, + fetchStats(){ + this.setState({ fetching : true}) + request.get('/admin/stats') + .query({ admin_key : this.props.adminKey }) + .then((res)=> this.setState({ stats : res.body })) + .finally(()=>this.setState({fetching : false})); + }, + render(){ + return
+

Stats

+
+
Total Brew Count
+
{this.state.stats.totalBrews}
+
+ + {this.state.fetching + &&
+ } +
; + } +}); + +module.exports = Stats; \ No newline at end of file diff --git a/client/admin/stats/stats.less b/client/admin/stats/stats.less new file mode 100644 index 000000000..5337bf671 --- /dev/null +++ b/client/admin/stats/stats.less @@ -0,0 +1,28 @@ + +.Stats{ + position : relative; + .pending{ + position : absolute; + top : 0px; + left : 0px; + height : 100%; + width : 100%; + background-color : rgba(238,238,238, 0.5); + } + dl{ + @maxItemWidth : 132px; + dt{ + float : left; + clear : left; + width : @maxItemWidth; + text-align : right; + &::after { + content: " : "; + } + } + dd{ + margin : 0 0 0 @maxItemWidth + 10px; + padding : 0 0 0.5em 0; + } + } +} \ No newline at end of file diff --git a/server/admin.api.js b/server/admin.api.js index e171f9381..40798f4fa 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -17,8 +17,8 @@ process.env.ADMIN_KEY = process.env.ADMIN_KEY || 'admin_key'; -//Removes all empty brews that are older than 3 days and that are shorter than a tweet -router.get('/api/invalid', mw.adminOnly, (req, res)=>{ +/* Removes all empty brews that are older than 3 days and that are shorter than a tweet */ +router.get('/admin/clear_invalid', mw.adminOnly, (req, res)=>{ const invalidBrewQuery = HomebrewModel.find({ '$where' : 'this.text.length < 140', createdAt : { @@ -28,12 +28,12 @@ router.get('/api/invalid', mw.adminOnly, (req, res)=>{ if(req.query.do_it){ invalidBrewQuery.remove().exec((err, objs)=>{ - refreshCount(); + if(err) return res.status(500).send(err); return res.send(200); }); } else { invalidBrewQuery.exec((err, objs)=>{ - if(err) console.log(err); + if(err) return res.status(500).send(err); return res.json({ count : objs.length }); @@ -41,10 +41,11 @@ router.get('/api/invalid', mw.adminOnly, (req, res)=>{ } }); +/* Searches for matching edit or share id, also attempts to partial match */ router.get('/admin/lookup/:id', mw.adminOnly, (req, res, next)=>{ - //search for mathcing edit id - //search for matching share id - // search for partial match + + console.log('lookup'); + HomebrewModel.findOne({ $or : [ { editId: { '$regex': req.params.id, '$options': 'i' } }, @@ -54,6 +55,17 @@ router.get('/admin/lookup/:id', mw.adminOnly, (req, res, next)=>{ }); }); +router.get('/admin/stats', mw.adminOnly, (req, res)=>{ + console.log('hittting stats'); + + HomebrewModel.count({}, (err, count)=>{ + return res.json({ + totalBrews : count + }) + }) + +}); + //Admin route @@ -68,7 +80,7 @@ router.get('/admin', function(req, res){ } render('admin', templateFn, { url : req.originalUrl, - admin_key : process.env.ADMIN_KEY, + adminKey : process.env.ADMIN_KEY }) .then((page)=>{ return res.send(page);