Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imprv/149843 152624 disable bulk export when fs not s3 or gcs #9033

1 change: 1 addition & 0 deletions apps/app/public/static/locales/en_US/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@
"bulk_export_started": "Please wait a moment...",
"bulk_export_download_expired": "Download period has expired",
"bulk_export_job_expired": "Export process was canceled because it took too long",
"bulk_export_only_available_for": "Only available for AWS or GCP",
"export_in_progress": "Export in progress",
"export_in_progress_explanation": "Export with the same format is already in progress. Would you like to restart to export the latest page contents?",
"export_cancel_warning": "The export in progress will be canceled",
Expand Down
1 change: 1 addition & 0 deletions apps/app/public/static/locales/fr_FR/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@
"bulk_export_started": "Patientez s'il-vous-plait...",
"bulk_export_download_expired": "La période de téléchargement a expiré",
"bulk_export_job_expired": "Le traitement a été interrompu car le temps d'exportation était trop long",
"bulk_export_only_available_for": "Uniquement disponible pour AWS ou GCP",
"export_in_progress": "Exportation en cours",
"export_in_progress_explanation": "L'exportation avec le même format est déjà en cours. Souhaitez-vous redémarrer pour exporter le dernier contenu de la page ?",
"export_cancel_warning": "L'export en cours sera annulé",
Expand Down
1 change: 1 addition & 0 deletions apps/app/public/static/locales/ja_JP/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,7 @@
"bulk_export_started": "ただいま準備中です...",
"bulk_export_download_expired": "ダウンロード期限が切れました",
"bulk_export_job_expired": "エクスポート時間が長すぎるため、処理が中断されました",
"bulk_export_only_available_for": "AWS と GCP のみ対応しています",
"export_in_progress": "エクスポート進行中",
"export_in_progress_explanation": "既に同じ形式でのエクスポートが進行中です。最新のページ内容でエクスポートを最初からやり直しますか?",
"export_cancel_warning": "進行中のエクスポートはキャンセルされます",
Expand Down
1 change: 1 addition & 0 deletions apps/app/public/static/locales/zh_CN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,7 @@
"bulk_export_started": "目前我们正在准备...",
"bulk_export_download_expired": "下载期限已过",
"bulk_export_job_expired": "由于导出时间太长,处理被中断",
"bulk_export_only_available_for": "仅适用于 AWS 或 GCP",
"export_in_progress": "导出正在进行中",
"export_in_progress_explanation": "已在进行相同格式的导出。您要重新启动以导出最新的页面内容吗?",
"export_cancel_warning": "正在进行的导出将被取消",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useTranslation } from 'next-i18next';

import AdminAppContainer from '~/client/services/AdminAppContainer';
import { toastSuccess, toastError } from '~/client/util/toastr';
import { FileUploadType } from '~/interfaces/file-uploader';

import { withUnstatedContainers } from '../../UnstatedUtils';
import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
Expand All @@ -16,9 +17,6 @@ import type { AzureSettingMoleculeProps } from './AzureSetting';
import { GcsSettingMolecule } from './GcsSetting';
import type { GcsSettingMoleculeProps } from './GcsSetting';


const fileUploadTypes = ['aws', 'gcs', 'azure', 'gridfs', 'local'] as const;

type FileUploadSettingMoleculeProps = {
fileUploadType: string
isFixedFileUploadByEnvVar: boolean
Expand All @@ -45,7 +43,7 @@ export const FileUploadSettingMolecule = React.memo((props: FileUploadSettingMol
</label>

<div className="col-md-6 py-2">
{fileUploadTypes.map((type) => {
{Object.values(FileUploadType).map((type) => {
return (
<div key={type} className="form-check form-check-inline">
<input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import dynamic from 'next/dynamic';
import Link from 'next/link';
import { useRouter } from 'next/router';
import Sticky from 'react-stickynode';
import { DropdownItem, UncontrolledTooltip } from 'reactstrap';
import { Tooltip, DropdownItem, UncontrolledTooltip } from 'reactstrap';

import { exportAsMarkdown, updateContentWidth, syncLatestRevisionBody } from '~/client/services/page-operation';
import { toastSuccess, toastError, toastWarning } from '~/client/util/toastr';
Expand All @@ -25,7 +25,7 @@ import type { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from
import { useShouldExpandContent } from '~/services/layout/use-should-expand-content';
import {
useCurrentPathname,
useCurrentUser, useIsGuestUser, useIsReadOnlyUser, useIsLocalAccountRegistrationEnabled, useIsSharedUser, useShareLinkId,
useCurrentUser, useIsGuestUser, useIsReadOnlyUser, useIsPageBulkExportEnabled, useIsLocalAccountRegistrationEnabled, useIsSharedUser, useShareLinkId,
} from '~/stores-universal/context';
import { useEditorMode } from '~/stores-universal/ui';
import {
Expand Down Expand Up @@ -77,13 +77,16 @@ const PageOperationMenuItems = (props: PageOperationMenuItemsProps): JSX.Element
const { data: isGuestUser } = useIsGuestUser();
const { data: isReadOnlyUser } = useIsReadOnlyUser();
const { data: isSharedUser } = useIsSharedUser();
const { data: isPageBulkExportEnabled } = useIsPageBulkExportEnabled();

const { open: openPresentationModal } = usePagePresentationModal();
const { open: openAccessoriesModal } = usePageAccessoriesModal();
const { open: openPageBulkExportSelectModal } = usePageBulkExportSelectModal();

const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);

const [isBulkExportTooltipOpen, setIsBulkExportTooltipOpen] = useState(false);

const syncLatestRevisionBodyHandler = useCallback(async() => {
// eslint-disable-next-line no-alert
const answer = window.confirm(t('sync-latest-revision-body.confirm'));
Expand Down Expand Up @@ -141,13 +144,25 @@ const PageOperationMenuItems = (props: PageOperationMenuItemsProps): JSX.Element
</DropdownItem>

{/* Bulk export */}
<DropdownItem
onClick={openPageBulkExportSelectModal}
className="grw-page-control-dropdown-item"
<span id="bulkExportDropdownItem">
<DropdownItem
disabled={!isPageBulkExportEnabled}
onClick={openPageBulkExportSelectModal}
className="grw-page-control-dropdown-item"
>
<span className="material-symbols-outlined me-1 grw-page-control-dropdown-icon">cloud_download</span>
{t('page_export.bulk_export')}
</DropdownItem>
</span>
<Tooltip
placement="left"
isOpen={isBulkExportTooltipOpen}
// Tooltip cannot be activated when target is disabled so set the target to wrapper span
target="bulkExportDropdownItem"
toggle={() => setIsBulkExportTooltipOpen(!isBulkExportTooltipOpen)}
>
<span className="material-symbols-outlined me-1 grw-page-control-dropdown-icon">cloud_download</span>
{t('page_export.bulk_export')}
</DropdownItem>
{t('page_export.bulk_export_only_available_for')}
</Tooltip>

<DropdownItem divider />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type {
IAttachment, IPage, IRevision, IUser, Ref,
} from '@growi/core';

import { FileUploadTypeForEnvVar } from '~/interfaces/file-uploader';

export const PageBulkExportFormat = {
md: 'md',
pdf: 'pdf',
Expand Down Expand Up @@ -45,3 +47,5 @@ export interface IPageBulkExportPageSnapshot {
path: string, // page path when export was stared
revision: Ref<IRevision>, // page revision when export was stared
}

export const PageBulkExportEnabledFileUploadTypes = [FileUploadTypeForEnvVar.aws, FileUploadTypeForEnvVar.gcs, FileUploadTypeForEnvVar.gcp] as const;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { configManager } from '~/server/service/config-manager';
import CronService from '~/server/service/cron';
import loggerFactory from '~/utils/logger';

import { PageBulkExportJobInProgressStatus, PageBulkExportJobStatus } from '../../interfaces/page-bulk-export';
import { PageBulkExportEnabledFileUploadTypes, PageBulkExportJobInProgressStatus, PageBulkExportJobStatus } from '../../interfaces/page-bulk-export';
import type { PageBulkExportJobDocument } from '../models/page-bulk-export-job';
import PageBulkExportJob from '../models/page-bulk-export-job';

Expand All @@ -29,6 +29,9 @@ class PageBulkExportJobCronService extends CronService {
}

override async executeJob(): Promise<void> {
const isPageBulkExportEnabled = PageBulkExportEnabledFileUploadTypes.includes(configManager.getConfig('crowi', 'app:fileUploadType'));
if (!isPageBulkExportEnabled) return;

await this.deleteExpiredExportJobs();
await this.deleteDownloadExpiredExportJobs();
await this.deleteFailedExportJobs();
Expand Down
20 changes: 20 additions & 0 deletions apps/app/src/interfaces/file-uploader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// file upload types actually supported by the app
export const FileUploadType = {
aws: 'aws',
gcs: 'gcs',
azure: 'azure',
gridfs: 'gridfs',
local: 'local',
} as const;

export type FileUploadType = typeof FileUploadType[keyof typeof FileUploadType]

// file upload type strings you can specify in the env var
export const FileUploadTypeForEnvVar = {
...FileUploadType,
mongo: 'mongo',
mongodb: 'mongodb',
gcp: 'gcp',
} as const;

export type FileUploadTypeForEnvVar = typeof FileUploadTypeForEnvVar[keyof typeof FileUploadTypeForEnvVar]
6 changes: 5 additions & 1 deletion apps/app/src/pages/[[...path]].page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import superjson from 'superjson';
import { BasicLayout } from '~/components/Layout/BasicLayout';
import { PageView } from '~/components/PageView/PageView';
import { DrawioViewerScript } from '~/components/Script/DrawioViewerScript';
import { PageBulkExportEnabledFileUploadTypes } from '~/features/page-bulk-export/interfaces/page-bulk-export';
import { SupportedAction, type SupportedActionType } from '~/interfaces/activity';
import type { CrowiRequest } from '~/interfaces/crowi-request';
import { RegistrationMode } from '~/interfaces/registration-mode';
Expand All @@ -42,7 +43,7 @@ import {
useCsrfToken, useIsSearchScopeChildrenAsDefault, useIsEnabledMarp, useCurrentPathname,
useIsSlackConfigured, useRendererConfig, useGrowiCloudUri,
useIsAllReplyShown, useIsContainerFluid, useIsNotCreatable,
useIsUploadAllFileAllowed, useIsUploadEnabled,
useIsUploadAllFileAllowed, useIsUploadEnabled, useIsPageBulkExportEnabled,
useElasticsearchMaxBodyLengthToIndex,
useIsLocalAccountRegistrationEnabled,
} from '~/stores-universal/context';
Expand Down Expand Up @@ -177,6 +178,7 @@ type Props = CommonProps & {
isContainerFluid: boolean,
isUploadEnabled: boolean,
isUploadAllFileAllowed: boolean,
isPageBulkExportEnabled: boolean,
isEnabledStaleNotification: boolean,
isEnabledAttachTitleHeader: boolean,
// isEnabledLinebreaks: boolean,
Expand Down Expand Up @@ -239,6 +241,7 @@ const Page: NextPageWithLayout<Props> = (props: Props) => {

useIsUploadAllFileAllowed(props.isUploadAllFileAllowed);
useIsUploadEnabled(props.isUploadEnabled);
useIsPageBulkExportEnabled(props.isPageBulkExportEnabled);

useIsLocalAccountRegistrationEnabled(props.isLocalAccountRegistrationEnabled);

Expand Down Expand Up @@ -560,6 +563,7 @@ function injectServerConfigurations(context: GetServerSidePropsContext, props: P
props.disableLinkSharing = configManager.getConfig('crowi', 'security:disableLinkSharing');
props.isUploadAllFileAllowed = crowi.fileUploadService.getFileUploadEnabled();
props.isUploadEnabled = crowi.fileUploadService.getIsUploadable();
props.isPageBulkExportEnabled = PageBulkExportEnabledFileUploadTypes.includes(configManager.getConfig('crowi', 'app:fileUploadType'));

props.isLocalAccountRegistrationEnabled = crowi.passportService.isLocalStrategySetup
&& configManager.getConfig('crowi', 'security:registrationMode') !== RegistrationMode.CLOSED;
Expand Down
1 change: 0 additions & 1 deletion apps/app/src/server/routes/apiv3/app-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,6 @@ module.exports = (crowi) => {

});


/**
* @swagger
*
Expand Down
9 changes: 3 additions & 6 deletions apps/app/src/server/service/file-uploader/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FileUploadTypeForEnvVar } from '~/interfaces/file-uploader';
import type Crowi from '~/server/crowi';
import loggerFactory from '~/utils/logger';

Expand All @@ -10,15 +11,11 @@ export type { FileUploader } from './file-uploader';
const logger = loggerFactory('growi:service:FileUploaderServise');

const envToModuleMappings = {
aws: 'aws',
local: 'local',
...FileUploadTypeForEnvVar,
mongo: 'gridfs',
mongodb: 'gridfs',
gridfs: 'gridfs',
gcp: 'gcs',
gcs: 'gcs',
azure: 'azure',
};
} as const;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これらエイリアス相当も src/interfaces/file-uploader.ts に移した方が見通しがよさそう


export const getUploader = (crowi: Crowi): FileUploader => {
const method = envToModuleMappings[configManager.getConfig('crowi', 'app:fileUploadType')];
Expand Down
4 changes: 4 additions & 0 deletions apps/app/src/stores-universal/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ export const useIsUploadAllFileAllowed = (initialData?: boolean): SWRResponse<bo
return useContextSWR('isUploadAllFileAllowed', initialData);
};

export const useIsPageBulkExportEnabled = (initialData?: boolean): SWRResponse<boolean, Error> => {
return useContextSWR('isPageBulkExportEnabled', initialData);
};

export const useShowPageLimitationL = (initialData?: number): SWRResponse<number, Error> => {
return useContextSWR('showPageLimitationL', initialData);
};
Expand Down
Loading