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

add component for bulk export settings and add donwload period configuration form

Futa Arai 1 год назад
Родитель
Сommit
ee1380f9cd

+ 6 - 3
apps/app/public/static/locales/en_US/admin.json

@@ -362,9 +362,12 @@
     "file_uploading": "File uploading",
     "enable_files_except_image": "Enabling this option will allow upload of any file type. Without this option, only image file upload is supported.",
     "attach_enable": "You can attach files other than image files if you enable this option.",
-    "enable_page_bulk_export": "Enable bulk exporting a page and it's child pages",
-    "page_bulk_export_explanation": "When enabled, users will be able to bulk export from the page menu.",
-    "page_bulk_export_warning": "The download period for exported results is 24 hours, and they will be deleted after that. During this period, running multiple large exports consecutively can fill up the file system.",
+    "page_bulk_export_settings": "Page Bulk Export Settings",
+    "enable_page_bulk_export": "Enable bulk export",
+    "page_bulk_export_execute_explanation": "Users will be able to bulk export from the page menu.",
+    "page_bulk_export_explanation": "Below are settings for exporting a page and all of its child pages. Exported results will be deleted from the file system and cannot be downloaded when the configured storage period passes.",
+    "page_bulk_export_warning": "Running multiple large exports consecutively can fill up the file system.",
+    "page_bulk_export_storage_period": "Storage period",
     "update": "Update",
     "mail_settings": "E-mail Settings",
     "mailer_is_not_set_up": "E-mail setting is not set up.",

+ 6 - 3
apps/app/public/static/locales/fr_FR/admin.json

@@ -362,9 +362,12 @@
     "file_uploading": "Téléversement de fichiers",
     "enable_files_except_image": "Autorise le téléversement de fichiers de n'importe quel type. Lorsque désactivé, seul les fichiers de type image sont autorisés.",
     "attach_enable": "Autorise le téléversement de fichiers de n'importe quel type",
-    "enable_page_bulk_export": "Autoriser l'exportation groupée de pages et de leurs pages subordonnées",
-    "page_bulk_export_explanation": "Si autorisé, l'exportation groupée sera possible à partir du menu de la page.",
-    "page_bulk_export_warning": "La période de téléchargement des résultats exportés est de 24 heures, après quoi ils seront supprimés. Pendant cette période, l’exécution consécutive de plusieurs exportations volumineuses peut remplir le système de fichiers.",
+    "page_bulk_export_settings": "Paramètres d'exportation de pages par lots",
+    "enable_page_bulk_export": "Activer l'exportation groupée",
+    "page_bulk_export_execute_explanation": "Il peut être exécuté à partir du menu des pages individuelles.",
+    "page_bulk_export_explanation": "Configurez les paramètres pour l'exportation groupée de pages et de leurs pages subordonnées. Les résultats de l'exportation seront supprimés du système de fichiers après la période de conservation définie et ne seront plus disponibles au téléchargement.",
+    "page_bulk_export_warning": "Les exportations continues comportant un grand nombre de pages peuvent surcharger le système de fichiers.",
+    "page_bulk_export_storage_period": "Date limite de téléchargement",
     "update": "Sauvegarder",
     "mail_settings": "Configuration e-mail",
     "mailer_is_not_set_up": "Paramètres e-mail non configurés.",

+ 7 - 3
apps/app/public/static/locales/ja_JP/admin.json

@@ -19,6 +19,7 @@
   "only_me": "自分のみ",
   "only_inside_the_group": "特定グループのみ",
   "optional": "オプション",
+  "days": "日",
   "security_settings": {
     "security_settings": "セキュリティ設定",
     "scope_of_page_disclosure": "ページの公開範囲",
@@ -371,9 +372,12 @@
     "file_uploading": "ファイルアップロード",
     "enable_files_except_image": "画像以外のファイルアップロードを許可",
     "attach_enable": "許可をしている場合、画像以外のファイルをページに添付可能になります。",
-    "enable_page_bulk_export": "ページとその配下のページの一括エクスポートを許可",
-    "page_bulk_export_explanation": "許可している場合、個別ページのメニューから一括エクスポートが可能になります。",
-    "page_bulk_export_warning": "エクスポート結果のダウンロード期限は24時間で、それを過ぎるとファイルシステムから削除されます。この間にページ数の多いエクスポートを連続で実行すると、ファイルシステムを圧迫する可能性があります。",
+    "page_bulk_export_settings": "ページ一括エクスポート設定",
+    "enable_page_bulk_export": "一括エクスポートを有効にする",
+    "page_bulk_export_execute_explanation": "個別ページのメニューから実行可能になります。",
+    "page_bulk_export_explanation": "ページとその配下ページの一括エクスポートの設定を行います。エクスポート結果は設定された保存期間を過ぎるとファイルシステムから削除され、ダウンロードできなくなります。",
+    "page_bulk_export_warning": "ページ数の多いエクスポートを連続で実行すると、ファイルシステムを圧迫する可能性があります。",
+    "page_bulk_export_storage_period": "保存期間",
     "update": "更新",
     "mail_settings": "メールの設定",
     "mailer_is_not_set_up": "メール設定がセットアップされていません。",

+ 6 - 3
apps/app/public/static/locales/zh_CN/admin.json

@@ -371,9 +371,12 @@
     "file_uploading": "文件上传",
     "enable_files_except_image": "启用此选项将允许上传任何文件类型。如果没有此选项,则仅支持图像文件上载。",
     "attach_enable": "如果启用此选项,则可以附加图像文件以外的文件。",
-    "enable_page_bulk_export": "允许批量导出页面及其子页面",
-    "page_bulk_export_explanation": "如果允许,可以从各个页面的菜单中批量导出。",
-    "page_bulk_export_warning": "导出结果的下载期限为24小时,下载期限过后将被删除。在此期间,连续运行多个大导出可能会填满文件系统。",
+    "page_bulk_export_settings": "页面批量导出设置",
+    "enable_page_bulk_export": "启用批量导出",
+    "page_bulk_export_execute_explanation": "用户将能够从页面菜单批量导出。",
+    "page_bulk_export_explanation": "以下是导出页面及其所有子页面的设置。当配置的存储期限过后,导出的结果将从文件系统中删除,并且无法下载。",
+    "page_bulk_export_warning": "连续运行多个大型导出可能会填满文件系统。",
+    "page_bulk_export_storage_period": "储存期限",
     "update": "更新",
     "mail_settings": "邮件设置",
     "mailer_is_not_set_up": "邮件设置尚未完成。",

+ 0 - 48
apps/app/src/client/components/Admin/App/AppSetting.jsx

@@ -170,54 +170,6 @@ const AppSetting = (props) => {
         </div>
       </div>
 
-      <div className="row mb-2">
-        <label className="text-start text-md-end col-md-3 col-form-label"></label>
-        <div className="col-md-6">
-          <div className="form-check form-check-info">
-            <input
-              type="checkbox"
-              id="cbIsPageBulkExportEnabled"
-              className="form-check-input"
-              name="isBulkExportPagesEnabled"
-              checked={adminAppContainer.state.isBulkExportPagesEnabled}
-              disabled={adminAppContainer.state.isFixedIsBulkExportPagesEnabled}
-              onChange={(e) => {
-                adminAppContainer.changeIsPageBulkExportEnabled(e.target.checked);
-              }}
-            />
-            <label
-              className="form-label form-check-label"
-              htmlFor="cbIsPageBulkExportEnabled"
-            >
-              {t('admin:app_setting.enable_page_bulk_export')}
-            </label>
-          </div>
-
-          <p className="form-text text-muted">
-            {t('admin:app_setting.page_bulk_export_explanation')}
-          </p>
-
-          <p className="alert alert-warning mt-2">
-            {t('admin:app_setting.page_bulk_export_warning')}
-          </p>
-
-          {adminAppContainer.state.isFixedIsBulkExportPagesEnabled && (
-            <p className="alert alert-warning mt-2 text-start">
-              <span className="material-symbols-outlined">help</span>
-              <b>FIXED</b><br />
-              {/* eslint-disable-next-line react/no-danger */}
-              <b dangerouslySetInnerHTML={{
-                __html: t('admin:app_setting.fixed_by_env_var', {
-                  envKey: 'BULK_EXPORT_PAGES_ENABLED',
-                  envVar: adminAppContainer.state.isBulkExportPagesEnabled,
-                }),
-              }}
-              />
-            </p>
-          )}
-        </div>
-      </div>
-
       <AdminUpdateButtonRow onClick={submitHandler} disabled={adminAppContainer.state.retrieveError != null} />
     </React.Fragment>
   );

+ 8 - 0
apps/app/src/client/components/Admin/App/AppSettingsPageContents.tsx

@@ -14,6 +14,7 @@ import AppSetting from './AppSetting';
 import FileUploadSetting from './FileUploadSetting';
 import MailSetting from './MailSetting';
 import { MaintenanceMode } from './MaintenanceMode';
+import PageBulkExportSettings from './PageBulkExportSettings';
 import QuestionnaireSettings from './QuestionnaireSettings';
 import SiteUrlSetting from './SiteUrlSetting';
 import V5PageMigration from './V5PageMigration';
@@ -108,6 +109,13 @@ const AppSettingsPageContents = (props: Props) => {
         </div>
       </div>
 
+      <div className="row mt-5">
+        <div className="col-lg-12">
+          <h2 className="admin-setting-header">{t('admin:app_setting.page_bulk_export_settings')}</h2>
+          <PageBulkExportSettings />
+        </div>
+      </div>
+
       <div className="row mt-5">
         <div className="col-lg-12">
           <h2 className="admin-setting-header">{t('admin:app_setting.questionnaire_settings')}</h2>

+ 140 - 0
apps/app/src/client/components/Admin/App/PageBulkExportSettings.tsx

@@ -0,0 +1,140 @@
+import {
+  useState, useCallback, useEffect,
+} from 'react';
+
+import { LoadingSpinner } from '@growi/ui/dist/components';
+import { useTranslation } from 'next-i18next';
+
+import { apiv3Put } from '~/client/util/apiv3-client';
+import { toastSuccess, toastError } from '~/client/util/toastr';
+import { useSWRxAppSettings } from '~/stores/admin/app-settings';
+
+import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
+
+const PageBulkExportSettings = (): JSX.Element => {
+  const { t } = useTranslation(['admin', 'commons']);
+
+  const { data, error, mutate } = useSWRxAppSettings();
+
+  const [isBulkExportPagesEnabled, setIsBulkExportPagesEnabled] = useState(data?.isBulkExportPagesEnabled);
+  const [bulkExportDownloadExpirationSeconds, setBulkExportDownloadExpirationSeconds] = useState(data?.bulkExportDownloadExpirationSeconds);
+
+  const changeBulkExportDownloadExpirationSeconds = (bulkExportDownloadExpirationDays: number) => {
+    const bulkExportDownloadExpirationSeconds = bulkExportDownloadExpirationDays * 24 * 60 * 60;
+    setBulkExportDownloadExpirationSeconds(bulkExportDownloadExpirationSeconds);
+  };
+
+  const onSubmitHandler = useCallback(async() => {
+    try {
+      await apiv3Put('/app-settings/page-bulk-export-settings', {
+        isBulkExportPagesEnabled,
+        bulkExportDownloadExpirationSeconds,
+      });
+      toastSuccess(t('commons:toaster.update_successed', { target: t('app_setting.questionnaire_settings') }));
+    }
+    catch (err) {
+      toastError(err);
+    }
+    mutate();
+  }, [isBulkExportPagesEnabled, bulkExportDownloadExpirationSeconds, mutate, t]);
+
+  useEffect(() => {
+    setIsBulkExportPagesEnabled(data?.isBulkExportPagesEnabled);
+    setBulkExportDownloadExpirationSeconds(data?.bulkExportDownloadExpirationSeconds);
+  }, [data, data?.isBulkExportPagesEnabled, data?.bulkExportDownloadExpirationSeconds]);
+
+  const isLoading = data === undefined && error === undefined;
+
+  return (
+    <>
+      {isLoading && (
+        <div className="text-muted text-center mb-5">
+          <LoadingSpinner className="me-1 fs-3" />
+        </div>
+      )}
+
+      {!isLoading && (
+        <>
+          <p className="card custom-card bg-warning-subtle my-3">
+            {t('admin:app_setting.page_bulk_export_explanation')} <br />
+            <span className="text-danger mt-1">
+              {t('admin:app_setting.page_bulk_export_warning')}
+            </span>
+          </p>
+
+          <div className="my-4 row">
+            <label
+              className="text-start text-md-end col-md-3 col-form-label"
+            >
+            </label>
+
+            <div className="col-md-6">
+              <div className="form-check form-switch form-check-info">
+                <input
+                  type="checkbox"
+                  className="form-check-input"
+                  id="cbIsPageBulkExportEnabled"
+                  checked={isBulkExportPagesEnabled}
+                  disabled={data?.isFixedIsBulkExportPagesEnabled}
+                  onChange={e => setIsBulkExportPagesEnabled(e.target.checked)}
+                />
+                <label className="form-label form-check-label" htmlFor="cbIsPageBulkExportEnabled">
+                  {t('app_setting.enable_page_bulk_export')}
+                </label>
+
+                <p className="form-text text-muted">
+                  {t('app_setting.page_bulk_export_execute_explanation')}
+                </p>
+              </div>
+            </div>
+          </div>
+
+          <div className="mb-4">
+            <div className="container">
+              <div className="row">
+                <label
+                  className="text-start text-md-end col-md-3 col-form-label"
+                >
+                  {t('app_setting.page_bulk_export_expire_time')}
+                </label>
+
+                <div className="col-md-2">
+                  <select
+                    className="form-select"
+                    value={(bulkExportDownloadExpirationSeconds ?? 0) / (24 * 60 * 60)}
+                    onChange={(e) => { changeBulkExportDownloadExpirationSeconds(Number(e.target.value)) }}
+                  >
+                    {Array.from({ length: 7 }, (_, i) => i + 1).map(number => (
+                      <option key={`be-download-expiration-option-${number}`} value={number}>
+                        {number}{t('admin:days')}
+                      </option>
+                    ))}
+                  </select>
+                </div>
+              </div>
+            </div>
+
+            {data?.isFixedIsBulkExportPagesEnabled && (
+              <p className="alert alert-warning mt-2 text-start">
+                <span className="material-symbols-outlined">help</span>
+                <b>FIXED</b><br />
+                {/* eslint-disable-next-line react/no-danger */}
+                <b dangerouslySetInnerHTML={{
+                  __html: t('admin:app_setting.fixed_by_env_var', {
+                    envKey: 'BULK_EXPORT_PAGES_ENABLED',
+                    envVar: isBulkExportPagesEnabled,
+                  }),
+                }}
+                />
+              </p>
+            )}
+          </div>
+
+          <AdminUpdateButtonRow onClick={onSubmitHandler} />
+        </>
+      )}
+    </>
+  );
+};
+
+export default PageBulkExportSettings;

+ 2 - 7
apps/app/src/client/services/AdminAppContainer.js

@@ -25,6 +25,7 @@ export default class AdminAppContainer extends Container {
       fileUpload: '',
       isBulkExportPagesEnabled: false,
       isFixedIsBulkExportPagesEnabled: false,
+      bulkExportDownloadExpirationSeconds: 86400,
 
       isV5Compatible: null,
       siteUrl: '',
@@ -103,6 +104,7 @@ export default class AdminAppContainer extends Container {
       isEmailPublishedForNewUser: appSettingsParams.isEmailPublishedForNewUser,
       fileUpload: appSettingsParams.fileUpload,
       isBulkExportPagesEnabled: appSettingsParams.isBulkExportPagesEnabled,
+      bulkExportDownloadExpirationSeconds: appSettingsParams.bulkExportDownloadExpirationSeconds,
       isV5Compatible: appSettingsParams.isV5Compatible,
       siteUrl: appSettingsParams.siteUrl,
       siteUrlUseOnlyEnvVars: appSettingsParams.siteUrlUseOnlyEnvVars,
@@ -203,13 +205,6 @@ export default class AdminAppContainer extends Container {
     this.setState({ fileUpload });
   }
 
-  /**
-   * Change isBulkExportPagesEnabled
-   */
-  changeIsPageBulkExportEnabled(isBulkExportPagesEnabled) {
-    this.setState({ isBulkExportPagesEnabled });
-  }
-
   /**
    * Change site url
    */

+ 5 - 0
apps/app/src/interfaces/res/admin/app-settings.ts

@@ -59,4 +59,9 @@ export type IResAppSettings = {
   isAppSiteUrlHashed: boolean,
 
   isMaintenanceMode: boolean,
+
+  isBulkExportPagesEnabled: boolean,
+  envIsBulkExportPagesEnabled: boolean,
+  bulkExportDownloadExpirationSeconds: number,
+  isFixedIsBulkExportPagesEnabled: boolean,
 }

+ 37 - 2
apps/app/src/server/routes/apiv3/app-settings.js

@@ -401,6 +401,10 @@ module.exports = (crowi) => {
       body('isQuestionnaireEnabled').isBoolean(),
       body('isAppSiteUrlHashed').isBoolean(),
     ],
+    pageBulkExportSettings: [
+      body('isBulkExportPagesEnabled').isBoolean(),
+      body('bulkExportDownloadExpirationSeconds').isInt(),
+    ],
     maintenanceMode: [
       body('flag').isBoolean(),
     ],
@@ -435,8 +439,6 @@ module.exports = (crowi) => {
       globalLang: crowi.configManager.getConfig('crowi', 'app:globalLang'),
       isEmailPublishedForNewUser: crowi.configManager.getConfig('crowi', 'customize:isEmailPublishedForNewUser'),
       fileUpload: crowi.configManager.getConfig('crowi', 'app:fileUpload'),
-      isBulkExportPagesEnabled: crowi.configManager.getConfig('crowi', 'app:isBulkExportPagesEnabled'),
-      envIsBulkExportPagesEnabled: crowi.configManager.getConfigFromEnvVars('crowi', 'app:isBulkExportPagesEnabled'),
       useOnlyEnvVarsForIsBulkExportPagesEnabled: crowi.configManager.getConfig('crowi', 'env:useOnlyEnvVars:app:isBulkExportPagesEnabled'),
       isV5Compatible: crowi.configManager.getConfig('crowi', 'app:isV5Compatible'),
       siteUrl: crowi.configManager.getConfig('crowi', 'app:siteUrl'),
@@ -493,6 +495,10 @@ module.exports = (crowi) => {
       isAppSiteUrlHashed: crowi.configManager.getConfig('crowi', 'questionnaire:isAppSiteUrlHashed'),
 
       isMaintenanceMode: crowi.configManager.getConfig('crowi', 'app:isMaintenanceMode'),
+
+      isBulkExportPagesEnabled: crowi.configManager.getConfig('crowi', 'app:isBulkExportPagesEnabled'),
+      envIsBulkExportPagesEnabled: crowi.configManager.getConfigFromEnvVars('crowi', 'app:isBulkExportPagesEnabled'),
+      bulkExportDownloadExpirationSeconds: crowi.configManager.getConfig('crowi', 'app:bulkExportDownloadExpirationSeconds'),
     };
     return res.apiv3({ appSettingsParams });
 
@@ -535,6 +541,7 @@ module.exports = (crowi) => {
       'customize:isEmailPublishedForNewUser': req.body.isEmailPublishedForNewUser,
       'app:fileUpload': req.body.fileUpload,
       'app:isBulkExportPagesEnabled': req.body.isBulkExportPagesEnabled,
+      'app:bulkExportDownloadExpirationSeconds': req.body.bulkExportDownloadExpirationSeconds,
     };
 
     try {
@@ -546,6 +553,7 @@ module.exports = (crowi) => {
         isEmailPublishedForNewUser: crowi.configManager.getConfig('crowi', 'customize:isEmailPublishedForNewUser'),
         fileUpload: crowi.configManager.getConfig('crowi', 'app:fileUpload'),
         isBulkExportPagesEnabled: crowi.configManager.getConfig('crowi', 'app:isBulkExportPagesEnabled'),
+        bulkExportDownloadExpirationSeconds: crowi.configManager.getConfig('crowi', 'app:bulkExportDownloadExpirationSeconds'),
       };
 
       const parameters = { action: SupportedAction.ACTION_ADMIN_APP_SETTINGS_UPDATE };
@@ -1023,6 +1031,33 @@ module.exports = (crowi) => {
 
   });
 
+  router.put('/page-bulk-export-settings', loginRequiredStrictly, adminRequired, addActivity, validator.pageBulkExportSettings, apiV3FormValidator,
+    async(req, res) => {
+      const requestParams = {
+        'app:isBulkExportPagesEnabled': req.body.isBulkExportPagesEnabled,
+        'app:bulkExportDownloadExpirationSeconds': req.body.bulkExportDownloadExpirationSeconds,
+      };
+
+      try {
+        await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams, true);
+        const responseParams = {
+          isBulkExportPagesEnabled: crowi.configManager.getConfig('crowi', 'app:isBulkExportPagesEnabled'),
+          bulkExportDownloadExpirationSeconds: crowi.configManager.getConfig('crowi', 'app:bulkExportDownloadExpirationSeconds'),
+        };
+
+        const parameters = { action: SupportedAction.ACTION_ADMIN_APP_SETTINGS_UPDATE };
+        activityEvent.emit('update', res.locals.activity._id, parameters);
+
+        return res.apiv3({ responseParams });
+      }
+      catch (err) {
+        const msg = 'Error occurred in updating page bulk export settings';
+        logger.error('Error', err);
+        return res.apiv3Err(new ErrorV3(msg, 'update-page-bulk-export-settings-failed'));
+      }
+
+    });
+
   /**
    * @swagger
    *