Просмотр исходного кода

Merge pull request #4477 from weseek/feat/77877-78636-send-three-revisions-to-client-when-conflicted

feat: send three revisions to client when conflicted
Yuki Takei 4 лет назад
Родитель
Сommit
9435d45ea5

+ 2 - 2
packages/app/src/client/services/AppContainer.js

@@ -330,9 +330,9 @@ export default class AppContainer extends Container {
       return res.data;
       return res.data;
     }
     }
 
 
-    // Return error code if code is exist
+    // Return error code and data if error code exists
     if (res.data.code != null) {
     if (res.data.code != null) {
-      const error = new Apiv1ErrorHandler(res.data.error, res.data.code);
+      const error = new Apiv1ErrorHandler(res.data.error, res.data.code, res.data.data);
       throw error;
       throw error;
     }
     }
 
 

+ 2 - 1
packages/app/src/client/util/apiv1ErrorHandler.js

@@ -1,10 +1,11 @@
 class Apiv1ErrorHandler extends Error {
 class Apiv1ErrorHandler extends Error {
 
 
-  constructor(message = '', code = '') {
+  constructor(message = '', code = '', data = '') {
     super();
     super();
 
 
     this.message = message;
     this.message = message;
     this.code = code;
     this.code = code;
+    this.data = data;
   }
   }
 
 
 }
 }

+ 3 - 0
packages/app/src/components/SavePageControls.jsx

@@ -47,6 +47,9 @@ class SavePageControls extends React.Component {
       await pageContainer.saveAndReload(editorContainer.getCurrentOptionsToSave());
       await pageContainer.saveAndReload(editorContainer.getCurrentOptionsToSave());
     }
     }
     catch (error) {
     catch (error) {
+      // TODO: display resolve conflict button when operation to update page is conflicted
+      // ref: https://estoc.weseek.co.jp/redmine/issues/78784
+      console.log(error.data);
       logger.error('failed to save', error);
       logger.error('failed to save', error);
       pageContainer.showErrorToastr(error);
       pageContainer.showErrorToastr(error);
     }
     }

+ 30 - 2
packages/app/src/server/routes/page.js

@@ -828,9 +828,38 @@ module.exports = function(crowi, app) {
     }
     }
 
 
     // check revision
     // check revision
+    const Revision = crowi.model('Revision');
     let page = await Page.findByIdAndViewer(pageId, req.user);
     let page = await Page.findByIdAndViewer(pageId, req.user);
     if (page != null && revisionId != null && !page.isUpdatable(revisionId)) {
     if (page != null && revisionId != null && !page.isUpdatable(revisionId)) {
-      return res.json(ApiResponse.error('Posted param "revisionId" is outdated.', 'outdated'));
+      const populatedFields = 'name imageUrlCached';
+      // when isUpdatable is false, originRevisionId is a reqested revisionId
+      const originRevision = await Revision.findById(revisionId).populate('author', populatedFields);
+      const latestRevision = await Revision.findById(page.revision).populate('author', populatedFields);
+
+      const revisions = {};
+
+      revisions.request = {
+        revisionID: '',
+        revisionBody: pageBody,
+        createdAt: new Date(),
+        userName: req.user.name,
+        userImgPath: req.user.imageUrlCached,
+      };
+      revisions.origin = {
+        revisionID: originRevision._id.toString(),
+        revisionBody: originRevision.body,
+        createdAt: originRevision.createdAt,
+        userName: originRevision.author.name,
+        userImgPath: originRevision.author.imageUrlCached,
+      };
+      revisions.latest = {
+        revisionID: latestRevision._id.toString(),
+        revisionBody: latestRevision.body,
+        createdAt: latestRevision.createdAt,
+        userName: latestRevision.author.name,
+        userImgPath: latestRevision.author.imageUrlCached,
+      };
+      return res.json(ApiResponse.error('Posted param "revisionId" is outdated.', 'conflict', revisions));
     }
     }
 
 
     const options = { isSyncRevisionToHackmd };
     const options = { isSyncRevisionToHackmd };
@@ -839,7 +868,6 @@ module.exports = function(crowi, app) {
       options.grantUserGroupId = grantUserGroupId;
       options.grantUserGroupId = grantUserGroupId;
     }
     }
 
 
-    const Revision = crowi.model('Revision');
     const previousRevision = await Revision.findById(revisionId);
     const previousRevision = await Revision.findById(revisionId);
     try {
     try {
       page = await Page.updatePage(page, pageBody, previousRevision.body, req.user, options);
       page = await Page.updatePage(page, pageBody, previousRevision.body, req.user, options);

+ 2 - 1
packages/app/src/server/util/apiResponse.js

@@ -1,11 +1,12 @@
 function ApiResponse() {
 function ApiResponse() {
 }
 }
 
 
-ApiResponse.error = function(err, code) {
+ApiResponse.error = function(err, code, data) {
   const result = {};
   const result = {};
 
 
   result.ok = false;
   result.ok = false;
   result.code = code;
   result.code = code;
+  result.data = data;
 
 
   if (err instanceof Error) {
   if (err instanceof Error) {
     result.error = err.toString();
     result.error = err.toString();