seed.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. 'use strict';
  2. const fs = require('fs-extra');
  3. const path = require('path');
  4. const mime = require('mime-types');
  5. const { categories, authors, articles, global, about } = require('../data/data.json');
  6. async function seedExampleApp() {
  7. const shouldImportSeedData = await isFirstRun();
  8. if (shouldImportSeedData) {
  9. try {
  10. console.log('Setting up the template...');
  11. await importSeedData();
  12. console.log('Ready to go');
  13. } catch (error) {
  14. console.log('Could not import seed data');
  15. console.error(error);
  16. }
  17. } else {
  18. console.log(
  19. 'Seed data has already been imported. We cannot reimport unless you clear your database first.'
  20. );
  21. }
  22. }
  23. async function isFirstRun() {
  24. const pluginStore = strapi.store({
  25. environment: strapi.config.environment,
  26. type: 'type',
  27. name: 'setup',
  28. });
  29. const initHasRun = await pluginStore.get({ key: 'initHasRun' });
  30. await pluginStore.set({ key: 'initHasRun', value: true });
  31. return !initHasRun;
  32. }
  33. async function setPublicPermissions(newPermissions) {
  34. // Find the ID of the public role
  35. const publicRole = await strapi.query('plugin::users-permissions.role').findOne({
  36. where: {
  37. type: 'public',
  38. },
  39. });
  40. // Create the new permissions and link them to the public role
  41. const allPermissionsToCreate = [];
  42. Object.keys(newPermissions).map((controller) => {
  43. const actions = newPermissions[controller];
  44. const permissionsToCreate = actions.map((action) => {
  45. return strapi.query('plugin::users-permissions.permission').create({
  46. data: {
  47. action: `api::${controller}.${controller}.${action}`,
  48. role: publicRole.id,
  49. },
  50. });
  51. });
  52. allPermissionsToCreate.push(...permissionsToCreate);
  53. });
  54. await Promise.all(allPermissionsToCreate);
  55. }
  56. function getFileSizeInBytes(filePath) {
  57. const stats = fs.statSync(filePath);
  58. const fileSizeInBytes = stats['size'];
  59. return fileSizeInBytes;
  60. }
  61. function getFileData(fileName) {
  62. const filePath = path.join('data', 'uploads', fileName);
  63. // Parse the file metadata
  64. const size = getFileSizeInBytes(filePath);
  65. const ext = fileName.split('.').pop();
  66. const mimeType = mime.lookup(ext || '') || '';
  67. return {
  68. filepath: filePath,
  69. originalFileName: fileName,
  70. size,
  71. mimetype: mimeType,
  72. };
  73. }
  74. async function uploadFile(file, name) {
  75. return strapi
  76. .plugin('upload')
  77. .service('upload')
  78. .upload({
  79. files: file,
  80. data: {
  81. fileInfo: {
  82. alternativeText: `An image uploaded to Strapi called ${name}`,
  83. caption: name,
  84. name,
  85. },
  86. },
  87. });
  88. }
  89. // Create an entry and attach files if there are any
  90. async function createEntry({ model, entry }) {
  91. try {
  92. // Actually create the entry in Strapi
  93. await strapi.documents(`api::${model}.${model}`).create({
  94. data: entry,
  95. });
  96. } catch (error) {
  97. console.error({ model, entry, error });
  98. }
  99. }
  100. async function checkFileExistsBeforeUpload(files) {
  101. const existingFiles = [];
  102. const uploadedFiles = [];
  103. const filesCopy = [...files];
  104. for (const fileName of filesCopy) {
  105. // Check if the file already exists in Strapi
  106. const fileWhereName = await strapi.query('plugin::upload.file').findOne({
  107. where: {
  108. name: fileName.replace(/\..*$/, ''),
  109. },
  110. });
  111. if (fileWhereName) {
  112. // File exists, don't upload it
  113. existingFiles.push(fileWhereName);
  114. } else {
  115. // File doesn't exist, upload it
  116. const fileData = getFileData(fileName);
  117. const fileNameNoExtension = fileName.split('.').shift();
  118. const [file] = await uploadFile(fileData, fileNameNoExtension);
  119. uploadedFiles.push(file);
  120. }
  121. }
  122. const allFiles = [...existingFiles, ...uploadedFiles];
  123. // If only one file then return only that file
  124. return allFiles.length === 1 ? allFiles[0] : allFiles;
  125. }
  126. async function updateBlocks(blocks) {
  127. const updatedBlocks = [];
  128. for (const block of blocks) {
  129. if (block.__component === 'shared.media') {
  130. const uploadedFiles = await checkFileExistsBeforeUpload([block.file]);
  131. // Copy the block to not mutate directly
  132. const blockCopy = { ...block };
  133. // Replace the file name on the block with the actual file
  134. blockCopy.file = uploadedFiles;
  135. updatedBlocks.push(blockCopy);
  136. } else if (block.__component === 'shared.slider') {
  137. // Get files already uploaded to Strapi or upload new files
  138. const existingAndUploadedFiles = await checkFileExistsBeforeUpload(block.files);
  139. // Copy the block to not mutate directly
  140. const blockCopy = { ...block };
  141. // Replace the file names on the block with the actual files
  142. blockCopy.files = existingAndUploadedFiles;
  143. // Push the updated block
  144. updatedBlocks.push(blockCopy);
  145. } else {
  146. // Just push the block as is
  147. updatedBlocks.push(block);
  148. }
  149. }
  150. return updatedBlocks;
  151. }
  152. async function importArticles() {
  153. for (const article of articles) {
  154. const cover = await checkFileExistsBeforeUpload([`${article.slug}.jpg`]);
  155. const updatedBlocks = await updateBlocks(article.blocks);
  156. await createEntry({
  157. model: 'article',
  158. entry: {
  159. ...article,
  160. cover,
  161. blocks: updatedBlocks,
  162. // Make sure it's not a draft
  163. publishedAt: Date.now(),
  164. },
  165. });
  166. }
  167. }
  168. async function importGlobal() {
  169. const favicon = await checkFileExistsBeforeUpload(['favicon.png']);
  170. const shareImage = await checkFileExistsBeforeUpload(['default-image.png']);
  171. return createEntry({
  172. model: 'global',
  173. entry: {
  174. ...global,
  175. favicon,
  176. // Make sure it's not a draft
  177. publishedAt: Date.now(),
  178. defaultSeo: {
  179. ...global.defaultSeo,
  180. shareImage,
  181. },
  182. },
  183. });
  184. }
  185. async function importAbout() {
  186. const updatedBlocks = await updateBlocks(about.blocks);
  187. await createEntry({
  188. model: 'about',
  189. entry: {
  190. ...about,
  191. blocks: updatedBlocks,
  192. // Make sure it's not a draft
  193. publishedAt: Date.now(),
  194. },
  195. });
  196. }
  197. async function importCategories() {
  198. for (const category of categories) {
  199. await createEntry({ model: 'category', entry: category });
  200. }
  201. }
  202. async function importAuthors() {
  203. for (const author of authors) {
  204. const avatar = await checkFileExistsBeforeUpload([author.avatar]);
  205. await createEntry({
  206. model: 'author',
  207. entry: {
  208. ...author,
  209. avatar,
  210. },
  211. });
  212. }
  213. }
  214. async function importSeedData() {
  215. // Allow read of application content types
  216. await setPublicPermissions({
  217. article: ['find', 'findOne'],
  218. category: ['find', 'findOne'],
  219. author: ['find', 'findOne'],
  220. global: ['find', 'findOne'],
  221. about: ['find', 'findOne'],
  222. });
  223. // Create all entries
  224. await importCategories();
  225. await importAuthors();
  226. await importArticles();
  227. await importGlobal();
  228. await importAbout();
  229. }
  230. async function main() {
  231. const { createStrapi, compileStrapi } = require('@strapi/strapi');
  232. const appContext = await compileStrapi();
  233. const app = await createStrapi(appContext).load();
  234. app.log.level = 'error';
  235. await seedExampleApp();
  236. await app.destroy();
  237. process.exit(0);
  238. }
  239. main().catch((error) => {
  240. console.error(error);
  241. process.exit(1);
  242. });