Files
demo-project/my-strapi-project/src/bootstrap/setup-demo.ts
T
2026-05-19 22:15:11 +02:00

195 lines
6.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Core } from '@strapi/strapi';
const DEMO_EMAIL = 'demo@strapi-demo.local';
const DEMO_PASSWORD = 'Demo1234!';
type PermissionMap = Record<string, string[]>;
async function ensurePermissions(
strapi: Core.Strapi,
roleType: 'public' | 'authenticated',
permissions: PermissionMap,
) {
const role = await strapi.db.query('plugin::users-permissions.role').findOne({
where: { type: roleType },
});
if (!role) return;
for (const [uid, actions] of Object.entries(permissions)) {
for (const action of actions) {
const permissionAction = `${uid}.${action}`;
const existing = await strapi.db.query('plugin::users-permissions.permission').findOne({
where: { action: permissionAction, role: role.id },
});
if (!existing) {
await strapi.db.query('plugin::users-permissions.permission').create({
data: { action: permissionAction, role: role.id },
});
}
}
}
}
async function ensureDemoUser(strapi: Core.Strapi) {
const existing = await strapi.db.query('plugin::users-permissions.user').findOne({
where: { email: DEMO_EMAIL },
});
if (existing) return;
const authenticatedRole = await strapi.db.query('plugin::users-permissions.role').findOne({
where: { type: 'authenticated' },
});
if (!authenticatedRole) return;
await strapi.plugin('users-permissions').service('user').add({
username: 'demo',
email: DEMO_EMAIL,
password: DEMO_PASSWORD,
role: authenticatedRole.id,
confirmed: true,
provider: 'local',
});
strapi.log.info(`Demo user created: ${DEMO_EMAIL} / ${DEMO_PASSWORD}`);
}
async function seedGlobal(strapi: Core.Strapi) {
const existing = await strapi.documents('api::global.global').findFirst({});
const data = {
siteName: 'Strapi Demo',
siteDescription: 'A small demo site powered by Strapi and Vue.',
heroTitle: 'Content managed in Strapi',
heroSubtitle: 'Edit copy, blog posts, and member-only pages from the Strapi admin — no redeploy needed.',
heroCtaLabel: 'Explore the blog',
defaultSeo: {
metaTitle: 'Strapi Demo',
metaDescription: 'See what Strapi can do with a Vue frontend.',
},
};
if (!existing) {
await strapi.documents('api::global.global').create({ data });
} else {
await strapi.documents('api::global.global').update({
documentId: existing.documentId,
data,
});
}
}
async function seedAbout(strapi: Core.Strapi) {
const existing = await strapi.documents('api::about.about').findFirst({});
if (!existing) {
await strapi.documents('api::about.about').create({
data: {
title: 'About this demo',
blocks: [
{
__component: 'shared.rich-text',
body: 'This site is a minimal showcase of Strapi as a headless CMS. Public pages load content from the Strapi REST API. The member area is protected — only logged-in users can fetch that content.',
},
{
__component: 'shared.quote',
title: 'Why Strapi?',
body: 'Give editors a friendly admin panel while developers keep building with their favorite frontend framework.',
},
],
} as never,
});
}
}
async function seedBlogPosts(strapi: Core.Strapi) {
const posts = [
{
title: 'What is a headless CMS?',
slug: 'what-is-a-headless-cms',
excerpt: 'Separate content from presentation and deliver it anywhere via APIs.',
body: '<p>A headless CMS stores structured content and exposes it through APIs. Your Vue app (or mobile app, or another site) decides how to display it.</p>',
},
{
title: 'Why teams pick Strapi',
slug: 'why-teams-pick-strapi',
excerpt: 'Open source, customizable, and quick to set up for prototypes and production.',
body: '<p>Strapi gives you content types, roles, media library, and plugins out of the box — perfect for demos like this one.</p>',
},
{
title: 'Connecting Vue to Strapi',
slug: 'connecting-vue-to-strapi',
excerpt: 'Use the REST API and JWT auth from your frontend.',
body: '<p>This demo uses fetch with a JWT stored in localStorage. Public endpoints need no token; protected content sends Authorization: Bearer …</p>',
},
];
for (const post of posts) {
const existing = await strapi.documents('api::blog-post.blog-post').findFirst({
filters: { slug: post.slug },
});
if (existing) {
if (!existing.publishedAt) {
await strapi.documents('api::blog-post.blog-post').publish({
documentId: existing.documentId,
});
}
continue;
}
await strapi.documents('api::blog-post.blog-post').create({
data: post,
status: 'published',
});
}
const testPost = await strapi.documents('api::blog-post.blog-post').findFirst({
filters: { slug: 'test' },
});
if (testPost) {
await strapi.documents('api::blog-post.blog-post').delete({
documentId: testPost.documentId,
});
}
}
async function seedMemberArea(strapi: Core.Strapi) {
const existing = await strapi.documents('api::member-area.member-area').findFirst({});
const data = {
title: 'Welcome, member!',
content:
'<p>This page is loaded from Strapis <strong>Member Area</strong> single type. The Public role cannot read it — you had to log in so the API returns this content.</p><p>Try changing this text in the Strapi admin under Content Manager → Member Area.</p>',
};
if (!existing) {
await strapi.documents('api::member-area.member-area').create({ data });
}
}
export async function setupDemo(strapi: Core.Strapi) {
await ensurePermissions(strapi, 'public', {
'api::global.global': ['find'],
'api::about.about': ['find'],
'api::blog-post.blog-post': ['find', 'findOne'],
});
await ensurePermissions(strapi, 'authenticated', {
'api::member-area.member-area': ['find'],
});
await ensureDemoUser(strapi);
await seedGlobal(strapi);
await seedAbout(strapi);
await seedBlogPosts(strapi);
await seedMemberArea(strapi);
strapi.log.info('Demo content and permissions are ready.');
}
export { DEMO_EMAIL, DEMO_PASSWORD };