0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2025-12-26 22:32:45 +00:00

Merge branch 'master' into update-Marked-renderer

This commit is contained in:
Trevor Buckner
2020-04-20 21:40:04 -04:00
19 changed files with 1694 additions and 1587 deletions

1
.gitignore vendored
View File

@@ -10,4 +10,3 @@ config/local.*
todo.md
startDB.bat
startMViewer.bat
*.xlsx

View File

@@ -1,14 +1,19 @@
FROM node:8
ENV NODE_ENV=docker
# Create app directory
WORKDIR /usr/src/app
# Bundle app source
# Copy package.json into the image, then run yarn install
# This improves caching so we don't have to download the dependencies every time the code changes
COPY package.json ./
# --ignore-scripts tells yarn not to run postbuild. We run it explicitly later
RUN yarn install --ignore-scripts
# Bundle app source and build application
COPY . .
ENV NODE_ENV=docker
RUN yarn
RUN yarn build
EXPOSE 8000
CMD [ "yarn", "start" ]
CMD [ "yarn", "start" ]

12
README.DOCKER.md Normal file
View File

@@ -0,0 +1,12 @@
# Running Homebrewery via Docker
The repo includes a Dockerfile and a docker-compose.yml file.
To run the application via docker-compose.yml:
`docker-compose up -d`
To stop the application:
`docker-compose down`
To stop the application and remove all data:
`docker-compose down -v`

View File

@@ -29,6 +29,10 @@ Fourth, you will need to install the program and run it using the two commands:
You should now be able to go to [http://localhost:8000](http://localhost:8000) in your browser and use the Homebrewery offline.
### Running the application via Docker
Please see the docs here: [README.DOCKER.md](./README.DOCKER.md)
### Standalone PHB Stylesheet
If you just want the stylesheet that is generated to make pages look like they are from the Player's Handbook, you will find it in the [phb.standalone.css](./phb.standalone.css) file.

View File

@@ -1,5 +1,9 @@
# changelog
### Wednesday, 11/03/2020 - v2.8.2
- Fixed delete button removing everyone's copy for brews with multiple authors
- Compressed homebrew text in database
### Monday, 26/11/2018 - v2.8.1
- Fixed some SSL issues with images in the example page so they appear now
- Fixed duplicate scrollbars in Edit Page

View File

@@ -50,7 +50,7 @@ const MetadataEditor = createClass({
if(!confirm('Are you REALLY sure? You will lose editor access to this document.')) return;
}
request.get(`/api/remove/${this.props.metadata.editId}`)
request.delete(`/api/${this.props.metadata.editId}`)
.send()
.end(function(err, res){
window.location.href = '/';

View File

@@ -3,6 +3,7 @@ const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const request = require('superagent');
const Meta = require('vitreum/meta');
const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('../../navbar/navbar.jsx');
@@ -134,7 +135,7 @@ const EditPage = createClass({
}));
request
.put(`/api/update/${this.props.brew.editId}`)
.put(`/api/${this.props.brew.editId}`)
.send(this.state.brew)
.end((err, res)=>{
if(err){
@@ -202,6 +203,7 @@ const EditPage = createClass({
render : function(){
return <div className='editPage page'>
<Meta name='robots' content='noindex, nofollow' />
{this.renderNavbar()}
<div className='content'>

View File

@@ -3,6 +3,7 @@ const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const request = require('superagent');
const Meta = require('vitreum/meta');
const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('../../navbar/navbar.jsx');
@@ -72,6 +73,7 @@ const HomePage = createClass({
render : function(){
return <div className='homePage page'>
<Meta name='google-site-verification' content='NwnAQSSJZzAT7N-p5MY6ydQ7Njm67dtbu73ZSyE5Fy4' />
{this.renderNavbar()}
<div className='content'>

View File

@@ -2,6 +2,7 @@ const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const Meta = require('vitreum/meta');
const Markdown = require('naturalcrit/markdown.js');
const PrintPage = createClass({
@@ -42,6 +43,7 @@ const PrintPage = createClass({
render : function(){
return <div>
<Meta name='robots' content='noindex, nofollow' />
{this.renderPages()}
</div>;
}

View File

@@ -2,6 +2,7 @@ const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
const Meta = require('vitreum/meta');
const Nav = require('naturalcrit/nav/nav.jsx');
const Navbar = require('../../navbar/navbar.jsx');
@@ -45,6 +46,7 @@ const SharePage = createClass({
render : function(){
return <div className='sharePage page'>
<Meta name='robots' content='noindex, nofollow' />
<Navbar>
<Nav.section>
<Nav.item className='brewTitle'>{this.props.brew.title}</Nav.item>

View File

@@ -26,7 +26,7 @@ const BrewItem = createClass({
if(!confirm('Are you REALLY sure? You will lose editor access to this document.')) return;
}
request.get(`/api/remove/${this.props.brew.editId}`)
request.delete(`/api/${this.props.brew.editId}`)
.send()
.end(function(err, res){
location.reload();

View File

@@ -42,15 +42,6 @@ const UserPage = createClass({
});
},
renderPrivateBrews : function(privateBrews){
if(!privateBrews || !privateBrews.length) return;
return [
<h1>{this.props.username}'s unpublished brews</h1>,
this.renderBrews(privateBrews)
];
},
render : function(){
const brews = this.getSortedBrews();
@@ -64,9 +55,14 @@ const UserPage = createClass({
<div className='content'>
<div className='phb'>
<h1>{this.props.username}'s brews</h1>
{this.renderBrews(brews.published)}
{this.renderPrivateBrews(brews.private)}
<div>
<h1>{this.props.username}'s brews</h1>
{this.renderBrews(brews.published)}
</div>
<div>
<h1>{this.props.username}'s unpublished brews</h1>
{this.renderBrews(brews.private)}
</div>
</div>
</div>
</div>;

View File

@@ -17,7 +17,7 @@
.phb{
.noColumns();
height : auto;
min-height : 279.4mm;
min-height : 279.4mm;
margin : 20px auto;
&::after{
display : none;
@@ -30,4 +30,4 @@
}
}
}
}

3078
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -40,19 +40,19 @@
"babel-preset-react": "^6.24.1",
"body-parser": "^1.19.0",
"classnames": "^2.2.6",
"codemirror": "^5.52.0",
"cookie-parser": "^1.4.4",
"codemirror": "^5.52.2",
"cookie-parser": "^1.4.5",
"create-react-class": "^15.6.3",
"express": "^4.17.1",
"jwt-simple": "^0.5.6",
"lodash": "^4.17.15",
"marked": "^0.8.2",
"moment": "^2.24.0",
"mongoose": "^5.9.2",
"mongoose": "^5.9.9",
"nconf": "^0.10.0",
"pico-router": "^2.1.0",
"react": "^16.13.0",
"react-dom": "^16.13.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"shortid": "^2.2.15",
"superagent": "^5.2.2",
"vitreum": "^4.10.1"

5
robots.txt Normal file
View File

@@ -0,0 +1,5 @@
# Disallow crawling brew edit and share pages
User-agent: *
Disallow: /edit/
Disallow: /share/
Disallow: /print/

View File

@@ -44,9 +44,14 @@ const HomebrewModel = require('./server/homebrew.model.js').model;
const welcomeText = require('fs').readFileSync('./client/homebrew/pages/homePage/welcome_msg.md', 'utf8');
const changelogText = require('fs').readFileSync('./changelog.md', 'utf8');
String.prototype.replaceAll = function(s, r){return this.split(s).join(r);};
//Robots.txt
app.get('/robots.txt', (req, res)=>{
return res.sendFile(`${__dirname}/robots.txt`);
});
//Source page
String.prototype.replaceAll = function(s, r){return this.split(s).join(r);};
app.get('/source/:id', (req, res)=>{
HomebrewModel.get({ shareId: req.params.id })
.then((brew)=>{
@@ -59,7 +64,7 @@ app.get('/source/:id', (req, res)=>{
});
});
//User Page
app.get('/user/:username', (req, res, next)=>{
const fullAccess = req.account && (req.account.username == req.params.username);
HomebrewModel.getByUser(req.params.username, fullAccess)
@@ -72,7 +77,7 @@ app.get('/user/:username', (req, res, next)=>{
});
});
//Edit Page
app.get('/edit/:id', (req, res, next)=>{
HomebrewModel.get({ editId: req.params.id })
.then((brew)=>{
@@ -115,7 +120,7 @@ app.get('/print/:id', (req, res, next)=>{
});
//Render Page
//Render the page
const render = require('vitreum/steps/render');
const templateFn = require('./client/template.js');
app.use((req, res)=>{

View File

@@ -1,5 +1,5 @@
module.exports = (req, res, next)=>{
if(process.env.NODE_ENV === 'local') return next();
if(process.env.NODE_ENV === 'local' || process.env.NODE_ENV === 'docker') return next();
if(req.header('x-forwarded-proto') !== 'https') {
return res.redirect(302, `https://${req.get('Host')}${req.url}`);
}

View File

@@ -3,7 +3,7 @@ const HomebrewModel = require('./homebrew.model.js').model;
const router = require('express').Router();
const zlib = require('zlib');
// const getTopBrews = (cb)=>{
// const getTopBrews = (cb) => {
// HomebrewModel.find().sort({ views: -1 }).limit(5).exec(function(err, brews) {
// cb(brews);
// });
@@ -11,53 +11,53 @@ const zlib = require('zlib');
const getGoodBrewTitle = (text)=>{
const titlePos = text.indexOf('# ');
if(titlePos !== -1){
if(titlePos !== -1) {
const ending = text.indexOf('\n', titlePos);
return text.substring(titlePos + 2, ending);
} else {
return _.find(text.split('\n'), (line)=>{
return line;
});
return _.find(text.split('\n'), (line)=>line);
}
};
router.post('/api', (req, res)=>{
let authors = [];
if(req.account) authors = [req.account.username];
const newBrew = (req, res)=>{
const authors = (req.account) ? [req.account.username] : [];
const newHomebrew = new HomebrewModel(_.merge({},
req.body,
{ authors: authors }
));
if(!newHomebrew.title){
if(!newHomebrew.title) {
newHomebrew.title = getGoodBrewTitle(newHomebrew.text);
}
newHomebrew.textBin = zlib.deflateRawSync(newHomebrew.text); // Compress brew text to binary before saving
newHomebrew.text = undefined; // Delete the non-binary text field since it's not needed anymore
// Compress brew text to binary before saving
newHomebrew.textBin = zlib.deflateRawSync(newHomebrew.text);
// Delete the non-binary text field since it's not needed anymore
newHomebrew.text = undefined;
newHomebrew.save((err, obj)=>{
if(err){
if(err) {
console.error(err, err.toString(), err.stack);
return res.status(500).send(`Error while creating new brew, ${err.toString()}`);
}
return res.json(obj);
});
});
};
router.put('/api/update/:id', (req, res)=>{
const updateBrew = (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 = undefined; // Delete the non-binary text field since it's not needed anymore
// Compress brew text to binary before saving
brew.textBin = zlib.deflateRawSync(req.body.text);
// Delete the non-binary text field since it's not needed anymore
brew.text = undefined;
brew.updatedAt = new Date();
if(req.account) brew.authors = _.uniq(_.concat(brew.authors, req.account.username));
if(req.account) {
brew.authors = _.uniq(_.concat(brew.authors, req.account.username));
}
brew.markModified('authors');
brew.markModified('systems');
@@ -68,62 +68,63 @@ router.put('/api/update/:id', (req, res)=>{
});
})
.catch((err)=>{
console.log(err);
console.error(err);
return res.status(500).send('Error while saving');
});
});
};
router.get('/api/remove/:id', (req, res)=>{
const deleteBrew = (req, res)=>{
HomebrewModel.find({ editId: req.params.id }, (err, objs)=>{
if(!objs.length || err) return res.status(404).send('Can not find homebrew with that id');
if(!objs.length || err) {
return res.status(404).send('Can not find homebrew with that id');
}
const brew = objs[0];
// Remove current user as author
if(req.account){
if(req.account) {
// Remove current user as author
brew.authors = _.pull(brew.authors, req.account.username);
brew.markModified('authors');
}
// Delete brew if there are no authors left
if(!brew.authors.length)
if(brew.authors.length === 0) {
// Delete brew if there are no authors left
brew.remove((err)=>{
if(err) return res.status(500).send('Error while removing');
return res.status(200).send();
});
// Otherwise, save the brew with updated author list
else
} else {
// Otherwise, save the brew with updated author list
brew.save((err, savedBrew)=>{
if(err) throw err;
return res.status(200).send(savedBrew);
});
}
});
});
};
router.post('/api', newBrew);
router.put('/api/:id', updateBrew);
router.put('/api/update/:id', updateBrew);
router.delete('/api/:id', deleteBrew);
router.get('/api/remove/:id', deleteBrew);
module.exports = router;
/*
module.exports = function(app){
module.exports = function(app) {
app;
app.get('/api/search', mw.adminOnly, function(req, res){
app.get('/api/search', mw.adminOnly, function(req, res) {
var page = req.query.page || 0;
var count = req.query.count || 20;
var query = {};
if(req.query && req.query.id){
if (req.query && req.query.id) {
query = {
"$or" : [{
"$or": [{
editId : req.query.id
},{
}, {
shareId : req.query.id
}]
};
@@ -134,21 +135,17 @@ module.exports = function(app){
}, {
skip: page*count,
limit: count*1
}, function(err, objs){
if(err) console.log(err);
}, function(err, objs) {
if (err) console.error(err);
return res.json({
page : page,
count : count,
total : homebrewTotal,
brews : objs
});
});
})
return app;
}
*/