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

Merge pull request #5814 from weseek/feat/94400-error-handling

feat/94400 error handling
yuken 3 лет назад
Родитель
Сommit
d0b73bef87

+ 1 - 0
packages/app/resource/locales/en_US/translation.json

@@ -445,6 +445,7 @@
   "modal_empty":{
   "modal_empty":{
     "empty_the_trash": "Empty The Trash",
     "empty_the_trash": "Empty The Trash",
     "empty_the_trash_button": "Empty The Trash",
     "empty_the_trash_button": "Empty The Trash",
+    "not_deletable_notice": "Some pages cannot be removed due to lack of permission.",
     "notice": "The pages deleted completely are unrecoverable."
     "notice": "The pages deleted completely are unrecoverable."
   },
   },
   "modal_duplicate": {
   "modal_duplicate": {

+ 1 - 0
packages/app/resource/locales/ja_JP/translation.json

@@ -444,6 +444,7 @@
   "modal_empty":{
   "modal_empty":{
     "empty_the_trash": "ゴミ箱を空にする",
     "empty_the_trash": "ゴミ箱を空にする",
     "empty_the_trash_button": "空にする",
     "empty_the_trash_button": "空にする",
+    "not_deletable_notice": "権限がないため、いくつかのページは削除できません",
     "notice": "完全削除したページは元に戻すことができません"
     "notice": "完全削除したページは元に戻すことができません"
   },
   },
   "modal_duplicate": {
   "modal_duplicate": {

+ 1 - 0
packages/app/resource/locales/zh_CN/translation.json

@@ -423,6 +423,7 @@
 	"modal_empty": {
 	"modal_empty": {
 		"empty_the_trash": "清空垃圾",
 		"empty_the_trash": "清空垃圾",
     "empty_the_trash_button": "清空垃圾",
     "empty_the_trash_button": "清空垃圾",
+    "not_deletable_notice": "由于缺乏权限,一些页面不能被删除",
 		"notice": "完全删除的页面是不可恢复的。"
 		"notice": "完全删除的页面是不可恢复的。"
 	},
 	},
 	"modal_duplicate": {
 	"modal_duplicate": {

+ 4 - 1
packages/app/src/components/EmptyTrashButton.tsx

@@ -31,6 +31,8 @@ const EmptyTrashButton = () => {
     pageWithMetas = injectTo(dataWithMetas);
     pageWithMetas = injectTo(dataWithMetas);
   }
   }
 
 
+  const deletablePages = pageWithMetas.filter(page => page.meta?.isAbleToDeleteCompletely);
+
   const onEmptiedTrashHandler = useCallback(() => {
   const onEmptiedTrashHandler = useCallback(() => {
     toastSuccess(t('empty_trash'));
     toastSuccess(t('empty_trash'));
 
 
@@ -38,7 +40,8 @@ const EmptyTrashButton = () => {
   }, [t, mutate]);
   }, [t, mutate]);
 
 
   const emptyTrashClickHandler = () => {
   const emptyTrashClickHandler = () => {
-    openEmptyTrashModal(pageWithMetas, { onEmptiedTrash: onEmptiedTrashHandler });
+    if (deletablePages.length === 0) { return }
+    openEmptyTrashModal(deletablePages, { onEmptiedTrash: onEmptiedTrashHandler, canDelepeAllPages: pagingResult?.totalCount === deletablePages.length });
   };
   };
 
 
   return (
   return (

+ 3 - 0
packages/app/src/components/EmptyTrashModal.tsx

@@ -19,6 +19,8 @@ const EmptyTrashModal: FC = () => {
 
 
   const isOpened = emptyTrashModalData?.isOpened ?? false;
   const isOpened = emptyTrashModalData?.isOpened ?? false;
 
 
+  const canDeleteAllpages = emptyTrashModalData?.opts?.canDelepeAllPages ?? false;
+
   const [errs, setErrs] = useState<Error[] | null>(null);
   const [errs, setErrs] = useState<Error[] | null>(null);
 
 
   async function emptyTrash() {
   async function emptyTrash() {
@@ -68,6 +70,7 @@ const EmptyTrashModal: FC = () => {
           {/* Todo: change the way to show path on modal when too many pages are selected */}
           {/* Todo: change the way to show path on modal when too many pages are selected */}
           {renderPagePaths()}
           {renderPagePaths()}
         </div>
         </div>
+        {!canDeleteAllpages && t('modal_empty.not_deletable_notice')}<br />
         {t('modal_empty.notice')}
         {t('modal_empty.notice')}
       </ModalBody>
       </ModalBody>
       <ModalFooter>
       <ModalFooter>

+ 19 - 10
packages/app/src/server/routes/apiv3/pages.js

@@ -545,7 +545,7 @@ module.exports = (crowi) => {
    *          200:
    *          200:
    *            description: Succeeded to remove all trash pages
    *            description: Succeeded to remove all trash pages
    */
    */
-  router.delete('/empty-trash', accessTokenParser, loginRequired, adminRequired, csrf, apiV3FormValidator, async(req, res) => {
+  router.delete('/empty-trash', accessTokenParser, loginRequired, csrf, apiV3FormValidator, async(req, res) => {
     const options = {};
     const options = {};
 
 
     const pagesInTrash = await Page.findChildrenByParentPathOrIdAndViewer('/trash', req.user);
     const pagesInTrash = await Page.findChildrenByParentPathOrIdAndViewer('/trash', req.user);
@@ -557,17 +557,26 @@ module.exports = (crowi) => {
       return res.apiv3Err(new ErrorV3(msg), 500);
       return res.apiv3Err(new ErrorV3(msg), 500);
     }
     }
 
 
+    // when some pages are not deletable
     if (deletablePages.length < pagesInTrash.length) {
     if (deletablePages.length < pagesInTrash.length) {
-      const msg = 'Some pages can not be deleted.';
-      return res.apiv3Err(new ErrorV3(msg), 500);
-    }
-
-    try {
-      const pages = await crowi.pageService.emptyTrashPage(req.user, options);
-      return res.apiv3({ pages });
+      try {
+        const options = { isCompletely: true, isRecursively: true };
+        await crowi.pageService.deleteMultiplePages(deletablePages, req.user, options);
+        return res.apiv3({ deletablePages });
+      }
+      catch (err) {
+        return res.apiv3Err(new ErrorV3('Failed to update page.', 'unknown'), 500);
+      }
     }
     }
-    catch (err) {
-      return res.apiv3Err(new ErrorV3('Failed to update page.', 'unknown'), 500);
+    // when all pages are deletable
+    else {
+      try {
+        const pages = await crowi.pageService.emptyTrashPage(req.user, options);
+        return res.apiv3({ pages });
+      }
+      catch (err) {
+        return res.apiv3Err(new ErrorV3('Failed to update page.', 'unknown'), 500);
+      }
     }
     }
   });
   });
 
 

+ 1 - 0
packages/app/src/stores/modal.tsx

@@ -78,6 +78,7 @@ export const usePageDeleteModal = (status?: DeleteModalStatus): SWRResponse<Dele
 */
 */
 type IEmptyTrashModalOption = {
 type IEmptyTrashModalOption = {
   onEmptiedTrash?: () => void,
   onEmptiedTrash?: () => void,
+  canDelepeAllPages: boolean,
 }
 }
 
 
 type EmptyTrashModalStatus = {
 type EmptyTrashModalStatus = {