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

Merge pull request #9482 from weseek/feat/158980-158982-enable-changing-bulk-export-result-download-period

Feat/158980 158982 enable changing bulk export result download period
Futa Arai 1 год назад
Родитель
Сommit
61f05e88c1

+ 7 - 4
apps/app/public/static/locales/en_US/admin.json

@@ -362,9 +362,11 @@
     "file_uploading": "File uploading",
     "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.",
     "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.",
     "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_explanation": "Enables a feature that allows all users to export a page and all it's child pages at once from the menu. Exported data will be automatically deleted after the storage period has passed.",
+    "page_bulk_export_warning": "The bulk page export feature is available to all users. In order to maintain system resources, we ask for your cooperation in using the minimum amount necessary. If you are an administrator, please inform all users of this.",
+    "page_bulk_export_storage_period": "Storage period",
     "update": "Update",
     "update": "Update",
     "mail_settings": "E-mail Settings",
     "mail_settings": "E-mail Settings",
     "mailer_is_not_set_up": "E-mail setting is not set up.",
     "mailer_is_not_set_up": "E-mail setting is not set up.",
@@ -1066,7 +1068,8 @@
     "ADMIN_USER_GROUP_ADD_USER": "Add User to User Group",
     "ADMIN_USER_GROUP_ADD_USER": "Add User to User Group",
     "ADMIN_SEARCH_CONNECTION": "Attempting to reconnect to Elasticsearch",
     "ADMIN_SEARCH_CONNECTION": "Attempting to reconnect to Elasticsearch",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "Normalize of Elasticsearch indexes",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "Normalize of Elasticsearch indexes",
-    "ADMIN_SEARCH_INDICES_REBUILD": "Rebuild Elasticsearch indexes"
+    "ADMIN_SEARCH_INDICES_REBUILD": "Rebuild Elasticsearch indexes",
+    "ADMIN_PAGE_BULK_EXPORT_SETTINGS_UPDATE": "Update Page Bulk Export Settings"
   },
   },
   "g2g": {
   "g2g": {
     "transfer_success": "Completed GROWI to GROWI transfer successfully",
     "transfer_success": "Completed GROWI to GROWI transfer successfully",

+ 7 - 4
apps/app/public/static/locales/fr_FR/admin.json

@@ -362,9 +362,11 @@
     "file_uploading": "Téléversement de fichiers",
     "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.",
     "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",
     "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_explanation": "Active une fonctionnalité qui permet à tous les utilisateurs d'exporter simultanément toutes les pages sélectionnées dans le menu des pages et leurs pages subordonnées. Les données exportées seront automatiquement supprimées une fois la période de conservation écoulée.",
+    "page_bulk_export_warning": "La fonctionnalité d’exportation de pages en masse est disponible pour tous les utilisateurs. Afin de maintenir les ressources du système, nous demandons votre coopération pour utiliser le montant minimum nécessaire. Si vous êtes administrateur, veuillez en informer tous les utilisateurs.",
+    "page_bulk_export_storage_period": "Date limite de téléchargement",
     "update": "Sauvegarder",
     "update": "Sauvegarder",
     "mail_settings": "Configuration e-mail",
     "mail_settings": "Configuration e-mail",
     "mailer_is_not_set_up": "Paramètres e-mail non configurés.",
     "mailer_is_not_set_up": "Paramètres e-mail non configurés.",
@@ -1065,7 +1067,8 @@
     "ADMIN_USER_GROUP_ADD_USER": "Ajouter l'utilisateur au groupe",
     "ADMIN_USER_GROUP_ADD_USER": "Ajouter l'utilisateur au groupe",
     "ADMIN_SEARCH_CONNECTION": "Essai de reconnexion Elasticsearch",
     "ADMIN_SEARCH_CONNECTION": "Essai de reconnexion Elasticsearch",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "Nomarliser l'index Elasticsearch",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "Nomarliser l'index Elasticsearch",
-    "ADMIN_SEARCH_INDICES_REBUILD": "Reconstruire l'index Elasticsearch"
+    "ADMIN_SEARCH_INDICES_REBUILD": "Reconstruire l'index Elasticsearch",
+    "ADMIN_PAGE_BULK_EXPORT_SETTINGS_UPDATE": "Mettre à jour les paramètres d'exportation groupée de la page"
   },
   },
   "g2g": {
   "g2g": {
     "transfer_success": "Transfert de GROWI vers GROWI complété!",
     "transfer_success": "Transfert de GROWI vers GROWI complété!",

+ 8 - 4
apps/app/public/static/locales/ja_JP/admin.json

@@ -19,6 +19,7 @@
   "only_me": "自分のみ",
   "only_me": "自分のみ",
   "only_inside_the_group": "特定グループのみ",
   "only_inside_the_group": "特定グループのみ",
   "optional": "オプション",
   "optional": "オプション",
+  "days": "日",
   "security_settings": {
   "security_settings": {
     "security_settings": "セキュリティ設定",
     "security_settings": "セキュリティ設定",
     "scope_of_page_disclosure": "ページの公開範囲",
     "scope_of_page_disclosure": "ページの公開範囲",
@@ -371,9 +372,11 @@
     "file_uploading": "ファイルアップロード",
     "file_uploading": "ファイルアップロード",
     "enable_files_except_image": "画像以外のファイルアップロードを許可",
     "enable_files_except_image": "画像以外のファイルアップロードを許可",
     "attach_enable": "許可をしている場合、画像以外のファイルをページに添付可能になります。",
     "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_explanation": "すべてのユーザーが、ページメニューから選択したページとその配下ページをまとめてエクスポートできる機能を有効化します。エクスポートされたデータは保存期間経過後に自動的に削除されます。",
+    "page_bulk_export_warning": "ページ一括エクスポート機能は全ユーザーが利用可能です。システムリソースの維持のため、必要最小限の利用にご協力をお願いいたします。管理者の方は、この旨をユーザーの皆様にご周知ください。",
+    "page_bulk_export_storage_period": "保存期間",
     "update": "更新",
     "update": "更新",
     "mail_settings": "メールの設定",
     "mail_settings": "メールの設定",
     "mailer_is_not_set_up": "メール設定がセットアップされていません。",
     "mailer_is_not_set_up": "メール設定がセットアップされていません。",
@@ -1076,7 +1079,8 @@
     "ADMIN_USER_GROUP_ADD_USER": "ユーザーグループにユーザーを追加",
     "ADMIN_USER_GROUP_ADD_USER": "ユーザーグループにユーザーを追加",
     "ADMIN_SEARCH_CONNECTION": "Elasticsearch の再接続の試行",
     "ADMIN_SEARCH_CONNECTION": "Elasticsearch の再接続の試行",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "Elasticsearch のインデックスの正規化",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "Elasticsearch のインデックスの正規化",
-    "ADMIN_SEARCH_INDICES_REBUILD": "Elasticsearch のインデックスのリビルド"
+    "ADMIN_SEARCH_INDICES_REBUILD": "Elasticsearch のインデックスのリビルド",
+    "ADMIN_PAGE_BULK_EXPORT_SETTINGS_UPDATE": "ページ一括エクスポート設定の更新"
   },
   },
   "g2g": {
   "g2g": {
     "transfer_success": "G2G移行が完了しました",
     "transfer_success": "G2G移行が完了しました",

+ 7 - 4
apps/app/public/static/locales/zh_CN/admin.json

@@ -371,9 +371,11 @@
     "file_uploading": "文件上传",
     "file_uploading": "文件上传",
     "enable_files_except_image": "启用此选项将允许上传任何文件类型。如果没有此选项,则仅支持图像文件上载。",
     "enable_files_except_image": "启用此选项将允许上传任何文件类型。如果没有此选项,则仅支持图像文件上载。",
     "attach_enable": "如果启用此选项,则可以附加图像文件以外的文件。",
     "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_explanation": "启用一项功能,允许所有用户一次性导出从页面菜单中选择的所有页面及其下级页面。保留期限过后,导出的数据将自动删除。",
+    "page_bulk_export_warning": "批量页面导出功能可供所有用户使用。为了维护系统资源,请您配合使用最低限度的资源。如果您是管理员,请将此事实告知所有用户。",
+    "page_bulk_export_storage_period": "储存期限",
     "update": "更新",
     "update": "更新",
     "mail_settings": "邮件设置",
     "mail_settings": "邮件设置",
     "mailer_is_not_set_up": "邮件设置尚未完成。",
     "mailer_is_not_set_up": "邮件设置尚未完成。",
@@ -1075,7 +1077,8 @@
     "ADMIN_USER_GROUP_ADD_USER": "添加用户到用户组",
     "ADMIN_USER_GROUP_ADD_USER": "添加用户到用户组",
     "ADMIN_SEARCH_CONNECTION": "重试Elasticsearch连接",
     "ADMIN_SEARCH_CONNECTION": "重试Elasticsearch连接",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "试图重新连接Elasticsearch",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "试图重新连接Elasticsearch",
-    "ADMIN_SEARCH_INDICES_REBUILD": "重建 Elasticsearch 索引"
+    "ADMIN_SEARCH_INDICES_REBUILD": "重建 Elasticsearch 索引",
+    "ADMIN_PAGE_BULK_EXPORT_SETTINGS_UPDATE": "更新页面批量导出设置"
   },
   },
   "g2g": {
   "g2g": {
     "transfer_success": "Completed GROWI to GROWI transfer successfully",
     "transfer_success": "Completed GROWI to GROWI transfer successfully",

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

@@ -170,54 +170,6 @@ const AppSetting = (props) => {
         </div>
         </div>
       </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} />
       <AdminUpdateButtonRow onClick={submitHandler} disabled={adminAppContainer.state.retrieveError != null} />
     </React.Fragment>
     </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 FileUploadSetting from './FileUploadSetting';
 import MailSetting from './MailSetting';
 import MailSetting from './MailSetting';
 import { MaintenanceMode } from './MaintenanceMode';
 import { MaintenanceMode } from './MaintenanceMode';
+import PageBulkExportSettings from './PageBulkExportSettings';
 import QuestionnaireSettings from './QuestionnaireSettings';
 import QuestionnaireSettings from './QuestionnaireSettings';
 import SiteUrlSetting from './SiteUrlSetting';
 import SiteUrlSetting from './SiteUrlSetting';
 import V5PageMigration from './V5PageMigration';
 import V5PageMigration from './V5PageMigration';
@@ -108,6 +109,13 @@ const AppSettingsPageContents = (props: Props) => {
         </div>
         </div>
       </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="row mt-5">
         <div className="col-lg-12">
         <div className="col-lg-12">
           <h2 className="admin-setting-header">{t('admin:app_setting.questionnaire_settings')}</h2>
           <h2 className="admin-setting-header">{t('admin:app_setting.questionnaire_settings')}</h2>

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

@@ -0,0 +1,136 @@
+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(() => {
+    if (data?.useOnlyEnvVarForFileUploadType) {
+      setIsBulkExportPagesEnabled(data?.envIsBulkExportPagesEnabled);
+    }
+    else {
+      setIsBulkExportPagesEnabled(data?.isBulkExportPagesEnabled);
+    }
+    setBulkExportDownloadExpirationSeconds(data?.bulkExportDownloadExpirationSeconds);
+  }, [data]);
+
+  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?.useOnlyEnvVarsForIsBulkExportPagesEnabled}
+                  onChange={e => setIsBulkExportPagesEnabled(e.target.checked)}
+                />
+                <label className="form-label form-check-label" htmlFor="cbIsPageBulkExportEnabled">
+                  {t('app_setting.enable_page_bulk_export')}
+                </label>
+              </div>
+              {data?.useOnlyEnvVarsForIsBulkExportPagesEnabled && (
+                <p className="form-text text-muted">
+                  {/* 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>
+          </div>
+
+          <div className="mb-4">
+            <div className="row">
+              <label
+                className="text-start text-md-end col-md-3 col-form-label"
+              >
+                {t('app_setting.page_bulk_export_storage_period')}
+              </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>
+
+          <AdminUpdateButtonRow onClick={onSubmitHandler} />
+        </>
+      )}
+    </>
+  );
+};
+
+export default PageBulkExportSettings;

+ 42 - 28
apps/app/src/client/components/Admin/App/QuestionnaireSettings.tsx

@@ -72,37 +72,51 @@ const QuestionnaireSettings = (): JSX.Element => {
 
 
       {!isLoading && (
       {!isLoading && (
         <>
         <>
-          <div className="my-4">
-            <div className="form-check form-switch form-check-info">
-              <input
-                type="checkbox"
-                className="form-check-input"
-                id="isQuestionnaireEnabled"
-                checked={isQuestionnaireEnabled}
-                onChange={onChangeIsQuestionnaireEnabledHandler}
-              />
-              <label className="form-label form-check-label" htmlFor="isQuestionnaireEnabled">
-                {t('app_setting.enable_questionnaire')}
-              </label>
+          <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="isQuestionnaireEnabled"
+                  checked={isQuestionnaireEnabled}
+                  onChange={onChangeIsQuestionnaireEnabledHandler}
+                />
+                <label className="form-label form-check-label" htmlFor="isQuestionnaireEnabled">
+                  {t('app_setting.enable_questionnaire')}
+                </label>
+              </div>
             </div>
             </div>
           </div>
           </div>
 
 
-          <div className="my-4">
-            <div className="form-check form-check-info">
-              <input
-                type="checkbox"
-                className="form-check-input"
-                id="isAppSiteUrlHashed"
-                checked={isAppSiteUrlHashed}
-                onChange={onChangeisAppSiteUrlHashedHandler}
-                disabled={!isQuestionnaireEnabled}
-              />
-              <label className="form-label form-check-label" htmlFor="isAppSiteUrlHashed">
-                {t('app_setting.anonymize_app_site_url')}
-              </label>
-              <p className="form-text text-muted small">
-                {t('app_setting.url_anonymization_explanation')}
-              </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-check-info">
+                <input
+                  type="checkbox"
+                  className="form-check-input"
+                  id="isAppSiteUrlHashed"
+                  checked={isAppSiteUrlHashed}
+                  onChange={onChangeisAppSiteUrlHashedHandler}
+                  disabled={!isQuestionnaireEnabled}
+                />
+                <label className="form-label form-check-label" htmlFor="isAppSiteUrlHashed">
+                  {t('app_setting.anonymize_app_site_url')}
+                </label>
+                <p className="form-text text-muted small">
+                  {t('app_setting.url_anonymization_explanation')}
+                </p>
+              </div>
             </div>
             </div>
           </div>
           </div>
 
 

+ 0 - 17
apps/app/src/client/services/AdminAppContainer.js

@@ -23,8 +23,6 @@ export default class AdminAppContainer extends Container {
       globalLang: '',
       globalLang: '',
       isEmailPublishedForNewUser: true,
       isEmailPublishedForNewUser: true,
       fileUpload: '',
       fileUpload: '',
-      isBulkExportPagesEnabled: false,
-      isFixedIsBulkExportPagesEnabled: false,
 
 
       isV5Compatible: null,
       isV5Compatible: null,
       siteUrl: '',
       siteUrl: '',
@@ -102,7 +100,6 @@ export default class AdminAppContainer extends Container {
       globalLang: appSettingsParams.globalLang,
       globalLang: appSettingsParams.globalLang,
       isEmailPublishedForNewUser: appSettingsParams.isEmailPublishedForNewUser,
       isEmailPublishedForNewUser: appSettingsParams.isEmailPublishedForNewUser,
       fileUpload: appSettingsParams.fileUpload,
       fileUpload: appSettingsParams.fileUpload,
-      isBulkExportPagesEnabled: appSettingsParams.isBulkExportPagesEnabled,
       isV5Compatible: appSettingsParams.isV5Compatible,
       isV5Compatible: appSettingsParams.isV5Compatible,
       siteUrl: appSettingsParams.siteUrl,
       siteUrl: appSettingsParams.siteUrl,
       siteUrlUseOnlyEnvVars: appSettingsParams.siteUrlUseOnlyEnvVars,
       siteUrlUseOnlyEnvVars: appSettingsParams.siteUrlUseOnlyEnvVars,
@@ -160,12 +157,6 @@ export default class AdminAppContainer extends Container {
       this.setState({ fileUploadType: appSettingsParams.envFileUploadType });
       this.setState({ fileUploadType: appSettingsParams.envFileUploadType });
       this.setState({ isFixedFileUploadByEnvVar: true });
       this.setState({ isFixedFileUploadByEnvVar: true });
     }
     }
-
-    if (appSettingsParams.useOnlyEnvVarsForIsBulkExportPagesEnabled) {
-      this.setState({ isBulkExportPagesEnabled: appSettingsParams.envIsBulkExportPagesEnabled });
-      this.setState({ isFixedIsBulkExportPagesEnabled: true });
-    }
-
   }
   }
 
 
   /**
   /**
@@ -203,13 +194,6 @@ export default class AdminAppContainer extends Container {
     this.setState({ fileUpload });
     this.setState({ fileUpload });
   }
   }
 
 
-  /**
-   * Change isBulkExportPagesEnabled
-   */
-  changeIsPageBulkExportEnabled(isBulkExportPagesEnabled) {
-    this.setState({ isBulkExportPagesEnabled });
-  }
-
   /**
   /**
    * Change site url
    * Change site url
    */
    */
@@ -412,7 +396,6 @@ export default class AdminAppContainer extends Container {
       globalLang: this.state.globalLang,
       globalLang: this.state.globalLang,
       isEmailPublishedForNewUser: this.state.isEmailPublishedForNewUser,
       isEmailPublishedForNewUser: this.state.isEmailPublishedForNewUser,
       fileUpload: this.state.fileUpload,
       fileUpload: this.state.fileUpload,
-      isBulkExportPagesEnabled: this.state.isBulkExportPagesEnabled,
     });
     });
     const { appSettingParams } = response.data;
     const { appSettingParams } = response.data;
     return appSettingParams;
     return appSettingParams;

+ 3 - 0
apps/app/src/interfaces/activity.ts

@@ -79,6 +79,7 @@ const ACTION_ADMIN_MAIL_SES_UPDATE = 'ADMIN_MAIL_SES_UPDATE';
 const ACTION_ADMIN_MAIL_TEST_SUBMIT = 'ADMIN_MAIL_TEST_SUBMIT';
 const ACTION_ADMIN_MAIL_TEST_SUBMIT = 'ADMIN_MAIL_TEST_SUBMIT';
 const ACTION_ADMIN_FILE_UPLOAD_CONFIG_UPDATE = 'ADMIN_FILE_UPLOAD_CONFIG_UPDATE';
 const ACTION_ADMIN_FILE_UPLOAD_CONFIG_UPDATE = 'ADMIN_FILE_UPLOAD_CONFIG_UPDATE';
 const ACTION_ADMIN_QUESTIONNAIRE_SETTINGS_UPDATE = 'ACTION_ADMIN_QUESTIONNAIRE_SETTINGS_UPDATE';
 const ACTION_ADMIN_QUESTIONNAIRE_SETTINGS_UPDATE = 'ACTION_ADMIN_QUESTIONNAIRE_SETTINGS_UPDATE';
+const ACTION_ADMIN_PAGE_BULK_EXPORT_SETTINGS_UPDATE = 'ADMIN_PAGE_BULK_EXPORT_SETTINGS_UPDATE';
 const ACTION_ADMIN_MAINTENANCEMODE_ENABLED = 'ADMIN_MAINTENANCEMODE_ENABLED';
 const ACTION_ADMIN_MAINTENANCEMODE_ENABLED = 'ADMIN_MAINTENANCEMODE_ENABLED';
 const ACTION_ADMIN_MAINTENANCEMODE_DISABLED = 'ADMIN_MAINTENANCEMODE_DISABLED';
 const ACTION_ADMIN_MAINTENANCEMODE_DISABLED = 'ADMIN_MAINTENANCEMODE_DISABLED';
 const ACTION_ADMIN_SECURITY_SETTINGS_UPDATE = 'ADMIN_SECURITY_SETTINGS_UPDATE';
 const ACTION_ADMIN_SECURITY_SETTINGS_UPDATE = 'ADMIN_SECURITY_SETTINGS_UPDATE';
@@ -259,6 +260,7 @@ export const SupportedAction = {
   ACTION_ADMIN_MAIL_TEST_SUBMIT,
   ACTION_ADMIN_MAIL_TEST_SUBMIT,
   ACTION_ADMIN_FILE_UPLOAD_CONFIG_UPDATE,
   ACTION_ADMIN_FILE_UPLOAD_CONFIG_UPDATE,
   ACTION_ADMIN_QUESTIONNAIRE_SETTINGS_UPDATE,
   ACTION_ADMIN_QUESTIONNAIRE_SETTINGS_UPDATE,
+  ACTION_ADMIN_PAGE_BULK_EXPORT_SETTINGS_UPDATE,
   ACTION_ADMIN_MAINTENANCEMODE_ENABLED,
   ACTION_ADMIN_MAINTENANCEMODE_ENABLED,
   ACTION_ADMIN_MAINTENANCEMODE_DISABLED,
   ACTION_ADMIN_MAINTENANCEMODE_DISABLED,
   ACTION_ADMIN_SECURITY_SETTINGS_UPDATE,
   ACTION_ADMIN_SECURITY_SETTINGS_UPDATE,
@@ -452,6 +454,7 @@ export const LargeActionGroup = {
   ACTION_ADMIN_MAIL_TEST_SUBMIT,
   ACTION_ADMIN_MAIL_TEST_SUBMIT,
   ACTION_ADMIN_FILE_UPLOAD_CONFIG_UPDATE,
   ACTION_ADMIN_FILE_UPLOAD_CONFIG_UPDATE,
   ACTION_ADMIN_QUESTIONNAIRE_SETTINGS_UPDATE,
   ACTION_ADMIN_QUESTIONNAIRE_SETTINGS_UPDATE,
+  ACTION_ADMIN_PAGE_BULK_EXPORT_SETTINGS_UPDATE,
   ACTION_ADMIN_MAINTENANCEMODE_ENABLED,
   ACTION_ADMIN_MAINTENANCEMODE_ENABLED,
   ACTION_ADMIN_MAINTENANCEMODE_DISABLED,
   ACTION_ADMIN_MAINTENANCEMODE_DISABLED,
   ACTION_ADMIN_SECURITY_SETTINGS_UPDATE,
   ACTION_ADMIN_SECURITY_SETTINGS_UPDATE,

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

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

+ 35 - 4
apps/app/src/server/routes/apiv3/app-settings.js

@@ -401,6 +401,10 @@ module.exports = (crowi) => {
       body('isQuestionnaireEnabled').isBoolean(),
       body('isQuestionnaireEnabled').isBoolean(),
       body('isAppSiteUrlHashed').isBoolean(),
       body('isAppSiteUrlHashed').isBoolean(),
     ],
     ],
+    pageBulkExportSettings: [
+      body('isBulkExportPagesEnabled').isBoolean(),
+      body('bulkExportDownloadExpirationSeconds').isInt(),
+    ],
     maintenanceMode: [
     maintenanceMode: [
       body('flag').isBoolean(),
       body('flag').isBoolean(),
     ],
     ],
@@ -435,8 +439,6 @@ module.exports = (crowi) => {
       globalLang: crowi.configManager.getConfig('crowi', 'app:globalLang'),
       globalLang: crowi.configManager.getConfig('crowi', 'app:globalLang'),
       isEmailPublishedForNewUser: crowi.configManager.getConfig('crowi', 'customize:isEmailPublishedForNewUser'),
       isEmailPublishedForNewUser: crowi.configManager.getConfig('crowi', 'customize:isEmailPublishedForNewUser'),
       fileUpload: crowi.configManager.getConfig('crowi', 'app:fileUpload'),
       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'),
       useOnlyEnvVarsForIsBulkExportPagesEnabled: crowi.configManager.getConfig('crowi', 'env:useOnlyEnvVars:app:isBulkExportPagesEnabled'),
       isV5Compatible: crowi.configManager.getConfig('crowi', 'app:isV5Compatible'),
       isV5Compatible: crowi.configManager.getConfig('crowi', 'app:isV5Compatible'),
       siteUrl: crowi.configManager.getConfig('crowi', 'app:siteUrl'),
       siteUrl: crowi.configManager.getConfig('crowi', 'app:siteUrl'),
@@ -493,6 +495,10 @@ module.exports = (crowi) => {
       isAppSiteUrlHashed: crowi.configManager.getConfig('crowi', 'questionnaire:isAppSiteUrlHashed'),
       isAppSiteUrlHashed: crowi.configManager.getConfig('crowi', 'questionnaire:isAppSiteUrlHashed'),
 
 
       isMaintenanceMode: crowi.configManager.getConfig('crowi', 'app:isMaintenanceMode'),
       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 });
     return res.apiv3({ appSettingsParams });
 
 
@@ -534,7 +540,6 @@ module.exports = (crowi) => {
       'app:globalLang': req.body.globalLang,
       'app:globalLang': req.body.globalLang,
       'customize:isEmailPublishedForNewUser': req.body.isEmailPublishedForNewUser,
       'customize:isEmailPublishedForNewUser': req.body.isEmailPublishedForNewUser,
       'app:fileUpload': req.body.fileUpload,
       'app:fileUpload': req.body.fileUpload,
-      'app:isBulkExportPagesEnabled': req.body.isBulkExportPagesEnabled,
     };
     };
 
 
     try {
     try {
@@ -545,7 +550,6 @@ module.exports = (crowi) => {
         globalLang: crowi.configManager.getConfig('crowi', 'app:globalLang'),
         globalLang: crowi.configManager.getConfig('crowi', 'app:globalLang'),
         isEmailPublishedForNewUser: crowi.configManager.getConfig('crowi', 'customize:isEmailPublishedForNewUser'),
         isEmailPublishedForNewUser: crowi.configManager.getConfig('crowi', 'customize:isEmailPublishedForNewUser'),
         fileUpload: crowi.configManager.getConfig('crowi', 'app:fileUpload'),
         fileUpload: crowi.configManager.getConfig('crowi', 'app:fileUpload'),
-        isBulkExportPagesEnabled: crowi.configManager.getConfig('crowi', 'app:isBulkExportPagesEnabled'),
       };
       };
 
 
       const parameters = { action: SupportedAction.ACTION_ADMIN_APP_SETTINGS_UPDATE };
       const parameters = { action: SupportedAction.ACTION_ADMIN_APP_SETTINGS_UPDATE };
@@ -1023,6 +1027,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
    * @swagger
    *
    *

+ 1 - 1
apps/app/src/server/service/config-loader.ts

@@ -761,7 +761,7 @@ const ENV_VAR_NAME_TO_CONFIG_INFO: Record<string, EnvConfig> = {
     ns: 'crowi',
     ns: 'crowi',
     key: 'app:bulkExportDownloadExpirationSeconds',
     key: 'app:bulkExportDownloadExpirationSeconds',
     type: ValueType.NUMBER,
     type: ValueType.NUMBER,
-    default: 86400, // 1 day
+    default: 259200, // 3 days
   },
   },
   BULK_EXPORT_JOB_CRON_SCHEDULE: {
   BULK_EXPORT_JOB_CRON_SCHEDULE: {
     ns: 'crowi',
     ns: 'crowi',