Skip to content

Commit

Permalink
Merge branch 'master' into addUserInfo-naturalcrit#1908
Browse files Browse the repository at this point in the history
  • Loading branch information
G-Ambatte authored Dec 22, 2022
2 parents c845f02 + 816860d commit 45b52b5
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 31 deletions.
21 changes: 19 additions & 2 deletions client/homebrew/editor/metadataEditor/metadataEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ const MetadataEditor = createClass({

render : function(){
return <div className='metadataEditor'>
<h1 className='sectionHead'>Brew</h1>

<div className='field title'>
<label>title</label>
<input type='text' className='value'
Expand Down Expand Up @@ -283,8 +285,6 @@ const MetadataEditor = createClass({
values={this.props.metadata.tags}
onChange={(e)=>this.handleFieldChange('tags', e)}/>

{this.renderAuthors()}

<div className='field systems'>
<label>systems</label>
<div className='value'>
Expand All @@ -296,6 +296,23 @@ const MetadataEditor = createClass({

{this.renderRenderOptions()}

<hr/>

<h1 className='sectionHead'>Authors</h1>

{this.renderAuthors()}

<StringArrayEditor label='invited authors' valuePatterns={[/.+/]}
validators={[(v)=>!this.props.metadata.authors.includes(v)]}
placeholder='invite author' unique={true}
values={this.props.metadata.invitedAuthors}
notes={['Invited authors 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)}/>

<hr/>

<h1 className='sectionHead'>Privacy</h1>

<div className='field publish'>
<label>publish</label>
<div className='value'>
Expand Down
20 changes: 16 additions & 4 deletions client/homebrew/editor/metadataEditor/metadataEditor.less
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
height : calc(100vh - 54px); // 54px is the height of the navbar + snippet bar. probably a better way to dynamic get this.
overflow-y : auto;

.sectionHead {
font-weight: 1000;
margin: 20px 0;

&:first-of-type {
margin-top: 0;
}
}

& > div {
margin-bottom: 10px;
}
Expand All @@ -30,6 +39,7 @@
}
.field{
display : flex;
flex-wrap : wrap;
width : 100%;
min-width : 200px;
&>label{
Expand Down Expand Up @@ -78,6 +88,11 @@
font-size : 0.8em;
}
}

small {
font-size : 0.6em;
font-style : italic;
}
}


Expand Down Expand Up @@ -128,10 +143,6 @@
button.unpublish{
.button(@silver);
}
small{
font-size : 0.6em;
font-style : italic;
}
}

.delete.field .value{
Expand Down Expand Up @@ -196,6 +207,7 @@
}
.field .list {
display: flex;
flex: 1 0;
flex-wrap: wrap;

> * {
Expand Down
27 changes: 17 additions & 10 deletions client/homebrew/editor/stringArrayEditor/stringArrayEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ const StringArrayEditor = createClass({
label : '',
values : [],
valuePatterns : null,
validators : [],
placeholder : '',
notes : [],
unique : false,
cannotEdit : [],
onChange : ()=>{}
Expand Down Expand Up @@ -83,7 +85,8 @@ const StringArrayEditor = createClass({
}
const matchesPatterns = !this.props.valuePatterns || this.props.valuePatterns.some((pattern)=>!!(value || '').match(pattern));
const uniqueIfSet = !this.props.unique || !values.includes(value);
return matchesPatterns && uniqueIfSet;
const passesValidators = !this.props.validators || this.props.validators.every((validator)=>validator(value));
return matchesPatterns && uniqueIfSet && passesValidators;
},

handleValueInputKeyDown : function(event, index) {
Expand Down Expand Up @@ -123,17 +126,21 @@ const StringArrayEditor = createClass({
</div>
);

return <div className='field values'>
return <div className='field'>
<label>{this.props.label}</label>
<div className='list'>
{valueElements}
<div className='input-group'>
<input type='text' className={`value ${this.valueIsValid(this.state.temporaryValue) ? '' : 'invalid'}`} placeholder={this.props.placeholder}
value={this.state.temporaryValue}
onKeyDown={(e)=>this.handleValueInputKeyDown(e)}
onChange={(e)=>this.setState({ temporaryValue: e.target.value })}/>
{this.valueIsValid(this.state.temporaryValue) ? <div className='icon steel' onClick={(e)=>{ e.stopPropagation(); this.addValue(this.state.temporaryValue); }}><i className='fa fa-check fa-fw'/></div> : null}
<div style={{ flex: '1 0' }}>
<div className='list'>
{valueElements}
<div className='input-group'>
<input type='text' className={`value ${this.valueIsValid(this.state.temporaryValue) ? '' : 'invalid'}`} placeholder={this.props.placeholder}
value={this.state.temporaryValue}
onKeyDown={(e)=>this.handleValueInputKeyDown(e)}
onChange={(e)=>this.setState({ temporaryValue: e.target.value })}/>
{this.valueIsValid(this.state.temporaryValue) ? <div className='icon steel' onClick={(e)=>{ e.stopPropagation(); this.addValue(this.state.temporaryValue); }}><i className='fa fa-check fa-fw'/></div> : null}
</div>
</div>

{this.props.notes ? this.props.notes.map((n)=><p><small>{n}</small></p>) : null}
</div>
</div>;
}
Expand Down
13 changes: 12 additions & 1 deletion client/homebrew/pages/editPage/editPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ const EditPage = createClass({
brew : { ...prevState.brew,
googleId : this.savedBrew.googleId ? this.savedBrew.googleId : null,
editId : this.savedBrew.editId,
shareId : this.savedBrew.shareId
shareId : this.savedBrew.shareId,
version : this.savedBrew.version
},
isPending : false,
isSaving : false,
Expand Down Expand Up @@ -329,6 +330,16 @@ const EditPage = createClass({
</Nav.item>;
}

if(this.state.errors.response.error.status === 409) {
const message = this.state.errors.response.body?.message;
return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer'>
{message ? message : 'Conflict: please refresh to get latest changes'}
</div>
</Nav.item>;
}

return <Nav.item className='save error' icon='fas fa-exclamation-triangle'>
Oops!
<div className='errorContainer'>
Expand Down
27 changes: 20 additions & 7 deletions server/homebrew.api.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ const getBrew = (accessType, stubOnly = false)=>{
}
});
stub = stub?.toObject();
if(accessType === 'edit' && stub?.authors?.length > 0 && !stub?.authors.includes(req.account?.username)) {
throw 'Current logged in user does not have access to this brew.';
}

// If there is a google id, try to find the google brew
if(!stubOnly && (googleId || stub?.googleId)) {
Expand All @@ -60,6 +57,14 @@ const getBrew = (accessType, stubOnly = false)=>{
// Combine the Homebrewery stub with the google brew, or if the stub doesn't exist just use the google brew
stub = stub ? _.assign({ ...excludeStubProps(stub), stubbed: true }, excludeGoogleProps(googleBrew)) : googleBrew;
}
const authorsExist = stub?.authors?.length > 0;
const isAuthor = stub?.authors?.includes(req.account?.username);
const isInvited = stub?.invitedAuthors?.includes(req.account?.username);
if(accessType === 'edit' && (authorsExist && !(isAuthor || isInvited))) {
throw `The current logged in user does not have editor access to this brew.
If you believe you should have access to this brew, ask the file owner to invite you as an author by opening the brew, viewing the Properties tab, and adding your username to the "invited authors" list. You can then try to access this document again.`;
}

// If after all of that we still don't have a brew, throw an exception
if(!stub && !stubOnly) {
Expand Down Expand Up @@ -111,15 +116,15 @@ const excludePropsFromUpdate = (brew)=>{

const excludeGoogleProps = (brew)=>{
const modified = _.clone(brew);
const propsToExclude = ['tags', 'systems', 'published', 'authors', 'owner', 'views', 'thumbnail'];
const propsToExclude = ['version', 'tags', 'systems', 'published', 'authors', 'owner', 'views', 'thumbnail'];
for (const prop of propsToExclude) {
delete modified[prop];
}
return modified;
};

const excludeStubProps = (brew)=>{
const propsToExclude = ['text', 'textBin', 'renderer', 'pageCount', 'version'];
const propsToExclude = ['text', 'textBin', 'renderer', 'pageCount'];
for (const prop of propsToExclude) {
brew[prop] = undefined;
}
Expand Down Expand Up @@ -187,7 +192,13 @@ const newBrew = async (req, res)=>{

const updateBrew = async (req, res)=>{
// Initialize brew from request and body, destructure query params, set a constant for the google id, and set the initial value for the after-save method
let brew = _.assign(req.brew, excludePropsFromUpdate(req.body));
const brewFromClient = excludePropsFromUpdate(req.body);
if(req.brew.version > brewFromClient.version) {
res.setHeader('Content-Type', 'application/json');
return res.status(409).send(JSON.stringify({ message: `The brew has been changed on a different device. Please save your changes elsewhere, refresh, and try again.` }));
}

let brew = _.assign(req.brew, brewFromClient);
const { saveToGoogle, removeFromGoogle } = req.query;
const googleId = brew.googleId;
let afterSave = async ()=>true;
Expand Down Expand Up @@ -233,9 +244,11 @@ const updateBrew = async (req, res)=>{
brew.text = undefined;
}
brew.updatedAt = new Date();
brew.version += 1;

if(req.account) {
brew.authors = _.uniq(_.concat(brew.authors, req.account.username));
brew.invitedAuthors = _.uniq(_.filter(brew.invitedAuthors, (a)=>req.account.username !== a));
}

// define a function to catch our save errors
Expand All @@ -252,7 +265,7 @@ const updateBrew = async (req, res)=>{
// if the brew does have a stub id, update it using the stub id as the key.
brew = _.assign(await HomebrewModel.findOne({ _id: brew._id }), brew);
saved = await brew.save()
.catch(saveError);
.catch(saveError);
}
if(!saved) return;
// Call and wait for afterSave to complete
Expand Down
15 changes: 8 additions & 7 deletions server/homebrew.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ const HomebrewSchema = mongoose.Schema({
textBin : { type: Buffer },
pageCount : { type: Number, default: 1 },

description : { type: String, default: '' },
tags : [String],
systems : [String],
renderer : { type: String, default: '' },
authors : [String],
published : { type: Boolean, default: false },
thumbnail : { type: String, default: '' },
description : { type: String, default: '' },
tags : [String],
systems : [String],
renderer : { type: String, default: '' },
authors : [String],
invitedAuthors : [String],
published : { type: Boolean, default: false },
thumbnail : { type: String, default: '' },

createdAt : { type: Date, default: Date.now },
updatedAt : { type: Date, default: Date.now },
Expand Down

0 comments on commit 45b52b5

Please sign in to comment.