page-operation.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import { getOrCreateModel } from '@growi/core';
  2. import mongoose, {
  3. Schema, Model, Document, QueryOptions, FilterQuery,
  4. } from 'mongoose';
  5. import {
  6. IPageForResuming, IUserForResuming, IOptionsForResuming,
  7. } from '~/server/interfaces/page-operation';
  8. import { ObjectIdLike } from '../interfaces/mongoose-utils';
  9. type IObjectId = mongoose.Types.ObjectId;
  10. const ObjectId = mongoose.Schema.Types.ObjectId;
  11. export const PageActionType = {
  12. Rename: 'Rename',
  13. Duplicate: 'Duplicate',
  14. Delete: 'Delete',
  15. DeleteCompletely: 'DeleteCompletely',
  16. Revert: 'Revert',
  17. NormalizeParent: 'NormalizeParent',
  18. } as const;
  19. export type PageActionType = typeof PageActionType[keyof typeof PageActionType];
  20. export const PageActionStage = {
  21. Main: 'Main',
  22. Sub: 'Sub',
  23. } as const;
  24. export type PageActionStage = typeof PageActionStage[keyof typeof PageActionStage];
  25. export const PageOperationAutoUpdateTimerType = {
  26. ExtendSec: 5, // add this second(s) to current time
  27. IntervalSec: 5, // every this second(s)
  28. SelfStopSec: 20, // execute self-stop after this second(s)
  29. } as const;
  30. /*
  31. * Main Schema
  32. */
  33. export interface IPageOperation {
  34. actionType: PageActionType,
  35. actionStage: PageActionStage,
  36. fromPath: string,
  37. toPath?: string,
  38. page: IPageForResuming,
  39. user: IUserForResuming,
  40. options?: IOptionsForResuming,
  41. incForUpdatingDescendantCount?: number,
  42. unprocessableExpiryDate?: Date,
  43. }
  44. export interface PageOperationDocument extends IPageOperation, Document {}
  45. export type PageOperationDocumentHasId = PageOperationDocument & { _id: ObjectIdLike };
  46. export interface PageOperationModel extends Model<PageOperationDocument> {
  47. findByIdAndUpdatePageActionStage(pageOpId: ObjectIdLike, stage: PageActionStage): Promise<PageOperationDocumentHasId | null>
  48. findMainOps(filter?: FilterQuery<PageOperationDocument>, projection?: any, options?: QueryOptions): Promise<PageOperationDocumentHasId[]>
  49. }
  50. const pageSchemaForResuming = new Schema<IPageForResuming>({
  51. _id: { type: ObjectId, ref: 'Page', index: true },
  52. parent: { type: ObjectId, ref: 'Page' },
  53. descendantCount: { type: Number },
  54. isEmpty: { type: Boolean },
  55. path: { type: String, required: true, index: true },
  56. revision: { type: ObjectId, ref: 'Revision' },
  57. status: { type: String },
  58. grant: { type: Number },
  59. grantedUsers: [{ type: ObjectId, ref: 'User' }],
  60. grantedGroup: { type: ObjectId, ref: 'UserGroup' },
  61. creator: { type: ObjectId, ref: 'User' },
  62. lastUpdateUser: { type: ObjectId, ref: 'User' },
  63. });
  64. const userSchemaForResuming = new Schema<IUserForResuming>({
  65. _id: { type: ObjectId, ref: 'User', required: true },
  66. });
  67. const optionsSchemaForResuming = new Schema<IOptionsForResuming>({
  68. createRedirectPage: { type: Boolean },
  69. updateMetadata: { type: Boolean },
  70. prevDescendantCount: { type: Number },
  71. }, { _id: false });
  72. const schema = new Schema<PageOperationDocument, PageOperationModel>({
  73. actionType: {
  74. type: String,
  75. enum: PageActionType,
  76. required: true,
  77. index: true,
  78. },
  79. actionStage: {
  80. type: String,
  81. enum: PageActionStage,
  82. required: true,
  83. index: true,
  84. },
  85. fromPath: { type: String, required: true, index: true },
  86. toPath: { type: String, index: true },
  87. page: { type: pageSchemaForResuming, required: true },
  88. user: { type: userSchemaForResuming, required: true },
  89. options: { type: optionsSchemaForResuming },
  90. incForUpdatingDescendantCount: { type: Number },
  91. unprocessableExpiryDate: { type: Date, default: null },
  92. });
  93. schema.statics.findByIdAndUpdatePageActionStage = async function(
  94. pageOpId: ObjectIdLike, stage: PageActionStage,
  95. ): Promise<PageOperationDocumentHasId | null> {
  96. return this.findByIdAndUpdate(pageOpId, {
  97. $set: { actionStage: stage },
  98. }, { new: true });
  99. };
  100. schema.statics.findMainOps = async function(
  101. filter?: FilterQuery<PageOperationDocument>, projection?: any, options?: QueryOptions,
  102. ): Promise<PageOperationDocumentHasId[]> {
  103. return this.find(
  104. { ...filter, actionStage: PageActionStage.Main },
  105. projection,
  106. options,
  107. );
  108. };
  109. schema.statics.cleanup = async function(excludeActionTypeList: PageActionType[], excludeStage: PageActionStage): Promise<void> {
  110. await this.deleteMany({ actionType: { $nin: excludeActionTypeList }, actionStage: { $ne: excludeStage } });
  111. };
  112. export default getOrCreateModel<PageOperationDocument, PageOperationModel>('PageOperation', schema);