mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-08 20:23:39 +00:00
Merge branch 'master' into experimentalNotificationDB
This commit is contained in:
@@ -55,9 +55,9 @@ const BrewRenderer = (props)=>{
|
|||||||
theme : '5ePHB',
|
theme : '5ePHB',
|
||||||
lang : '',
|
lang : '',
|
||||||
errors : [],
|
errors : [],
|
||||||
currentEditorCursorPageNum : 0,
|
currentEditorCursorPageNum : 1,
|
||||||
currentEditorViewPageNum : 0,
|
currentEditorViewPageNum : 1,
|
||||||
currentBrewRendererPageNum : 0,
|
currentBrewRendererPageNum : 1,
|
||||||
themeBundle : {},
|
themeBundle : {},
|
||||||
onPageChange : ()=>{},
|
onPageChange : ()=>{},
|
||||||
...props
|
...props
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
overflow-y : unset;
|
overflow-y : unset;
|
||||||
.pages {
|
.pages {
|
||||||
margin : 0px;
|
margin : 0px;
|
||||||
|
zoom: 100% !important;
|
||||||
& > .page { box-shadow : unset; }
|
& > .page { box-shadow : unset; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,17 +304,14 @@ const MetadataEditor = createClass({
|
|||||||
onChange={(e)=>this.handleRenderer('V3', e)} />
|
onChange={(e)=>this.handleRenderer('V3', e)} />
|
||||||
V3
|
V3
|
||||||
</label>
|
</label>
|
||||||
|
<small><a href='/legacy' target='_blank' rel='noopener noreferrer'>Click here to see the demo page for the old Legacy renderer!</a></small>
|
||||||
<a href='/legacy' target='_blank' rel='noopener noreferrer'>
|
|
||||||
Click here to see the demo page for the old Legacy renderer!
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
},
|
},
|
||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
return <div className='metadataEditor'>
|
return <div className='metadataEditor'>
|
||||||
<h1 className='sectionHead'>Brew</h1>
|
<h1>Properties Editor</h1>
|
||||||
|
|
||||||
<div className='field title'>
|
<div className='field title'>
|
||||||
<label>title</label>
|
<label>title</label>
|
||||||
@@ -362,9 +359,7 @@ const MetadataEditor = createClass({
|
|||||||
|
|
||||||
{this.renderRenderOptions()}
|
{this.renderRenderOptions()}
|
||||||
|
|
||||||
<hr/>
|
<h2>Authors</h2>
|
||||||
|
|
||||||
<h1 className='sectionHead'>Authors</h1>
|
|
||||||
|
|
||||||
{this.renderAuthors()}
|
{this.renderAuthors()}
|
||||||
|
|
||||||
@@ -375,15 +370,13 @@ const MetadataEditor = createClass({
|
|||||||
notes={['Invited author usernames are case sensitive.', 'After adding an invited author, send them the edit link. There, they can choose to accept or decline the invitation.']}
|
notes={['Invited author usernames are case sensitive.', 'After adding an invited author, send them the edit link. There, they can choose to accept or decline the invitation.']}
|
||||||
onChange={(e)=>this.handleFieldChange('invitedAuthors', e)}/>
|
onChange={(e)=>this.handleFieldChange('invitedAuthors', e)}/>
|
||||||
|
|
||||||
<hr/>
|
<h2>Privacy</h2>
|
||||||
|
|
||||||
<h1 className='sectionHead'>Privacy</h1>
|
|
||||||
|
|
||||||
<div className='field publish'>
|
<div className='field publish'>
|
||||||
<label>publish</label>
|
<label>publish</label>
|
||||||
<div className='value'>
|
<div className='value'>
|
||||||
{this.renderPublish()}
|
{this.renderPublish()}
|
||||||
<small>Published homebrews will be publicly viewable and searchable (eventually...)</small>
|
<small>Published brews are searchable in <a href='/vault'>the Vault</a> and visible on your user page. Unpublished brews are not indexed in the Vault or visible on your user page, but can still be shared and indexed by search engines. You can unpublish a brew any time.</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
@import 'naturalcrit/styles/colors.less';
|
@import 'naturalcrit/styles/colors.less';
|
||||||
|
|
||||||
|
|
||||||
.metadataEditor {
|
.metadataEditor {
|
||||||
position : absolute;
|
position : absolute;
|
||||||
z-index : 5;
|
z-index : 5;
|
||||||
@@ -9,12 +10,19 @@
|
|||||||
padding : 25px;
|
padding : 25px;
|
||||||
overflow-y : auto;
|
overflow-y : auto;
|
||||||
background-color : #999999;
|
background-color : #999999;
|
||||||
|
font-size : 13px;
|
||||||
|
|
||||||
.sectionHead {
|
h1 {
|
||||||
|
margin: 0 0 40px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
margin : 20px 0;
|
margin : 20px 0;
|
||||||
font-weight : 1000;
|
font-weight : bold;
|
||||||
|
border-bottom: 2px solid gray;
|
||||||
&:first-of-type { margin-top : 0; }
|
color: #555;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > div { margin-bottom : 10px; }
|
& > div { margin-bottom : 10px; }
|
||||||
@@ -43,15 +51,21 @@
|
|||||||
min-width : 200px;
|
min-width : 200px;
|
||||||
& > label {
|
& > label {
|
||||||
width : 80px;
|
width : 80px;
|
||||||
font-size : 11px;
|
|
||||||
font-weight : 800;
|
font-weight : 800;
|
||||||
line-height : 1.8em;
|
line-height : 1.8em;
|
||||||
text-transform : uppercase;
|
text-transform : uppercase;
|
||||||
|
font-size: .9em;
|
||||||
}
|
}
|
||||||
& > .value {
|
& > .value {
|
||||||
flex : 1 1 auto;
|
flex : 1 1 auto;
|
||||||
width : 50px;
|
width : 50px;
|
||||||
&:invalid { background : #FFB9B9; }
|
&:invalid { background : #FFB9B9; }
|
||||||
|
small {
|
||||||
|
display : block;
|
||||||
|
font-size : 0.9em;
|
||||||
|
font-style : italic;
|
||||||
|
line-height : 1.4em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
input[type='text'], textarea {
|
input[type='text'], textarea {
|
||||||
border : 1px solid gray;
|
border : 1px solid gray;
|
||||||
@@ -78,7 +92,6 @@
|
|||||||
textarea.value {
|
textarea.value {
|
||||||
height : auto;
|
height : auto;
|
||||||
font-family : 'Open Sans', sans-serif;
|
font-family : 'Open Sans', sans-serif;
|
||||||
font-size : 0.8em;
|
|
||||||
resize : none;
|
resize : none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,12 +100,6 @@
|
|||||||
z-index : 200;
|
z-index : 200;
|
||||||
max-width : 150px;
|
max-width : 150px;
|
||||||
}
|
}
|
||||||
small {
|
|
||||||
display : inline-block;
|
|
||||||
font-size : 0.6em;
|
|
||||||
font-style : italic;
|
|
||||||
line-height : 1.4em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -113,18 +120,13 @@
|
|||||||
display : inline-flex;
|
display : inline-flex;
|
||||||
align-items : center;
|
align-items : center;
|
||||||
margin-right : 15px;
|
margin-right : 15px;
|
||||||
font-size : 0.7em;
|
font-size : 0.9em;
|
||||||
font-weight : 800;
|
font-weight : 800;
|
||||||
white-space : nowrap;
|
white-space : nowrap;
|
||||||
vertical-align : middle;
|
vertical-align : middle;
|
||||||
cursor : pointer;
|
cursor : pointer;
|
||||||
user-select : none;
|
user-select : none;
|
||||||
}
|
}
|
||||||
a {
|
|
||||||
display : inline-flex;
|
|
||||||
font-size : 0.7em;
|
|
||||||
font-weight : 800;
|
|
||||||
}
|
|
||||||
input {
|
input {
|
||||||
margin : 3px;
|
margin : 3px;
|
||||||
vertical-align : middle;
|
vertical-align : middle;
|
||||||
@@ -149,12 +151,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.authors.field .value {
|
.authors.field .value {
|
||||||
font-size : 0.8em;
|
|
||||||
line-height : 1.5em;
|
line-height : 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.themes.field {
|
.themes.field {
|
||||||
font-size : 13.33px;
|
|
||||||
.navDropdownContainer {
|
.navDropdownContainer {
|
||||||
position : relative;
|
position : relative;
|
||||||
z-index : 100;
|
z-index : 100;
|
||||||
@@ -165,9 +165,9 @@
|
|||||||
background-color : darkgray;
|
background-color : darkgray;
|
||||||
}
|
}
|
||||||
& > div:first-child {
|
& > div:first-child {
|
||||||
padding : 6px 3px;
|
padding : 3px 3px;
|
||||||
background-color : inherit;
|
background-color : inherit;
|
||||||
border : 2px solid rgb(118,118,118);
|
border : 1px solid gray;
|
||||||
i { float : right; }
|
i { float : right; }
|
||||||
&:hover {
|
&:hover {
|
||||||
color : white;
|
color : white;
|
||||||
@@ -240,6 +240,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.field .list {
|
.field .list {
|
||||||
display : flex;
|
display : flex;
|
||||||
flex : 1 0;
|
flex : 1 0;
|
||||||
@@ -277,8 +278,7 @@
|
|||||||
background-color : #DDDDDD;
|
background-color : #DDDDDD;
|
||||||
border-radius : 0.5em;
|
border-radius : 0.5em;
|
||||||
|
|
||||||
.icon {
|
.icon { #groupedIcon; }
|
||||||
#groupedIcon; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group {
|
.input-group {
|
||||||
@@ -294,16 +294,29 @@
|
|||||||
height : 100%;
|
height : 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.invalid:focus { background-color : pink; }
|
.input-group {
|
||||||
|
height : ~'calc(.9em + 4px + .6em)';
|
||||||
|
|
||||||
.icon {
|
input { border-radius : 0.5em 0 0 0.5em; }
|
||||||
#groupedIcon;
|
|
||||||
top : -0.54em;
|
|
||||||
right : 1px;
|
|
||||||
height : 97%;
|
|
||||||
font-size : 0.8em;
|
|
||||||
|
|
||||||
i { font-size : 1.125em; }
|
input:last-child { border-radius : 0.5em; }
|
||||||
|
|
||||||
|
.value {
|
||||||
|
width : 7.5vw;
|
||||||
|
min-width : 75px;
|
||||||
|
height : 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invalid:focus { background-color : pink; }
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
#groupedIcon;
|
||||||
|
top : -0.54em;
|
||||||
|
right : 1px;
|
||||||
|
height : 97%;
|
||||||
|
|
||||||
|
i { font-size : 1.125em; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ const StringArrayEditor = createClass({
|
|||||||
|
|
||||||
return <div className='field'>
|
return <div className='field'>
|
||||||
<label>{this.props.label}</label>
|
<label>{this.props.label}</label>
|
||||||
<div style={{ flex: '1 0' }}>
|
<div style={{ flex: '1 0' }} className='value'>
|
||||||
<div className='list'>
|
<div className='list'>
|
||||||
{valueElements}
|
{valueElements}
|
||||||
<div className='input-group'>
|
<div className='input-group'>
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
const React = require('react');
|
|
||||||
const createClass = require('create-react-class');
|
|
||||||
const cx = require('classnames');
|
|
||||||
const Nav = require('naturalcrit/nav/nav.jsx');
|
|
||||||
|
|
||||||
const MAX_TITLE_LENGTH = 50;
|
|
||||||
|
|
||||||
|
|
||||||
const EditTitle = createClass({
|
|
||||||
displayName : 'EditTitleNavItem',
|
|
||||||
getDefaultProps : function() {
|
|
||||||
return {
|
|
||||||
title : '',
|
|
||||||
onChange : function(){}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
handleChange : function(e){
|
|
||||||
if(e.target.value.length > MAX_TITLE_LENGTH) return;
|
|
||||||
this.props.onChange(e.target.value);
|
|
||||||
},
|
|
||||||
render : function(){
|
|
||||||
return <Nav.item className='editTitle'>
|
|
||||||
<input placeholder='Brew Title' type='text' value={this.props.title} onChange={this.handleChange} />
|
|
||||||
|
|
||||||
<div className={cx('charCount', { 'max': this.props.title.length >= MAX_TITLE_LENGTH })}>
|
|
||||||
{this.props.title.length}/{MAX_TITLE_LENGTH}
|
|
||||||
</div>
|
|
||||||
</Nav.item>;
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = EditTitle;
|
|
||||||
@@ -36,7 +36,7 @@ const RecentItems = createClass({
|
|||||||
//== Add current brew to appropriate recent items list (depending on storageKey) ==//
|
//== Add current brew to appropriate recent items list (depending on storageKey) ==//
|
||||||
if(this.props.storageKey == 'edit'){
|
if(this.props.storageKey == 'edit'){
|
||||||
let editId = this.props.brew.editId;
|
let editId = this.props.brew.editId;
|
||||||
if(this.props.brew.googleId){
|
if(this.props.brew.googleId && !this.props.brew.stubbed){
|
||||||
editId = `${this.props.brew.googleId}${this.props.brew.editId}`;
|
editId = `${this.props.brew.googleId}${this.props.brew.editId}`;
|
||||||
}
|
}
|
||||||
edited = _.filter(edited, (brew)=>{
|
edited = _.filter(edited, (brew)=>{
|
||||||
@@ -51,7 +51,7 @@ const RecentItems = createClass({
|
|||||||
}
|
}
|
||||||
if(this.props.storageKey == 'view'){
|
if(this.props.storageKey == 'view'){
|
||||||
let shareId = this.props.brew.shareId;
|
let shareId = this.props.brew.shareId;
|
||||||
if(this.props.brew.googleId){
|
if(this.props.brew.googleId && !this.props.brew.stubbed){
|
||||||
shareId = `${this.props.brew.googleId}${this.props.brew.shareId}`;
|
shareId = `${this.props.brew.googleId}${this.props.brew.shareId}`;
|
||||||
}
|
}
|
||||||
viewed = _.filter(viewed, (brew)=>{
|
viewed = _.filter(viewed, (brew)=>{
|
||||||
@@ -83,7 +83,7 @@ const RecentItems = createClass({
|
|||||||
let edited = JSON.parse(localStorage.getItem(EDIT_KEY) || '[]');
|
let edited = JSON.parse(localStorage.getItem(EDIT_KEY) || '[]');
|
||||||
if(this.props.storageKey == 'edit') {
|
if(this.props.storageKey == 'edit') {
|
||||||
let prevEditId = prevProps.brew.editId;
|
let prevEditId = prevProps.brew.editId;
|
||||||
if(prevProps.brew.googleId){
|
if(prevProps.brew.googleId && !this.props.brew.stubbed){
|
||||||
prevEditId = `${prevProps.brew.googleId}${prevProps.brew.editId}`;
|
prevEditId = `${prevProps.brew.googleId}${prevProps.brew.editId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ const RecentItems = createClass({
|
|||||||
return brew.id !== prevEditId;
|
return brew.id !== prevEditId;
|
||||||
});
|
});
|
||||||
let editId = this.props.brew.editId;
|
let editId = this.props.brew.editId;
|
||||||
if(this.props.brew.googleId){
|
if(this.props.brew.googleId && !this.props.brew.stubbed){
|
||||||
editId = `${this.props.brew.googleId}${this.props.brew.editId}`;
|
editId = `${this.props.brew.googleId}${this.props.brew.editId}`;
|
||||||
}
|
}
|
||||||
edited.unshift({
|
edited.unshift({
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
const React = require('react');
|
|
||||||
const createClass = require('create-react-class');
|
|
||||||
const Nav = require('naturalcrit/nav/nav.jsx');
|
|
||||||
|
|
||||||
const MAIN_URL = 'https://www.reddit.com/r/UnearthedArcana/submit?selftext=true';
|
|
||||||
|
|
||||||
|
|
||||||
const RedditShare = createClass({
|
|
||||||
displayName : 'RedditShareNavItem',
|
|
||||||
getDefaultProps : function() {
|
|
||||||
return {
|
|
||||||
brew : {
|
|
||||||
title : '',
|
|
||||||
sharedId : '',
|
|
||||||
text : ''
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
getText : function(){
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
handleClick : function(){
|
|
||||||
const url = [
|
|
||||||
MAIN_URL,
|
|
||||||
`title=${encodeURIComponent(this.props.brew.title ? this.props.brew.title : 'Check out my brew!')}`,
|
|
||||||
`text=${encodeURIComponent(this.props.brew.text)}`
|
|
||||||
].join('&');
|
|
||||||
|
|
||||||
window.open(url, '_blank');
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
render : function(){
|
|
||||||
return <Nav.item icon='fa-reddit-alien' color='red' onClick={this.handleClick}>
|
|
||||||
share on reddit
|
|
||||||
</Nav.item>;
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = RedditShare;
|
|
||||||
@@ -32,7 +32,7 @@ import { updateHistory, versionHistoryGarbageCollection } from '../../utils/vers
|
|||||||
|
|
||||||
const googleDriveIcon = require('../../googleDrive.svg');
|
const googleDriveIcon = require('../../googleDrive.svg');
|
||||||
|
|
||||||
const SAVE_TIMEOUT = 3000;
|
const SAVE_TIMEOUT = 10000;
|
||||||
|
|
||||||
const EditPage = createClass({
|
const EditPage = createClass({
|
||||||
displayName : 'EditPage',
|
displayName : 'EditPage',
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ const SharePage = createClass({
|
|||||||
|
|
||||||
getInitialState : function() {
|
getInitialState : function() {
|
||||||
return {
|
return {
|
||||||
themeBundle : {}
|
themeBundle : {},
|
||||||
|
currentBrewRendererPageNum : 1
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -39,6 +40,10 @@ const SharePage = createClass({
|
|||||||
document.removeEventListener('keydown', this.handleControlKeys);
|
document.removeEventListener('keydown', this.handleControlKeys);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleBrewRendererPageChange : function(pageNumber){
|
||||||
|
this.setState({ currentBrewRendererPageNum: pageNumber });
|
||||||
|
},
|
||||||
|
|
||||||
handleControlKeys : function(e){
|
handleControlKeys : function(e){
|
||||||
if(!(e.ctrlKey || e.metaKey)) return;
|
if(!(e.ctrlKey || e.metaKey)) return;
|
||||||
const P_KEY = 80;
|
const P_KEY = 80;
|
||||||
@@ -114,9 +119,12 @@ const SharePage = createClass({
|
|||||||
<BrewRenderer
|
<BrewRenderer
|
||||||
text={this.props.brew.text}
|
text={this.props.brew.text}
|
||||||
style={this.props.brew.style}
|
style={this.props.brew.style}
|
||||||
|
lang={this.props.brew.lang}
|
||||||
renderer={this.props.brew.renderer}
|
renderer={this.props.brew.renderer}
|
||||||
theme={this.props.brew.theme}
|
theme={this.props.brew.theme}
|
||||||
themeBundle={this.state.themeBundle}
|
themeBundle={this.state.themeBundle}
|
||||||
|
onPageChange={this.handleBrewRendererPageChange}
|
||||||
|
currentBrewRendererPageNum={this.state.currentBrewRendererPageNum}
|
||||||
allowPrint={true}
|
allowPrint={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/*eslint max-lines: ["warn", {"max": 400, "skipBlankLines": true, "skipComments": true}]*/
|
||||||
|
/*eslint max-params:["warn", { max: 10 }], */
|
||||||
require('./vaultPage.less');
|
require('./vaultPage.less');
|
||||||
|
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
@@ -18,13 +20,15 @@ const request = require('../../utils/request-middleware.js');
|
|||||||
const VaultPage = (props)=>{
|
const VaultPage = (props)=>{
|
||||||
const [pageState, setPageState] = useState(parseInt(props.query.page) || 1);
|
const [pageState, setPageState] = useState(parseInt(props.query.page) || 1);
|
||||||
|
|
||||||
|
const [sortState, setSort] = useState(props.query.sort || 'title');
|
||||||
|
const [dirState, setdir] = useState(props.query.dir || 'asc');
|
||||||
|
|
||||||
//Response state
|
//Response state
|
||||||
const [brewCollection, setBrewCollection] = useState(null);
|
const [brewCollection, setBrewCollection] = useState(null);
|
||||||
const [totalBrews, setTotalBrews] = useState(null);
|
const [totalBrews, setTotalBrews] = useState(null);
|
||||||
const [searching, setSearching] = useState(false);
|
const [searching, setSearching] = useState(false);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
|
|
||||||
const titleRef = useRef(null);
|
const titleRef = useRef(null);
|
||||||
const authorRef = useRef(null);
|
const authorRef = useRef(null);
|
||||||
const countRef = useRef(null);
|
const countRef = useRef(null);
|
||||||
@@ -34,7 +38,7 @@ const VaultPage = (props)=>{
|
|||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
disableSubmitIfFormInvalid();
|
disableSubmitIfFormInvalid();
|
||||||
loadPage(pageState, true);
|
loadPage(pageState, true, props.query.sort, props.query.dir);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const updateStateWithBrews = (brews, page)=>{
|
const updateStateWithBrews = (brews, page)=>{
|
||||||
@@ -43,7 +47,7 @@ const VaultPage = (props)=>{
|
|||||||
setSearching(false);
|
setSearching(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateUrl = (titleValue, authorValue, countValue, v3Value, legacyValue, page)=>{
|
const updateUrl = (titleValue, authorValue, countValue, v3Value, legacyValue, page, sort, dir)=>{
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
const urlParams = new URLSearchParams(url.search);
|
const urlParams = new URLSearchParams(url.search);
|
||||||
|
|
||||||
@@ -53,21 +57,23 @@ const VaultPage = (props)=>{
|
|||||||
urlParams.set('v3', v3Value);
|
urlParams.set('v3', v3Value);
|
||||||
urlParams.set('legacy', legacyValue);
|
urlParams.set('legacy', legacyValue);
|
||||||
urlParams.set('page', page);
|
urlParams.set('page', page);
|
||||||
|
urlParams.set('sort', sort);
|
||||||
|
urlParams.set('dir', dir);
|
||||||
|
|
||||||
url.search = urlParams.toString();
|
url.search = urlParams.toString();
|
||||||
window.history.replaceState(null, '', url.toString());
|
window.history.replaceState(null, '', url.toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
const performSearch = async (title, author, count, v3, legacy, page)=>{
|
const performSearch = async (title, author, count, v3, legacy, page, sort, dir)=>{
|
||||||
updateUrl(title, author, count, v3, legacy, page);
|
updateUrl(title, author, count, v3, legacy, page, sort, dir);
|
||||||
|
|
||||||
const response = await request.get(
|
const response = await request
|
||||||
`/api/vault?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}&count=${count}&page=${page}`
|
.get(`/api/vault?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}&count=${count}&page=${page}&sort=${sort}&dir=${dir}`)
|
||||||
).catch((error)=>{
|
.catch((error)=>{
|
||||||
console.log('error at loadPage: ', error);
|
console.log('error at loadPage: ', error);
|
||||||
setError(error);
|
setError(error);
|
||||||
updateStateWithBrews([], 1);
|
updateStateWithBrews([], 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(response.ok)
|
if(response.ok)
|
||||||
updateStateWithBrews(response.body.brews, page);
|
updateStateWithBrews(response.body.brews, page);
|
||||||
@@ -76,9 +82,8 @@ const VaultPage = (props)=>{
|
|||||||
const loadTotal = async (title, author, v3, legacy)=>{
|
const loadTotal = async (title, author, v3, legacy)=>{
|
||||||
setTotalBrews(null);
|
setTotalBrews(null);
|
||||||
|
|
||||||
const response = await request.get(
|
const response = await request.get(`/api/vault/total?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}`)
|
||||||
`/api/vault/total?title=${title}&author=${author}&v3=${v3}&legacy=${legacy}`
|
.catch((error)=>{
|
||||||
).catch((error)=>{
|
|
||||||
console.log('error at loadTotal: ', error);
|
console.log('error at loadTotal: ', error);
|
||||||
setError(error);
|
setError(error);
|
||||||
updateStateWithBrews([], 1);
|
updateStateWithBrews([], 1);
|
||||||
@@ -88,9 +93,8 @@ const VaultPage = (props)=>{
|
|||||||
setTotalBrews(response.body.totalBrews);
|
setTotalBrews(response.body.totalBrews);
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadPage = async (page, updateTotal)=>{
|
const loadPage = async (page, updateTotal, sort, dir)=>{
|
||||||
if(!validateForm())
|
if(!validateForm()) return;
|
||||||
return;
|
|
||||||
|
|
||||||
setSearching(true);
|
setSearching(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
@@ -100,8 +104,14 @@ const VaultPage = (props)=>{
|
|||||||
const count = countRef.current.value || 10;
|
const count = countRef.current.value || 10;
|
||||||
const v3 = v3Ref.current.checked != false;
|
const v3 = v3Ref.current.checked != false;
|
||||||
const legacy = legacyRef.current.checked != false;
|
const legacy = legacyRef.current.checked != false;
|
||||||
|
const sortOption = sort || 'title';
|
||||||
|
const dirOption = dir || 'asc';
|
||||||
|
const pageProp = page || 1;
|
||||||
|
|
||||||
performSearch(title, author, count, v3, legacy, page);
|
setSort(sortOption);
|
||||||
|
setdir(dirOption);
|
||||||
|
|
||||||
|
performSearch(title, author, count, v3, legacy, pageProp, sortOption, dirOption);
|
||||||
|
|
||||||
if(updateTotal)
|
if(updateTotal)
|
||||||
loadTotal(title, author, v3, legacy);
|
loadTotal(title, author, v3, legacy);
|
||||||
@@ -248,6 +258,33 @@ const VaultPage = (props)=>{
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const renderSortOption = (optionTitle, optionValue)=>{
|
||||||
|
const oppositeDir = dirState === 'asc' ? 'desc' : 'asc';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`sort-option ${sortState === optionValue ? `active` : ''}`}>
|
||||||
|
<button onClick={()=>loadPage(1, false, optionValue, oppositeDir)}>
|
||||||
|
{optionTitle}
|
||||||
|
</button>
|
||||||
|
{sortState === optionValue && (
|
||||||
|
<i className={`sortDir fas ${dirState === 'asc' ? 'fa-sort-up' : 'fa-sort-down'}`} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderSortBar = ()=>{
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='sort-container'>
|
||||||
|
{renderSortOption('Title', 'title', props.query.dir)}
|
||||||
|
{renderSortOption('Created Date', 'createdAt', props.query.dir)}
|
||||||
|
{renderSortOption('Updated Date', 'updatedAt', props.query.dir)}
|
||||||
|
{renderSortOption('Views', 'views', props.query.dir)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const renderPaginationControls = ()=>{
|
const renderPaginationControls = ()=>{
|
||||||
if(!totalBrews) return null;
|
if(!totalBrews) return null;
|
||||||
|
|
||||||
@@ -271,10 +308,8 @@ const VaultPage = (props)=>{
|
|||||||
.map((_, index)=>(
|
.map((_, index)=>(
|
||||||
<a
|
<a
|
||||||
key={startPage + index}
|
key={startPage + index}
|
||||||
className={`pageNumber ${
|
className={`pageNumber ${pageState === startPage + index ? 'currentPage' : ''}`}
|
||||||
pageState === startPage + index ? 'currentPage' : ''
|
onClick={()=>loadPage(startPage + index, false, sortState, dirState)}
|
||||||
}`}
|
|
||||||
onClick={()=>loadPage(startPage + index, false)}
|
|
||||||
>
|
>
|
||||||
{startPage + index}
|
{startPage + index}
|
||||||
</a>
|
</a>
|
||||||
@@ -284,7 +319,7 @@ const VaultPage = (props)=>{
|
|||||||
<div className='paginationControls'>
|
<div className='paginationControls'>
|
||||||
<button
|
<button
|
||||||
className='previousPage'
|
className='previousPage'
|
||||||
onClick={()=>loadPage(pageState - 1, false)}
|
onClick={()=>loadPage(pageState - 1, false, sortState, dirState)}
|
||||||
disabled={pageState === startPage}
|
disabled={pageState === startPage}
|
||||||
>
|
>
|
||||||
<i className='fa-solid fa-chevron-left'></i>
|
<i className='fa-solid fa-chevron-left'></i>
|
||||||
@@ -293,7 +328,7 @@ const VaultPage = (props)=>{
|
|||||||
{startPage > 1 && (
|
{startPage > 1 && (
|
||||||
<a
|
<a
|
||||||
className='pageNumber firstPage'
|
className='pageNumber firstPage'
|
||||||
onClick={()=>loadPage(1, false)}
|
onClick={()=>loadPage(1, false, sortState, dirState)}
|
||||||
>
|
>
|
||||||
1 ...
|
1 ...
|
||||||
</a>
|
</a>
|
||||||
@@ -302,7 +337,7 @@ const VaultPage = (props)=>{
|
|||||||
{endPage < totalPages && (
|
{endPage < totalPages && (
|
||||||
<a
|
<a
|
||||||
className='pageNumber lastPage'
|
className='pageNumber lastPage'
|
||||||
onClick={()=>loadPage(totalPages, false)}
|
onClick={()=>loadPage(totalPages, false, sortState, dirState)}
|
||||||
>
|
>
|
||||||
... {totalPages}
|
... {totalPages}
|
||||||
</a>
|
</a>
|
||||||
@@ -310,7 +345,7 @@ const VaultPage = (props)=>{
|
|||||||
</ol>
|
</ol>
|
||||||
<button
|
<button
|
||||||
className='nextPage'
|
className='nextPage'
|
||||||
onClick={()=>loadPage(pageState + 1, false)}
|
onClick={()=>loadPage(pageState + 1, false, sortState, dirState)}
|
||||||
disabled={pageState === totalPages}
|
disabled={pageState === totalPages}
|
||||||
>
|
>
|
||||||
<i className='fa-solid fa-chevron-right'></i>
|
<i className='fa-solid fa-chevron-right'></i>
|
||||||
@@ -385,6 +420,7 @@ const VaultPage = (props)=>{
|
|||||||
<div className='form dataGroup'>{renderForm()}</div>
|
<div className='form dataGroup'>{renderForm()}</div>
|
||||||
|
|
||||||
<div className='resultsContainer dataGroup'>
|
<div className='resultsContainer dataGroup'>
|
||||||
|
{renderSortBar()}
|
||||||
{renderFoundBrews()}
|
{renderFoundBrews()}
|
||||||
</div>
|
</div>
|
||||||
</SplitPane>
|
</SplitPane>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
*:not(input) { user-select : none; }
|
*:not(input) { user-select : none; }
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
height : 100%;
|
||||||
background : #2C3E50;
|
background : #2C3E50;
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
.dataGroup {
|
.dataGroup {
|
||||||
width : 100%;
|
width : 100%;
|
||||||
@@ -27,9 +27,9 @@
|
|||||||
|
|
||||||
code {
|
code {
|
||||||
padding-inline : 5px;
|
padding-inline : 5px;
|
||||||
|
font-family : monospace;
|
||||||
background : lightgrey;
|
background : lightgrey;
|
||||||
border-radius : 5px;
|
border-radius : 5px;
|
||||||
font-family : monospace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3, h4 {
|
h1, h2, h3, h4 {
|
||||||
@@ -165,6 +165,48 @@
|
|||||||
color : white;
|
color : white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sort-container {
|
||||||
|
display : flex;
|
||||||
|
flex-wrap : wrap;
|
||||||
|
column-gap : 15px;
|
||||||
|
justify-content : center;
|
||||||
|
height : 30px;
|
||||||
|
color : white;
|
||||||
|
background-color : #555555;
|
||||||
|
border-top : 1px solid #666666;
|
||||||
|
border-bottom : 1px solid #666666;
|
||||||
|
|
||||||
|
.sort-option {
|
||||||
|
display : flex;
|
||||||
|
align-items : center;
|
||||||
|
padding : 0 8px;
|
||||||
|
|
||||||
|
&:hover { background-color : #444444; }
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color : #333333;
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-weight : 800;
|
||||||
|
color : white;
|
||||||
|
|
||||||
|
& + .sortDir { padding-left : 5px; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding : 0;
|
||||||
|
font-size : 11px;
|
||||||
|
font-weight : normal;
|
||||||
|
color : #CCCCCC;
|
||||||
|
text-transform : uppercase;
|
||||||
|
background-color : transparent;
|
||||||
|
|
||||||
|
&:hover { background : none; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.foundBrews {
|
.foundBrews {
|
||||||
position : relative;
|
position : relative;
|
||||||
width : 100%;
|
width : 100%;
|
||||||
@@ -236,15 +278,15 @@
|
|||||||
width : 47%;
|
width : 47%;
|
||||||
margin-right : 40px;
|
margin-right : 40px;
|
||||||
color : black;
|
color : black;
|
||||||
isolation:isolate;
|
isolation : isolate;
|
||||||
|
|
||||||
&:after {
|
&::after {
|
||||||
position:absolute;
|
position : absolute;
|
||||||
inset:0;
|
inset : 0;
|
||||||
display:block;
|
z-index : -2;
|
||||||
content:'';
|
display : block;
|
||||||
|
content : '';
|
||||||
background-image : url('/assets/parchmentBackground.jpg');
|
background-image : url('/assets/parchmentBackground.jpg');
|
||||||
z-index:-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:nth-child(even of .brewItem) { margin-right : 0; }
|
&:nth-child(even of .brewItem) { margin-right : 0; }
|
||||||
@@ -257,28 +299,24 @@
|
|||||||
color : var(--HB_Color_HeaderText);
|
color : var(--HB_Color_HeaderText);
|
||||||
}
|
}
|
||||||
.info {
|
.info {
|
||||||
|
position : relative;
|
||||||
|
z-index : 2;
|
||||||
font-family : 'ScalySansRemake';
|
font-family : 'ScalySansRemake';
|
||||||
font-size : 1.2em;
|
font-size : 1.2em;
|
||||||
position:relative;
|
|
||||||
z-index:2;
|
|
||||||
|
|
||||||
>span {
|
>span {
|
||||||
margin-right : 12px;
|
margin-right : 12px;
|
||||||
line-height : 1.5em;
|
line-height : 1.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.links {
|
.links { z-index : 2; }
|
||||||
z-index:2;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
margin: 0px;
|
margin : 0px;
|
||||||
visibility: hidden;
|
visibility : hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thumbnail {
|
.thumbnail { z-index : -1; }
|
||||||
z-index:1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.paginationControls {
|
.paginationControls {
|
||||||
|
|||||||
@@ -6,5 +6,7 @@
|
|||||||
"enable_v3" : true,
|
"enable_v3" : true,
|
||||||
"enable_themes" : true,
|
"enable_themes" : true,
|
||||||
"local_environments" : ["docker", "local"],
|
"local_environments" : ["docker", "local"],
|
||||||
"publicUrl" : "https://homebrewery.naturalcrit.com"
|
"publicUrl" : "https://homebrewery.naturalcrit.com",
|
||||||
|
"hb_images" : null,
|
||||||
|
"hb_fonts" : null
|
||||||
}
|
}
|
||||||
|
|||||||
1473
package-lock.json
generated
1473
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@@ -86,20 +86,20 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.25.2",
|
"@babel/core": "^7.25.7",
|
||||||
"@babel/plugin-transform-runtime": "^7.25.4",
|
"@babel/plugin-transform-runtime": "^7.25.7",
|
||||||
"@babel/preset-env": "^7.25.4",
|
"@babel/preset-env": "^7.25.7",
|
||||||
"@babel/preset-react": "^7.24.7",
|
"@babel/preset-react": "^7.25.7",
|
||||||
"@googleapis/drive": "^8.14.0",
|
"@googleapis/drive": "^8.14.0",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"codemirror": "^5.65.6",
|
"codemirror": "^5.65.6",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.7",
|
||||||
"create-react-class": "^15.7.0",
|
"create-react-class": "^15.7.0",
|
||||||
"dedent-tabs": "^0.10.3",
|
"dedent-tabs": "^0.10.3",
|
||||||
"dompurify": "^3.1.6",
|
"dompurify": "^3.1.7",
|
||||||
"expr-eval": "^2.0.2",
|
"expr-eval": "^2.0.2",
|
||||||
"express": "^4.21.0",
|
"express": "^4.21.1",
|
||||||
"express-async-handler": "^1.2.0",
|
"express-async-handler": "^1.2.0",
|
||||||
"express-static-gzip": "2.1.8",
|
"express-static-gzip": "2.1.8",
|
||||||
"fs-extra": "11.2.0",
|
"fs-extra": "11.2.0",
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
"marked-smartypants-lite": "^1.0.2",
|
"marked-smartypants-lite": "^1.0.2",
|
||||||
"markedLegacy": "npm:marked@^0.3.19",
|
"markedLegacy": "npm:marked@^0.3.19",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"mongoose": "^8.6.2",
|
"mongoose": "^8.7.0",
|
||||||
"nanoid": "3.3.4",
|
"nanoid": "3.3.4",
|
||||||
"nconf": "^0.12.1",
|
"nconf": "^0.12.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
@@ -126,16 +126,16 @@
|
|||||||
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
|
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@stylistic/stylelint-plugin": "^3.0.1",
|
"@stylistic/stylelint-plugin": "^3.1.1",
|
||||||
"eslint": "^9.10.0",
|
"eslint": "^9.12.0",
|
||||||
"eslint-plugin-jest": "^28.8.3",
|
"eslint-plugin-jest": "^28.8.3",
|
||||||
"eslint-plugin-react": "^7.36.1",
|
"eslint-plugin-react": "^7.37.1",
|
||||||
"globals": "^15.9.0",
|
"globals": "^15.10.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-expect-message": "^1.1.3",
|
"jest-expect-message": "^1.1.3",
|
||||||
"postcss-less": "^6.0.0",
|
"postcss-less": "^6.0.0",
|
||||||
"stylelint": "^16.9.0",
|
"stylelint": "^16.9.0",
|
||||||
"stylelint-config-recess-order": "^5.1.0",
|
"stylelint-config-recess-order": "^5.1.1",
|
||||||
"stylelint-config-recommended": "^14.0.1",
|
"stylelint-config-recommended": "^14.0.1",
|
||||||
"supertest": "^7.0.0"
|
"supertest": "^7.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ const express = require('express');
|
|||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
const app = express();
|
const app = express();
|
||||||
const config = require('./config.js');
|
const config = require('./config.js');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
|
|
||||||
const { homebrewApi, getBrew, getUsersBrewThemes, getCSS } = require('./homebrew.api.js');
|
const { homebrewApi, getBrew, getUsersBrewThemes, getCSS } = require('./homebrew.api.js');
|
||||||
const GoogleActions = require('./googleActions.js');
|
const GoogleActions = require('./googleActions.js');
|
||||||
@@ -451,6 +453,10 @@ if(isLocalEnvironment){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add Static Local Paths
|
||||||
|
app.use('/staticImages', express.static(config.get('hb_images') && fs.existsSync(config.get('hb_images')) ? config.get('hb_images') :'staticImages'));
|
||||||
|
app.use('/staticFonts', express.static(config.get('hb_fonts') && fs.existsSync(config.get('hb_fonts')) ? config.get('hb_fonts'):'staticFonts'));
|
||||||
|
|
||||||
//Vault Page
|
//Vault Page
|
||||||
app.get('/vault', asyncHandler(async(req, res, next)=>{
|
app.get('/vault', asyncHandler(async(req, res, next)=>{
|
||||||
req.ogMeta = { ...defaultMetaTags,
|
req.ogMeta = { ...defaultMetaTags,
|
||||||
@@ -520,7 +526,7 @@ app.use(async (err, req, res, next)=>{
|
|||||||
err.originalUrl = req.originalUrl;
|
err.originalUrl = req.originalUrl;
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
||||||
if(err.originalUrl?.startsWith('/api/')) {
|
if(err.originalUrl?.startsWith('/api')) {
|
||||||
// console.log('API error');
|
// console.log('API error');
|
||||||
res.status(err.status || err.response?.status || 500).send(err);
|
res.status(err.status || err.response?.status || 500).send(err);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -172,7 +172,6 @@ const GoogleActions = {
|
|||||||
})
|
})
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log('Error saving to google');
|
console.log('Error saving to google');
|
||||||
console.error(err);
|
|
||||||
throw (err);
|
throw (err);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -211,7 +210,6 @@ const GoogleActions = {
|
|||||||
})
|
})
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
console.log('Error while creating new Google brew');
|
console.log('Error while creating new Google brew');
|
||||||
console.error(err);
|
|
||||||
throw (err);
|
throw (err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -242,11 +242,8 @@ const api = {
|
|||||||
|
|
||||||
let googleId, saved;
|
let googleId, saved;
|
||||||
if(saveToGoogle) {
|
if(saveToGoogle) {
|
||||||
googleId = await api.newGoogleBrew(req.account, newHomebrew, res)
|
googleId = await api.newGoogleBrew(req.account, newHomebrew, res);
|
||||||
.catch((err)=>{
|
|
||||||
console.error(err);
|
|
||||||
res.status(err?.status || err?.response?.status || 500).send(err?.message || err);
|
|
||||||
});
|
|
||||||
if(!googleId) return;
|
if(!googleId) return;
|
||||||
api.excludeStubProps(newHomebrew);
|
api.excludeStubProps(newHomebrew);
|
||||||
newHomebrew.googleId = googleId;
|
newHomebrew.googleId = googleId;
|
||||||
@@ -351,19 +348,13 @@ const api = {
|
|||||||
brew.googleId = undefined;
|
brew.googleId = undefined;
|
||||||
} else if(!brew.googleId && saveToGoogle) {
|
} else if(!brew.googleId && saveToGoogle) {
|
||||||
// If we don't have a google id and the user wants to save to google, create the google brew and set the google id on the brew
|
// If we don't have a google id and the user wants to save to google, create the google brew and set the google id on the brew
|
||||||
brew.googleId = await api.newGoogleBrew(req.account, api.excludeGoogleProps(brew), res)
|
brew.googleId = await api.newGoogleBrew(req.account, api.excludeGoogleProps(brew), res);
|
||||||
.catch((err)=>{
|
|
||||||
console.error(err);
|
|
||||||
res.status(err.status || err.response.status).send(err.message || err);
|
|
||||||
});
|
|
||||||
if(!brew.googleId) return;
|
if(!brew.googleId) return;
|
||||||
} else if(brew.googleId) {
|
} else if(brew.googleId) {
|
||||||
// If the google id exists and no other actions are being performed, update the google brew
|
// If the google id exists and no other actions are being performed, update the google brew
|
||||||
const updated = await GoogleActions.updateGoogleBrew(api.excludeGoogleProps(brew))
|
const updated = await GoogleActions.updateGoogleBrew(api.excludeGoogleProps(brew));
|
||||||
.catch((err)=>{
|
|
||||||
console.error(err);
|
|
||||||
res.status(err?.response?.status || 500).send(err);
|
|
||||||
});
|
|
||||||
if(!updated) return;
|
if(!updated) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -560,16 +560,6 @@ brew`);
|
|||||||
views : 0
|
views : 0
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle google error', async()=>{
|
|
||||||
google.newGoogleBrew = jest.fn(()=>{
|
|
||||||
throw 'err';
|
|
||||||
});
|
|
||||||
await api.newBrew({ body: { text: 'asdf', title: '' }, query: { saveToGoogle: true }, account: { username: 'test user' } }, res);
|
|
||||||
|
|
||||||
expect(res.status).toHaveBeenCalledWith(500);
|
|
||||||
expect(res.send).toHaveBeenCalledWith('err');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('deleteGoogleBrew', ()=>{
|
describe('deleteGoogleBrew', ()=>{
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
const config = require('../config.js');
|
||||||
|
const nodeEnv = config.get('node_env');
|
||||||
|
const isLocalEnvironment = config.get('local_environments').includes(nodeEnv);
|
||||||
|
|
||||||
module.exports = (req, res, next)=>{
|
module.exports = (req, res, next)=>{
|
||||||
const isImageRequest = req.get('Accept')?.split(',')
|
const isImageRequest = req.get('Accept')?.split(',')
|
||||||
?.filter((h)=>!h.includes('q='))
|
?.filter((h)=>!h.includes('q='))
|
||||||
?.every((h)=>/image\/.*/.test(h));
|
?.every((h)=>/image\/.*/.test(h));
|
||||||
if(isImageRequest) {
|
if(isImageRequest && !isLocalEnvironment && !req.url?.startsWith('/staticImages')) {
|
||||||
return res.status(406).send({
|
return res.status(406).send({
|
||||||
message : 'Request for image at this URL is not supported'
|
message : 'Request for image at this URL is not supported'
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,12 +29,18 @@ const rendererConditions = (legacy, v3)=>{
|
|||||||
return {}; // If all renderers selected, renderer field not needed in query for speed
|
return {}; // If all renderers selected, renderer field not needed in query for speed
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sortConditions = (sort, dir) => {
|
||||||
|
return { [sort]: dir === 'asc' ? 1 : -1 };
|
||||||
|
};
|
||||||
|
|
||||||
const findBrews = async (req, res)=>{
|
const findBrews = async (req, res)=>{
|
||||||
const title = req.query.title || '';
|
const title = req.query.title || '';
|
||||||
const author = req.query.author || '';
|
const author = req.query.author || '';
|
||||||
const page = Math.max(parseInt(req.query.page) || 1, 1);
|
const page = Math.max(parseInt(req.query.page) || 1, 1);
|
||||||
const count = Math.max(parseInt(req.query.count) || 20, 10);
|
const count = Math.max(parseInt(req.query.count) || 20, 10);
|
||||||
const skip = (page - 1) * count;
|
const skip = (page - 1) * count;
|
||||||
|
const sort = req.query.sort || 'title';
|
||||||
|
const dir = req.query.dir || 'asc';
|
||||||
|
|
||||||
const combinedQuery = {
|
const combinedQuery = {
|
||||||
$and : [
|
$and : [
|
||||||
@@ -54,6 +60,7 @@ const findBrews = async (req, res)=>{
|
|||||||
};
|
};
|
||||||
|
|
||||||
await HomebrewModel.find(combinedQuery, projection)
|
await HomebrewModel.find(combinedQuery, projection)
|
||||||
|
.sort(sortConditions(sort, dir))
|
||||||
.skip(skip)
|
.skip(skip)
|
||||||
.limit(count)
|
.limit(count)
|
||||||
.maxTimeMS(5000)
|
.maxTimeMS(5000)
|
||||||
|
|||||||
Reference in New Issue
Block a user