Skip to content

Commit

Permalink
fix(slug): prevent slug change after publication
Browse files Browse the repository at this point in the history
  • Loading branch information
mathiazom committed Sep 23, 2024
1 parent f3b6e47 commit b5e0aa9
Showing 1 changed file with 32 additions and 8 deletions.
40 changes: 32 additions & 8 deletions studio/schemas/schemaTypes/slug.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { SlugValidationContext, defineField } from "sanity";
import { SlugValidationContext, defineField, isSlug } from "sanity";

import { apiVersion } from "studio/env";
import { isPublished } from "studio/utils/documentUtils";

async function isSlugUniqueAcrossAllDocuments(
Expand Down Expand Up @@ -49,18 +50,41 @@ function createSlugField(source: string) {
isUnique: isSlugUniqueAcrossAllDocuments,
},
validation: (rule) =>
rule.required().custom((value) => {
if (value?.current === undefined) return true;
return (
encodeURIComponent(value.current) === value.current ||
"Slug can only consist of latin letters (a-z, A-Z), digits (0-9), hyphen (-), underscore (_), full stop (.) and tilde (~)"
);
}),
rule
.required()
.custom((value) => {
if (value?.current === undefined) return true;
return (
encodeURIComponent(value.current) === value.current ||
"Slug can only consist of latin letters (a-z, A-Z), digits (0-9), hyphen (-), underscore (_), full stop (.) and tilde (~)"
);
})
.custom(async (value, { document, getClient }) => {
/*
prevent slug changes after initial publication
*/
if (document === undefined || isPublished(document)) return true;
const publishedDocument = await getClient({ apiVersion }).getDocument(
document._id.replace(/^drafts\./, ""),
);
if (
publishedDocument !== undefined &&
"slug" in publishedDocument &&
isSlug(publishedDocument.slug) &&
(value === undefined ||
publishedDocument.slug.current !== value.current)
) {
return "Can not be changed after publication";
}
return true;
}),
readOnly: (ctx) => {
/*
make slugs read-only after initial publish
to avoid breaking shared links
if document is already draft, this is handled through validation instead
if new slugs are needed, redirects can be used instead
*/
return ctx.document !== undefined && isPublished(ctx.document);
Expand Down

0 comments on commit b5e0aa9

Please sign in to comment.