0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2025-12-24 20:42:43 +00:00

Merge branch 'master' into showGoogleAuthStatus-#2520

This commit is contained in:
G.Ambatte
2022-12-09 07:56:25 +13:00
committed by GitHub
7 changed files with 1094 additions and 1042 deletions

View File

@@ -1,7 +1,6 @@
```css
h5 {
font-size: .35cm !important;
margin-top: 0.3cm;
}
.page ul ul {
@@ -45,6 +44,23 @@ pre {
## changelog
For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery).
### Monday 05/12/2022 - v3.4.1
{{taskList
##### G-Ambatte
* [x] Fix Account page incorrect last login time
Fixes issues [#2521](https://github.com/naturalcrit/homebrewery/issues/2521)
##### Gazook
* [x] Fix crashing on iOS and Safari browsers
Fixes issues [#2531](https://github.com/naturalcrit/homebrewery/issues/2531)
}}
### Monday 28/11/2022 - v3.4.0
{{taskList

View File

@@ -139,10 +139,10 @@ const Editor = createClass({
// Highlight injectors {style}
if(line.includes('{') && line.includes('}')){
const regex = /(?<!{){(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\s]*)*))\1}/g;
const regex = /(?:^|[^{\n])({(?=((?::(?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':{}\s]*)*))\2})/gm;
let match;
while ((match = regex.exec(line)) != null) {
codeMirror.markText({ line: lineNumber, ch: match.index }, { line: lineNumber, ch: match.index + match[0].length }, { className: 'injection' });
codeMirror.markText({ line: lineNumber, ch: line.indexOf(match[1]) }, { line: lineNumber, ch: line.indexOf(match[1]) + match[1].length }, { className: 'injection' });
}
}
// Highlight inline spans {{content}}

View File

@@ -9,12 +9,18 @@ const Nav = require('naturalcrit/nav/nav.jsx');
const StringArrayEditor = require('../stringArrayEditor/stringArrayEditor.jsx');
const Themes = require('themes/themes.json');
const validations = require('./validations.js')
const validations = require('./validations.js');
const SYSTEMS = ['5e', '4e', '3.5e', 'Pathfinder'];
const homebreweryThumbnail = require('../../thumbnail.png');
const callIfExists = (val, fn, ...args)=>{
if(val[fn]) {
val[fn](...args);
}
};
const MetadataEditor = createClass({
displayName : 'MetadataEditor',
getDefaultProps : function() {
@@ -53,28 +59,25 @@ const MetadataEditor = createClass({
},
handleFieldChange : function(name, e){
e.persist();
// load validation rules, and check input value against them
const inputRules = validations[name] ?? [];
const validationErr = inputRules.map((rule)=>rule(e.target.value)).filter(Boolean);
// if no validation rules, save to props
if(validationErr.length === 0){
e.target.setCustomValidity('');
callIfExists(e.target, 'setCustomValidity', '');
this.props.onChange({
...this.props.metadata,
[name] : e.target.value
});
} else {
// if validation issues, display built-in browser error popup with each error.
console.log(validationErr);
const errMessage = validationErr.map((err)=>{
return `- ${err}`;
}).join('\n');
e.target.setCustomValidity(errMessage);
e.target.reportValidity();
};
callIfExists(e.target, 'setCustomValidity', errMessage);
callIfExists(e.target, 'reportValidity');
}
},
handleSystem : function(system, e){

2011
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "homebrewery",
"description": "Create authentic looking D&D homebrews using only markdown",
"version": "3.4.0",
"version": "3.4.1",
"engines": {
"node": "16.11.x"
},
@@ -51,7 +51,7 @@
]
},
"dependencies": {
"@babel/core": "^7.19.6",
"@babel/core": "^7.20.5",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.19.4",
"@babel/preset-react": "^7.18.6",
@@ -64,32 +64,32 @@
"express": "^4.18.2",
"express-async-handler": "^1.2.0",
"express-static-gzip": "2.1.7",
"fs-extra": "10.1.0",
"fs-extra": "11.1.0",
"googleapis": "109.0.1",
"js-yaml": "^4.1.0",
"jwt-simple": "^0.5.6",
"less": "^3.13.1",
"lodash": "^4.17.21",
"marked": "4.2.3",
"marked": "4.2.4",
"marked-extended-tables": "^1.0.5",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.29.4",
"mongoose": "^6.7.3",
"mongoose": "^6.8.0",
"nanoid": "3.3.4",
"nconf": "^0.12.0",
"npm": "^8.10.0",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-frame-component": "4.1.3",
"react-router-dom": "6.4.3",
"react-router-dom": "6.4.5",
"sanitize-filename": "1.6.3",
"superagent": "^6.1.0",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
},
"devDependencies": {
"eslint": "^8.28.0",
"eslint": "^8.29.0",
"eslint-plugin-react": "^7.31.11",
"jest": "^29.2.2",
"supertest": "^6.3.1"
"supertest": "^6.3.3"
}
}

View File

@@ -78,10 +78,10 @@ const faqText = require('fs').readFileSync('faq.md', 'utf8');
String.prototype.replaceAll = function(s, r){return this.split(s).join(r);};
const defaultMetaTags = {
siteName : 'The Homebrewery - Make your Homebrew content look legit!',
site_name : 'The Homebrewery - Make your Homebrew content look legit!',
title : 'The Homebrewery',
description : 'A NaturalCrit Tool for Homebrews',
thumbnail : `${config.get('publicUrl')}/thumbnail.png`,
description : 'A NaturalCrit Tool for creating authentic Homebrews using Markdown.',
image : `${config.get('publicUrl')}/thumbnail.png`,
type : 'website'
};
@@ -148,8 +148,7 @@ app.get('/changelog', async (req, res, next)=>{
req.ogMeta = { ...defaultMetaTags,
title : 'Changelog',
description : 'Development changelog.',
thumbnail : null
description : 'Development changelog.'
};
splitTextStyleAndMetadata(req.brew);
@@ -192,12 +191,19 @@ app.get('/download/:id', asyncHandler(getBrew('share')), (req, res)=>{
sanitizeBrew(brew, 'share');
const prefix = 'HB - ';
const encodeRFC3986ValueChars = (str)=>{
return (
encodeURIComponent(str)
.replace(/[!'()*]/g, (char)=>{`%${char.charCodeAt(0).toString(16).toUpperCase()}`;})
);
};
let fileName = sanitizeFilename(`${prefix}${brew.title}`).replaceAll(' ', '');
if(!fileName || !fileName.length) { fileName = `${prefix}-Untitled-Brew`; };
res.set({
'Cache-Control' : 'no-cache',
'Content-Type' : 'text/plain',
'Content-Disposition' : `attachment; filename="${fileName}.txt"`
'Content-Disposition' : `attachment; filename*=UTF-8''${encodeRFC3986ValueChars(fileName)}.txt`
});
res.status(200).send(brew.text);
});
@@ -208,8 +214,7 @@ app.get('/user/:username', async (req, res, next)=>{
req.ogMeta = { ...defaultMetaTags,
title : `${req.params.username}'s Collection`,
description : 'View my collection of homebrew on the Homebrewery.',
image : null
description : 'View my collection of homebrew on the Homebrewery.'
// type : could be 'profile'?
};
@@ -274,7 +279,8 @@ app.get('/edit/:id', asyncHandler(getBrew('edit')), (req, res, next)=>{
req.ogMeta = { ...defaultMetaTags,
title : req.brew.title || 'Untitled Brew',
description : req.brew.description || 'No description.',
image : req.brew.thumbnail || null,
image : req.brew.thumbnail || defaultMetaTags.image,
type : 'article'
};
@@ -292,8 +298,7 @@ app.get('/new/:id', asyncHandler(getBrew('share')), (req, res, next)=>{
req.ogMeta = { ...defaultMetaTags,
title : 'New',
description : 'Start crafting your homebrew on the Homebrewery!',
image : null
description : 'Start crafting your homebrew on the Homebrewery!'
};
return next();
@@ -306,7 +311,7 @@ app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, r
req.ogMeta = { ...defaultMetaTags,
title : req.brew.title || 'Untitled Brew',
description : req.brew.description || 'No description.',
image : req.brew.thumbnail || null,
image : req.brew.thumbnail || defaultMetaTags.image,
type : 'article'
};
@@ -340,7 +345,7 @@ app.get('/account', asyncHandler(async (req, res, next)=>{
if(req.account) {
if(req.account.googleId) {
try {
auth = await GoogleActions.authCheck(req.account, res);
auth = await GoogleActions.authCheck(req.account, res, false);
} catch (e) {
auth = undefined;
console.log('Google auth check failed!');
@@ -377,8 +382,7 @@ app.get('/account', asyncHandler(async (req, res, next)=>{
req.ogMeta = { ...defaultMetaTags,
title : `Account Page`,
description : null,
image : null
description : null
};
return next();

View File

@@ -5,24 +5,28 @@ const { nanoid } = require('nanoid');
const token = require('./token.js');
const config = require('./config.js');
const keys = typeof(config.get('service_account')) == 'string' ?
JSON.parse(config.get('service_account')) :
config.get('service_account');
let serviceAuth;
try {
serviceAuth = google.auth.fromJSON(keys);
serviceAuth.scopes = [
'https://www.googleapis.com/auth/drive'
];
} catch (err) {
console.warn(err);
console.log('Please make sure that a Google Service Account is set up properly in your config files.');
if(!config.get('service_account')){
console.log('No Google Service Account in config files - Google Drive integration will not be available.');
} else {
const keys = typeof(config.get('service_account')) == 'string' ?
JSON.parse(config.get('service_account')) :
config.get('service_account');
try {
serviceAuth = google.auth.fromJSON(keys);
serviceAuth.scopes = ['https://www.googleapis.com/auth/drive'];
} catch (err) {
console.warn(err);
console.log('Please make sure the Google Service Account is set up properly in your config files.');
}
}
google.options({ auth: serviceAuth || config.get('google_api_key') });
const GoogleActions = {
authCheck : (account, res)=>{
authCheck : (account, res, updateTokens=true)=>{
if(!account || !account.googleId){ // If not signed into Google
const err = new Error('Not Signed In');
err.status = 401;
@@ -40,7 +44,7 @@ const GoogleActions = {
refresh_token : account.googleRefreshToken
});
oAuth2Client.on('tokens', (tokens)=>{
updateTokens && oAuth2Client.on('tokens', (tokens)=>{
if(tokens.refresh_token) {
account.googleRefreshToken = tokens.refresh_token;
}