revision.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import { allOrigin } from '@growi/core';
  2. import type {
  3. HasObjectId,
  4. IRevision,
  5. Origin,
  6. } from '@growi/core/dist/interfaces';
  7. import type { Types } from 'mongoose';
  8. import { type Document, type Model, Schema } from 'mongoose';
  9. import mongoosePaginate from 'mongoose-paginate-v2';
  10. import loggerFactory from '~/utils/logger';
  11. import { getOrCreateModel } from '../util/mongoose-utils';
  12. import type { PageDocument } from './page';
  13. const logger = loggerFactory('growi:models:revision');
  14. export interface IRevisionDocument extends IRevision, Document {}
  15. type UpdateRevisionListByPageId = (
  16. pageId: Types.ObjectId,
  17. updateData: Partial<IRevision>,
  18. ) => Promise<void>;
  19. type PrepareRevision = (
  20. pageData: PageDocument,
  21. body: string,
  22. previousBody: string | null,
  23. user: HasObjectId,
  24. origin?: Origin,
  25. options?: { format: string },
  26. ) => IRevisionDocument;
  27. export interface IRevisionModel extends Model<IRevisionDocument> {
  28. updateRevisionListByPageId: UpdateRevisionListByPageId;
  29. prepareRevision: PrepareRevision;
  30. }
  31. // Use this to allow empty strings to pass the `required` validator
  32. Schema.Types.String.checkRequired((v) => typeof v === 'string');
  33. const revisionSchema = new Schema<IRevisionDocument, IRevisionModel>(
  34. {
  35. // The type of pageId is always converted to String at server startup
  36. // Refer to this method (/src/server/service/normalize-data/convert-revision-page-id-to-string.ts) to change the pageId type
  37. pageId: {
  38. type: Schema.Types.ObjectId,
  39. ref: 'Page',
  40. required: true,
  41. index: true,
  42. },
  43. body: {
  44. type: String,
  45. required: true,
  46. get: (data) => {
  47. // replace CR/CRLF to LF above v3.1.5
  48. // see https://github.com/growilabs/growi/issues/463
  49. return data ? data.replace(/\r\n?/g, '\n') : '';
  50. },
  51. },
  52. format: { type: String, default: 'markdown' },
  53. author: { type: Schema.Types.ObjectId, ref: 'User' },
  54. hasDiffToPrev: { type: Boolean },
  55. origin: { type: String, enum: allOrigin },
  56. },
  57. {
  58. timestamps: { createdAt: true, updatedAt: false },
  59. },
  60. );
  61. revisionSchema.plugin(mongoosePaginate);
  62. const updateRevisionListByPageId: UpdateRevisionListByPageId = async function (
  63. this: IRevisionModel,
  64. pageId,
  65. updateData,
  66. ) {
  67. // Check pageId for safety
  68. if (pageId == null) {
  69. throw new Error('Error: pageId is required');
  70. }
  71. await this.updateMany({ pageId }, { $set: updateData });
  72. };
  73. revisionSchema.statics.updateRevisionListByPageId = updateRevisionListByPageId;
  74. const prepareRevision: PrepareRevision = function (
  75. this: IRevisionModel,
  76. pageData,
  77. body,
  78. previousBody,
  79. user,
  80. origin,
  81. options = { format: 'markdown' },
  82. ) {
  83. if (user._id == null) {
  84. throw new Error('user should have _id');
  85. }
  86. if (pageData._id == null) {
  87. throw new Error('pageData should have _id');
  88. }
  89. const newRevision = new this();
  90. newRevision.pageId = pageData._id;
  91. newRevision.body = body;
  92. newRevision.format = options.format;
  93. newRevision.author = user._id;
  94. newRevision.origin = origin;
  95. if (pageData.revision != null) {
  96. newRevision.hasDiffToPrev = body !== previousBody;
  97. }
  98. return newRevision;
  99. };
  100. revisionSchema.statics.prepareRevision = prepareRevision;
  101. export const Revision = getOrCreateModel<IRevisionDocument, IRevisionModel>(
  102. 'Revision',
  103. revisionSchema,
  104. );