create-strapi-app
Version:
Generate a new Strapi application.
275 lines (242 loc) • 7.27 kB
JavaScript
const fs = require('fs-extra');
const path = require('path');
const mime = require('mime-types');
const { categories, authors, articles, global, about } = require('../data/data.json');
async function seedExampleApp() {
const shouldImportSeedData = await isFirstRun();
if (shouldImportSeedData) {
try {
console.log('Setting up the template...');
await importSeedData();
console.log('Ready to go');
} catch (error) {
console.log('Could not import seed data');
console.error(error);
}
} else {
console.log(
'Seed data has already been imported. We cannot reimport unless you clear your database first.'
);
}
}
async function isFirstRun() {
const pluginStore = strapi.store({
environment: strapi.config.environment,
type: 'type',
name: 'setup',
});
const initHasRun = await pluginStore.get({ key: 'initHasRun' });
await pluginStore.set({ key: 'initHasRun', value: true });
return !initHasRun;
}
async function setPublicPermissions(newPermissions) {
// Find the ID of the public role
const publicRole = await strapi.query('plugin::users-permissions.role').findOne({
where: {
type: 'public',
},
});
// Create the new permissions and link them to the public role
const allPermissionsToCreate = [];
Object.keys(newPermissions).map((controller) => {
const actions = newPermissions[controller];
const permissionsToCreate = actions.map((action) => {
return strapi.query('plugin::users-permissions.permission').create({
data: {
action: `api::${controller}.${controller}.${action}`,
role: publicRole.id,
},
});
});
allPermissionsToCreate.push(...permissionsToCreate);
});
await Promise.all(allPermissionsToCreate);
}
function getFileSizeInBytes(filePath) {
const stats = fs.statSync(filePath);
const fileSizeInBytes = stats['size'];
return fileSizeInBytes;
}
function getFileData(fileName) {
const filePath = path.join('data', 'uploads', fileName);
// Parse the file metadata
const size = getFileSizeInBytes(filePath);
const ext = fileName.split('.').pop();
const mimeType = mime.lookup(ext || '') || '';
return {
filepath: filePath,
originalFileName: fileName,
size,
mimetype: mimeType,
};
}
async function uploadFile(file, name) {
return strapi
.plugin('upload')
.service('upload')
.upload({
files: file,
data: {
fileInfo: {
alternativeText: `An image uploaded to Strapi called ${name}`,
caption: name,
name,
},
},
});
}
// Create an entry and attach files if there are any
async function createEntry({ model, entry }) {
try {
// Actually create the entry in Strapi
await strapi.documents(`api::${model}.${model}`).create({
data: entry,
});
} catch (error) {
console.error({ model, entry, error });
}
}
async function checkFileExistsBeforeUpload(files) {
const existingFiles = [];
const uploadedFiles = [];
const filesCopy = [...files];
for (const fileName of filesCopy) {
// Check if the file already exists in Strapi
const fileWhereName = await strapi.query('plugin::upload.file').findOne({
where: {
name: fileName.replace(/\..*$/, ''),
},
});
if (fileWhereName) {
// File exists, don't upload it
existingFiles.push(fileWhereName);
} else {
// File doesn't exist, upload it
const fileData = getFileData(fileName);
const fileNameNoExtension = fileName.split('.').shift();
const [file] = await uploadFile(fileData, fileNameNoExtension);
uploadedFiles.push(file);
}
}
const allFiles = [...existingFiles, ...uploadedFiles];
// If only one file then return only that file
return allFiles.length === 1 ? allFiles[0] : allFiles;
}
async function updateBlocks(blocks) {
const updatedBlocks = [];
for (const block of blocks) {
if (block.__component === 'shared.media') {
const uploadedFiles = await checkFileExistsBeforeUpload([block.file]);
// Copy the block to not mutate directly
const blockCopy = { ...block };
// Replace the file name on the block with the actual file
blockCopy.file = uploadedFiles;
updatedBlocks.push(blockCopy);
} else if (block.__component === 'shared.slider') {
// Get files already uploaded to Strapi or upload new files
const existingAndUploadedFiles = await checkFileExistsBeforeUpload(block.files);
// Copy the block to not mutate directly
const blockCopy = { ...block };
// Replace the file names on the block with the actual files
blockCopy.files = existingAndUploadedFiles;
// Push the updated block
updatedBlocks.push(blockCopy);
} else {
// Just push the block as is
updatedBlocks.push(block);
}
}
return updatedBlocks;
}
async function importArticles() {
for (const article of articles) {
const cover = await checkFileExistsBeforeUpload([`${article.slug}.jpg`]);
const updatedBlocks = await updateBlocks(article.blocks);
await createEntry({
model: 'article',
entry: {
...article,
cover,
blocks: updatedBlocks,
// Make sure it's not a draft
publishedAt: Date.now(),
},
});
}
}
async function importGlobal() {
const favicon = await checkFileExistsBeforeUpload(['favicon.png']);
const shareImage = await checkFileExistsBeforeUpload(['default-image.png']);
return createEntry({
model: 'global',
entry: {
...global,
favicon,
// Make sure it's not a draft
publishedAt: Date.now(),
defaultSeo: {
...global.defaultSeo,
shareImage,
},
},
});
}
async function importAbout() {
const updatedBlocks = await updateBlocks(about.blocks);
await createEntry({
model: 'about',
entry: {
...about,
blocks: updatedBlocks,
// Make sure it's not a draft
publishedAt: Date.now(),
},
});
}
async function importCategories() {
for (const category of categories) {
await createEntry({ model: 'category', entry: category });
}
}
async function importAuthors() {
for (const author of authors) {
const avatar = await checkFileExistsBeforeUpload([author.avatar]);
await createEntry({
model: 'author',
entry: {
...author,
avatar,
},
});
}
}
async function importSeedData() {
// Allow read of application content types
await setPublicPermissions({
article: ['find', 'findOne'],
category: ['find', 'findOne'],
author: ['find', 'findOne'],
global: ['find', 'findOne'],
about: ['find', 'findOne'],
});
// Create all entries
await importCategories();
await importAuthors();
await importArticles();
await importGlobal();
await importAbout();
}
async function main() {
const { createStrapi, compileStrapi } = require('@strapi/strapi');
const appContext = await compileStrapi();
const app = await createStrapi(appContext).load();
app.log.level = 'error';
await seedExampleApp();
await app.destroy();
process.exit(0);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
;