Skip to content

Commit

Permalink
Merge pull request #8963 from weseek/feat/78040-135788-resume-suspend…
Browse files Browse the repository at this point in the history
…ed-bulk-export-job

Feat/78040 135788 resume suspended bulk export job
  • Loading branch information
yuki-takei authored Aug 13, 2024
2 parents a9680d5 + f46858f commit 2591f22
Show file tree
Hide file tree
Showing 18 changed files with 297 additions and 144 deletions.
3 changes: 2 additions & 1 deletion apps/app/public/static/locales/en_US/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,8 @@
"markdown": "Markdown",
"choose_export_format": "Select export format",
"bulk_export_started": "Please wait a moment...",
"bulk_export_download_expired": "Download period has expired"
"bulk_export_download_expired": "Download period has expired",
"duplicate_bulk_export_job_error": "Export for the same page and its children is in progress"
},
"message": {
"successfully_connected": "Successfully Connected!",
Expand Down
3 changes: 2 additions & 1 deletion apps/app/public/static/locales/fr_FR/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,8 @@
"markdown": "Markdown",
"choose_export_format": "Sélectionnez le format d'exportation",
"bulk_export_started": "Patientez s'il-vous-plait...",
"bulk_export_download_expired": "La période de téléchargement a expiré"
"bulk_export_download_expired": "La période de téléchargement a expiré",
"duplicate_bulk_export_job_error": "L'export pour la même page et ses enfants est en cours"
},
"message": {
"successfully_connected": "Connecté!",
Expand Down
3 changes: 2 additions & 1 deletion apps/app/public/static/locales/ja_JP/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,8 @@
"markdown": "マークダウン",
"choose_export_format": "エクスポート形式を選択してください",
"bulk_export_started": "ただいま準備中です...",
"bulk_export_download_expired": "ダウンロード期限が切れました"
"bulk_export_download_expired": "ダウンロード期限が切れました",
"duplicate_bulk_export_job_error": "既に同じページとその配下のエクスポートが進行中です"
},
"message": {
"successfully_connected": "接続に成功しました!",
Expand Down
3 changes: 2 additions & 1 deletion apps/app/public/static/locales/zh_CN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,8 @@
"markdown": "Markdown",
"choose_export_format": "选择导出格式",
"bulk_export_started": "目前我们正在准备...",
"bulk_export_download_expired": "下载期限已过"
"bulk_export_download_expired": "下载期限已过",
"duplicate_bulk_export_job_error": "正在导出同一页面及其子页面"
},
"message": {
"successfully_connected": "连接成功!",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ const PageBulkExportSelectModal = (): JSX.Element => {
toastSuccess(t('page_export.bulk_export_started'));
}
catch (e) {
toastError(t('page_export.failed_to_export'));
// TODO: Enable cancel and restart of export if duplicate export exists (https://redmine.weseek.co.jp/issues/150418)
const errorCode = e?.[0].code ?? 'page_export.failed_to_export';
toastError(t(errorCode));
}
close();
};
Expand All @@ -38,7 +40,7 @@ const PageBulkExportSelectModal = (): JSX.Element => {
</small>
</div>
<div className="d-flex justify-content-center mt-2">
<button className="btn btn-primary" type="button" onClick={() => startBulkExport(PageBulkExportFormat.markdown)}>
<button className="btn btn-primary" type="button" onClick={() => startBulkExport(PageBulkExportFormat.md)}>
{t('page_export.markdown')}
</button>
<button className="btn btn-primary ms-2" type="button" onClick={() => startBulkExport(PageBulkExportFormat.pdf)}>PDF</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,38 @@ import type {
} from '@growi/core';

export const PageBulkExportFormat = {
markdown: 'markdown',
md: 'md',
pdf: 'pdf',
} as const;

export type PageBulkExportFormat = typeof PageBulkExportFormat[keyof typeof PageBulkExportFormat]

export const PageBulkExportJobStatus = {
initializing: 'initializing', // preparing for export
exporting: 'exporting', // exporting to fs
uploading: 'uploading', // uploading to cloud storage
completed: 'completed',
failed: 'failed',
} as const;

export type PageBulkExportJobStatus = typeof PageBulkExportJobStatus[keyof typeof PageBulkExportJobStatus]

export interface IPageBulkExportJob {
user: Ref<IUser>, // user that started export job
page: Ref<IPage>, // the root page of page tree to export
lastUploadedPagePath: string, // the path of page that was uploaded last
uploadId: string | null, // upload ID of multipart upload of S3/GCS
lastExportedPagePath?: string, // the path of page that was exported to the fs last
uploadId?: string, // upload ID of multipart upload of S3/GCS
uploadKey?: string, // upload key of multipart upload of S3/GCS
format: PageBulkExportFormat,
completedAt: Date | null, // the date at which job was completed
completedAt?: Date, // the date at which job was completed
attachment?: Ref<IAttachment>,
status: PageBulkExportJobStatus,
}

export interface IPageBulkExportJobHasId extends IPageBulkExportJob, HasObjectId {}

// snapshot of page info to upload
export interface IPageBulkExportPageInfo {
export interface IPageBulkExportPageSnapshot {
pageBulkExportJob: Ref<IPageBulkExportJob>,
path: string, // page path when export was stared
revision: Ref<IRevision>, // page revision when export was stared
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { type Document, type Model, Schema } from 'mongoose';
import { getOrCreateModel } from '~/server/util/mongoose-utils';

import type { IPageBulkExportJob } from '../../interfaces/page-bulk-export';
import { PageBulkExportFormat } from '../../interfaces/page-bulk-export';
import { PageBulkExportFormat, PageBulkExportJobStatus } from '../../interfaces/page-bulk-export';

export interface PageBulkExportJobDocument extends IPageBulkExportJob, Document {}

Expand All @@ -12,11 +12,15 @@ export type PageBulkExportJobModel = Model<PageBulkExportJobDocument>
const pageBulkExportJobSchema = new Schema<PageBulkExportJobDocument>({
user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
page: { type: Schema.Types.ObjectId, ref: 'Page', required: true },
lastUploadedPagePath: { type: String },
lastExportedPagePath: { type: String },
uploadId: { type: String, unique: true, sparse: true },
uploadKey: { type: String, unique: true, sparse: true },
format: { type: String, enum: Object.values(PageBulkExportFormat), required: true },
completedAt: { type: Date },
attachment: { type: Schema.Types.ObjectId, ref: 'Attachment' },
status: {
type: String, enum: Object.values(PageBulkExportJobStatus), required: true, default: PageBulkExportJobStatus.initializing,
},
}, { timestamps: true });

export default getOrCreateModel<PageBulkExportJobDocument, PageBulkExportJobModel>('PageBulkExportJob', pageBulkExportJobSchema);

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { type Document, type Model, Schema } from 'mongoose';

import { getOrCreateModel } from '~/server/util/mongoose-utils';

import type { IPageBulkExportPageSnapshot } from '../../interfaces/page-bulk-export';

export interface PageBulkExportPageSnapshotDocument extends IPageBulkExportPageSnapshot, Document {}

export type PageBulkExportPageSnapshotModel = Model<PageBulkExportPageSnapshotDocument>

const pageBulkExportPageInfoSchema = new Schema<PageBulkExportPageSnapshotDocument>({
pageBulkExportJob: { type: Schema.Types.ObjectId, ref: 'PageBulkExportJob', required: true },
path: { type: String, required: true },
revision: { type: Schema.Types.ObjectId, ref: 'Revision', required: true },
}, { timestamps: true });

export default getOrCreateModel<PageBulkExportPageSnapshotDocument, PageBulkExportPageSnapshotModel>(
'PageBulkExportPageSnapshot', pageBulkExportPageInfoSchema,
);
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type Crowi from '~/server/crowi';
import type { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';
import loggerFactory from '~/utils/logger';

import { pageBulkExportService } from '../../service/page-bulk-export';
import { DuplicateBulkExportJobError, pageBulkExportService } from '../../service/page-bulk-export';

const logger = loggerFactory('growi:routes:apiv3:page-bulk-export');

Expand Down Expand Up @@ -40,12 +40,15 @@ module.exports = (crowi: Crowi): Router => {
};

try {
await pageBulkExportService?.createAndStartPageBulkExportJob(path, req.user, activityParameters);
await pageBulkExportService?.createAndExecuteBulkExportJob(path, req.user, activityParameters);
return res.apiv3({}, 204);
}
catch (err) {
logger.error(err);
return res.apiv3Err(new ErrorV3('Failed to start bulk export'));
if (err instanceof DuplicateBulkExportJobError) {
return res.apiv3Err(new ErrorV3('Duplicate bulk export job is in progress', 'page_export.duplicate_bulk_export_job_error'), 409);
}
return res.apiv3Err(new ErrorV3('Failed to start bulk export', 'page_export.failed_to_export'));
}
});

Expand Down
Loading

0 comments on commit 2591f22

Please sign in to comment.