From a06b29c6f527e341b374079bf287e9a3d881b6ef Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 23 Jan 2020 10:50:35 -0500 Subject: [PATCH] Admin controls for compressing old brews --- client/admin/admin.jsx | 3 + client/admin/brewCompress/brewCompress.jsx | 75 +++++++++++++++++++++ client/admin/brewCompress/brewCompress.less | 10 +++ server/admin.api.js | 34 +++++++++- server/homebrew.api.js | 6 +- server/homebrew.model.js | 2 +- 6 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 client/admin/brewCompress/brewCompress.jsx create mode 100644 client/admin/brewCompress/brewCompress.less diff --git a/client/admin/admin.jsx b/client/admin/admin.jsx index 966cb8b63..9708b458a 100644 --- a/client/admin/admin.jsx +++ b/client/admin/admin.jsx @@ -4,6 +4,7 @@ const createClass = require('create-react-class'); const BrewCleanup = require('./brewCleanup/brewCleanup.jsx'); const BrewLookup = require('./brewLookup/brewLookup.jsx'); +const BrewCompress = require ('./brewCompress/brewCompress.jsx'); const Stats = require('./stats/stats.jsx'); const Admin = createClass({ @@ -26,6 +27,8 @@ const Admin = createClass({
+
+ ; } diff --git a/client/admin/brewCompress/brewCompress.jsx b/client/admin/brewCompress/brewCompress.jsx new file mode 100644 index 000000000..a43fd52c2 --- /dev/null +++ b/client/admin/brewCompress/brewCompress.jsx @@ -0,0 +1,75 @@ +const React = require('react'); +const createClass = require('create-react-class'); +const cx = require('classnames'); + +const request = require('superagent'); + + +const BrewCompress = createClass({ + displayName : 'BrewCompress', + getDefaultProps(){ + return {}; + }, + getInitialState() { + return { + count : 0, + + pending : false, + primed : false, + err : null, + ids : null + }; + }, + prime(){ + this.setState({ pending: true }); + + request.get('/admin/finduncompressed') + .then((res)=>this.setState({ count: res.body.count, primed: true, ids: res.body.ids })) + .catch((err)=>this.setState({ error: err })) + .finally(()=>this.setState({ pending: false })); + }, + cleanup(){ + this.setState({ pending: true }); + this.state.ids.forEach((id)=>{ + request.put(`/admin/compress/${id}`) + .catch((err)=>this.setState({ error: err })) + .finally(()=>this.setState({ pending: false, primed: false })); + }); + }, + renderPrimed(){ + if(!this.state.primed) return; + + if(!this.state.count){ + return
No Matching Brews found.
; + } + return
+ + Found {this.state.count} Brews that could be compressed. +
; + }, + render(){ + return
+

Brew Compression

+

Compresses the text in brews to binary

+ + + {this.renderPrimed()} + + {this.state.error + &&
{this.state.error.toString()}
+ } +
; + } +}); + +module.exports = BrewCompress; \ No newline at end of file diff --git a/client/admin/brewCompress/brewCompress.less b/client/admin/brewCompress/brewCompress.less new file mode 100644 index 000000000..2a2bf42ea --- /dev/null +++ b/client/admin/brewCompress/brewCompress.less @@ -0,0 +1,10 @@ +.BrewCompress{ + .removeBox{ + margin-top: 20px; + button{ + background-color: @red; + margin-right: 10px; + } + } + +} \ No newline at end of file diff --git a/server/admin.api.js b/server/admin.api.js index a6486a618..99d42f5ec 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -3,6 +3,7 @@ const router = require('express').Router(); const Moment = require('moment'); const render = require('vitreum/steps/render'); const templateFn = require('../client/template.js'); +const zlib = require('zlib'); process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin'; process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password3'; @@ -26,7 +27,7 @@ const mw = { }; -/* Removes all empty brews that are older than 3 days and that are shorter than a tweet */ +/* Search for brews that are older than 3 days and that are shorter than a tweet */ const junkBrewQuery = HomebrewModel.find({ '$where' : 'this.text.length < 140', createdAt : { @@ -34,6 +35,11 @@ const junkBrewQuery = HomebrewModel.find({ } }).limit(100).maxTime(60000); +/* Search for brews that aren't compressed (missing the compressed text field) */ +const uncompressedBrewQuery = HomebrewModel.find({ + 'textBin' : null +}).limit(50).distinct('_id'); + router.get('/admin/cleanup', mw.adminOnly, (req, res)=>{ junkBrewQuery.exec((err, objs)=>{ if(err) return res.status(500).send(err); @@ -58,6 +64,32 @@ router.get('/admin/lookup/:id', mw.adminOnly, (req, res, next)=>{ }); }); +/* Find 50 brews that aren't compressed yet */ +router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{ + uncompressedBrewQuery.exec((err, objs)=>{ + if(err) return res.status(500).send(err); + return res.json({ count: objs.length, ids: objs }); + }); +}); + +/* Compresses the "text" field of a brew to binary */ +router.put('/admin/compress/:id', (req, res)=>{ + HomebrewModel.get({ _id: req.params.id }) + .then((brew)=>{ + brew.textBin = zlib.deflateRawSync(brew.text); // Compress brew text to binary before saving + brew.text = undefined; // Delete the non-binary text field since it's not needed anymore + + brew.save((err, obj)=>{ + if(err) throw err; + return res.status(200).send(obj); + }); + }) + .catch((err)=>{ + console.log(err); + return res.status(500).send('Error while saving'); + }); +}); + router.get('/admin/stats', mw.adminOnly, (req, res)=>{ HomebrewModel.count({}, (err, count)=>{ return res.json({ diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 1a028f7f6..25399beb1 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -38,7 +38,7 @@ router.post('/api', (req, res)=>{ } newHomebrew.textBin = zlib.deflateRawSync(newHomebrew.text); // Compress brew text to binary before saving - newHomebrew.text = ''; // Clear out the non-binary text field so its not saved twice + newHomebrew.text = undefined; // Delete the non-binary text field since it's not needed anymore newHomebrew.save((err, obj)=>{ if(err){ @@ -53,8 +53,8 @@ router.put('/api/update/:id', (req, res)=>{ HomebrewModel.get({ editId: req.params.id }) .then((brew)=>{ brew = _.merge(brew, req.body); - brew.textBin = zlib.deflateRawSync(req.body.text); // Compress brew text to binary before saving - brew.text = ''; // Clear out the non-binary text field so its not saved twice + brew.textBin = zlib.deflateRawSync(req.body.text); // Compress brew text to binary before saving + brew.text = undefined; // Delete the non-binary text field since it's not needed anymore brew.updatedAt = new Date(); if(req.account) brew.authors = _.uniq(_.concat(brew.authors, req.account.username)); diff --git a/server/homebrew.model.js b/server/homebrew.model.js index e8d857982..25c7a38e1 100644 --- a/server/homebrew.model.js +++ b/server/homebrew.model.js @@ -53,7 +53,7 @@ HomebrewSchema.statics.get = function(query){ return new Promise((resolve, reject)=>{ Homebrew.find(query, (err, brews)=>{ if(err || !brews.length) return reject('Can not find brew'); - if(!_.isUndefined(brews[0].textBin)) { // Uncompress zipped text field + if(!_.isNil(brews[0].textBin)) { // Uncompress zipped text field unzipped = zlib.inflateRawSync(brews[0].textBin); brews[0].text = unzipped.toString(); }