-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent Overwriting Files with Same Slug Names #1239
Conversation
Deploy preview for netlify-cms-www ready! Built with commit 3c02916 |
Deploy preview for cms-demo ready! Built with commit 3c02916 |
src/backends/backend.js
Outdated
persistEntry(config, collection, entryDraft, MediaFiles, integrations, options = {}) { | ||
async checkOverwrite(collection, slug, path, entryDraft) { | ||
const errorMessage = "Oops, duplicate filename found. Please choose a unique name." | ||
const existingEntry = window.repoFilesUnpublished.find(e => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, repoFilesUnpublished
is an implementation detail of the test-repo backend, not something most backend use, so this will have to be checked using a different method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To get them for any backend type, you should be able to use backend.unpublishedEntries()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be easier and more performant, however, to just check for the specific entry using unpublishedEntry()
instead of filtering them yourself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tech4him1 the problem is when backend.unpublishedEntry
uses implementation.unpublishedEntry
it throws an error if there is no entry found.
unpublishedEntry(collection, slug) {
const entry = window.repoFilesUnpublished.find(e => (
e.metaData.collection === collection.get('name') && e.slug === slug
));
if (!entry) {
return Promise.reject(new EditorialWorkflowError('content is not under editorial workflow', true));
}
return Promise.resolve(entry);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about:
import { EditorialWorkflowError } from "ValueObjects/errors"; // at top of js
const existingEntry = await this.implementation.unpublishedEntry(...).catch(error => ((error instanceof EditorialWorkflowError && error.notUnderEditorialWorkflow) ? Promise.resolve(false) : Promise.reject(error));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tech4him1 badass!
@brianlmacdonald Do you mind if I rebase this so the commit history and diff is clean? |
@tech4him1 Ugh. Sorry, when the fork branch and local branch diverged is where I failed to rebase this time. |
52b26f8
to
d971c68
Compare
With explicit slug editing on the horizon, I'm now thinking the goals of this PR should be met as a part of slug validation. Edit: hmm I was seeing some issues in the PR that made me think it simpler to take a different route, but on further review this PR seems to satisfy it's goal for now. |
@erquhart I always assumed this was intended to be a stop-gap until we explicit slug editing was added? |
Yeah, see my edit. I'm thinking this is good to go. |
src/backends/backend.js
Outdated
slug, | ||
raw: this.entryToRaw(collection, entryDraft.get("entry")), | ||
}; | ||
entryObj = await this.checkOverwrite(collection, slug, path, entryDraft); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of implicitly constructing and returning the entry object from checkOverwrite
, we should construct the entry object here either before or after the check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Working on an update commit. Noticed this only covers the "title" field, while both "title" and "field" could be used for the slug.
d971c68
to
ed18d9c
Compare
ed18d9c
to
b449760
Compare
Added a commit that does two things:
@brianlmacdonald @tech4him1 if both of you can give a review we can get this merged. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks awesome!
src/backends/backend.js
Outdated
return key.toLowerCase().trim() === field; | ||
}); | ||
}); | ||
return keys.find(key => entryData.get(key) !== undefined); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we can't use the old logic here, where we return the values (on line 48), instead of having to run entryData.get
again here? Maybe I'm mis-reading the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const keyVals = validIdentifierFields.map(field => {
return entryData.find((_, key) => {
return key.toLowerCase().trim() === field;
});
});
return keyVals.find(key => key !== undefined);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, I believe I was thinking we were lowercasing and trimming the return value for some reason, but that isn't the case.
This reverts commit 9a1c668.
This reverts commit b25544e.
Reverted in 1.8.2 to fix #1377. @brianlmacdonald this was breaking both simple and editorial workflow publishing of new entries. If you want to give it another go please open a new PR. |
@erquhart sure. Was this working before because it was running through the test-repo? |
Could have sworn I tested against real backends, but maybe it was just the test repo. |
I'm making a github backend now and running locally. I'm on gitter, I'll fire off questions if I get stuck. |
@erquhart This ended up being the fix.
|
This reverts commit 9a1c668.
Closes #1164.
Previously, when a file was added with the same title as an existing one and the slug equals title, the existing file is overwritten.
- Summary
This checks in
src/backends/backend.js
before theentryObj
is created inpersistEntry
if there's an existing file with the same name. Throws an Error if there is.First, for
editorialWorkflow
mode, it checks inwindow.repoFilesUnpublished
for preexisting entry. Next, it usesthis.implementation.getEntry
, checking if there's already a published entry in danger of being overwritten.- Test plan
I created a file called
test
Saved the file successfully, and checked that it was in workflow.
Then created a new file, also called
test
, tried to save it, and--Then instead, saved it as
Test 2
.Then published it.
Then created a new file, also called
Test 2
, and tried to save it, and --Error stopped it. All files are safe.
- Description for the changelog
Prevents file overwrite when encountering slug name collisions.
- A picture of a cute animal (not mandatory but encouraged)
Behold, a Fennec Fox at rest!