2
0

import.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. const loggerFactory = require('@alias/logger');
  2. const logger = loggerFactory('growi:routes:apiv3:import'); // eslint-disable-line no-unused-vars
  3. const path = require('path');
  4. const multer = require('multer');
  5. const { ObjectId } = require('mongoose').Types;
  6. const express = require('express');
  7. const router = express.Router();
  8. /**
  9. * @swagger
  10. * tags:
  11. * name: Import
  12. */
  13. module.exports = (crowi) => {
  14. const { importService } = crowi;
  15. const uploads = multer({
  16. storage: multer.diskStorage({
  17. destination: (req, file, cb) => {
  18. cb(null, importService.baseDir);
  19. },
  20. filename(req, file, cb) {
  21. // to prevent hashing the file name. files with same name will be overwritten.
  22. cb(null, file.originalname);
  23. },
  24. }),
  25. fileFilter: (req, file, cb) => {
  26. if (path.extname(file.originalname) === '.zip') {
  27. return cb(null, true);
  28. }
  29. cb(new Error('Only ".zip" is allowed'));
  30. },
  31. });
  32. /**
  33. * defined overwrite params for each collection
  34. * all imported documents are overwriten by this value
  35. * each value can be any value or a function (_value, { _document, key, schema }) { return newValue }
  36. *
  37. * @param {object} Model instance of mongoose model
  38. * @param {object} req request object
  39. * @return {object} document to be persisted
  40. */
  41. const overwriteParamsFn = async(Model, schema, req) => {
  42. const { collectionName } = Model.collection;
  43. /* eslint-disable no-case-declarations */
  44. switch (Model.collection.collectionName) {
  45. case 'pages':
  46. // TODO: use schema and req to generate overwriteParams
  47. // e.g. { creator: schema.creator === 'me' ? ObjectId(req.user._id) : importService.keepOriginal }
  48. return {
  49. status: 'published', // FIXME when importing users and user groups
  50. grant: 1, // FIXME when importing users and user groups
  51. grantedUsers: [], // FIXME when importing users and user groups
  52. grantedGroup: null, // FIXME when importing users and user groups
  53. creator: ObjectId(req.user._id), // FIXME when importing users
  54. lastUpdateUser: ObjectId(req.user._id), // FIXME when importing users
  55. liker: [], // FIXME when importing users
  56. seenUsers: [], // FIXME when importing users
  57. commentCount: 0, // FIXME when importing comments
  58. extended: {}, // FIXME when ?
  59. pageIdOnHackmd: undefined, // FIXME when importing hackmd?
  60. revisionHackmdSynced: undefined, // FIXME when importing hackmd?
  61. hasDraftOnHackmd: undefined, // FIXME when importing hackmd?
  62. };
  63. // case 'revisoins':
  64. // return {};
  65. // case 'users':
  66. // return {};
  67. // ... add more cases
  68. default:
  69. throw new Error(`cannot find a model for collection name "${collectionName}"`);
  70. }
  71. /* eslint-enable no-case-declarations */
  72. };
  73. /**
  74. * @swagger
  75. *
  76. * /import:
  77. * post:
  78. * tags: [Import]
  79. * description: import a collection from a zipped json
  80. * produces:
  81. * - application/json
  82. * responses:
  83. * 200:
  84. * description: data is successfully imported
  85. * content:
  86. * application/json:
  87. */
  88. router.post('/', async(req, res) => {
  89. // TODO: add express validator
  90. const { zipFile, schema } = req.body;
  91. // unzip
  92. await importService.unzip(zipFile);
  93. // eslint-disable-next-line no-unused-vars
  94. const { meta, files } = await importService.parseZipFile(zipFile);
  95. // TODO: validate using meta data
  96. try {
  97. await Promise.all(files.map(async({ fileName, collectionName, size }) => {
  98. const Model = importService.getModelFromCollectionName(collectionName);
  99. let overwriteParams;
  100. if (overwriteParamsFn[collectionName] != null) {
  101. // await in case overwriteParamsFn[collection] is a Promise
  102. overwriteParams = await overwriteParamsFn(Model, schema[collectionName], req);
  103. }
  104. await importService.import(Model, fileName, overwriteParams);
  105. }));
  106. // TODO: use res.apiv3
  107. return res.send({ ok: true });
  108. }
  109. catch (err) {
  110. // TODO: use ApiV3Error
  111. logger.error(err);
  112. return res.status(500).send({ status: 'ERROR' });
  113. }
  114. });
  115. router.post('/upload', uploads.single('file'), async(req, res) => {
  116. const { file } = req;
  117. const zipFile = path.join(file.destination, file.filename);
  118. try {
  119. const data = await importService.parseZipFile(zipFile);
  120. // TODO: use res.apiv3
  121. return res.send({
  122. ok: true,
  123. file: file.filename,
  124. data,
  125. });
  126. }
  127. catch (err) {
  128. // TODO: use ApiV3Error
  129. logger.error(err);
  130. return res.status(500).send({ status: 'ERROR' });
  131. }
  132. });
  133. return router;
  134. };