Przeglądaj źródła

Created the feat where the users who subscribe descendant pages get subscribed when they got renamed.

Shunm634-source 3 lat temu
rodzic
commit
7c423e2d14

+ 4 - 0
packages/app/src/components/InAppNotification/InAppNotificationElm.tsx

@@ -119,6 +119,10 @@ const InAppNotificationElm: FC<Props> = (props: Props) => {
       actionMsg = 'reverted';
       actionIcon = 'icon-action-undo';
       break;
+    case 'PAGE_RECURSIVELY_RENAME':
+      actionMsg = 'renamed under';
+      actionIcon = 'icon-action-redo';
+      break;
     case 'COMMENT_CREATE':
       actionMsg = 'commented on';
       actionIcon = 'icon-bubble';

+ 6 - 0
packages/app/src/interfaces/activity.ts

@@ -14,6 +14,9 @@ const ACTION_PAGE_DELETE_COMPLETELY = 'PAGE_DELETE_COMPLETELY';
 const ACTION_PAGE_REVERT = 'PAGE_REVERT';
 const ACTION_COMMENT_CREATE = 'COMMENT_CREATE';
 const ACTION_COMMENT_UPDATE = 'COMMENT_UPDATE';
+const ACTION_PAGE_RECURSIVELY_RENAME = 'PAGE_RECURSIVELY_RENAME';
+const ACTION_PAGE_RECURSIVELY_DELETE = 'PAGE_RECURSIVELY_DELETE';
+const ACTION_PAGE_RECURSIVELY_DELETE_COMPLETELY = 'PAGE_RECURSIVELY_DELETE_COMPLETELY';
 
 
 export const SUPPORTED_TARGET_MODEL_TYPE = {
@@ -36,6 +39,9 @@ export const SUPPORTED_ACTION_TYPE = {
   ACTION_PAGE_REVERT,
   ACTION_COMMENT_CREATE,
   ACTION_COMMENT_UPDATE,
+  ACTION_PAGE_RECURSIVELY_RENAME,
+  ACTION_PAGE_RECURSIVELY_DELETE,
+  ACTION_PAGE_RECURSIVELY_DELETE_COMPLETELY,
 } as const;
 
 

+ 2 - 3
packages/app/src/server/models/activity.ts

@@ -72,10 +72,9 @@ activitySchema.methods.getNotificationTargetUsers = async function() {
   const { user: actionUser, target } = this;
 
   const [subscribeUsers, unsubscribeUsers] = await Promise.all([
-    Subscription.getSubscription((target as any) as Types.ObjectId),
-    Subscription.getUnsubscription((target as any) as Types.ObjectId),
+    Subscription.getSubscription((target as Types.ObjectId)),
+    Subscription.getUnsubscription((target as Types.ObjectId)),
   ]);
-
   const unique = array => Object.values(array.reduce((objects, object) => ({ ...objects, [object.toString()]: object }), {}));
   const filter = (array, pull) => {
     const ids = pull.map(object => object.toString());

+ 1 - 2
packages/app/src/server/routes/apiv3/pages.js

@@ -538,9 +538,7 @@ module.exports = (crowi) => {
       logger.error(err);
       return res.apiv3Err(new ErrorV3('Failed to update page.', 'unknown'), 500);
     }
-
     const result = { page: serializePageSecurely(renamedPage ?? page) };
-
     try {
       // global notification
       await globalNotificationService.fire(GlobalNotificationSetting.EVENT.PAGE_MOVE, page, req.user, {
@@ -683,6 +681,7 @@ module.exports = (crowi) => {
    */
   router.post('/duplicate', accessTokenParser, loginRequiredStrictly, csrf, validator.duplicatePage, apiV3FormValidator, async(req, res) => {
     const { pageId, isRecursively } = req.body;
+    // console.log('The page is duplicated recursively?', isRecursively, pageId);
 
     const newPagePath = pathUtils.normalizePath(req.body.pageNameInput);
 

+ 33 - 13
packages/app/src/server/service/page.ts

@@ -166,10 +166,19 @@ class PageService {
       }
     });
 
+    // Change the parameter of the function into the pages
     // rename
-    this.pageEvent.on('rename', async(page, user) => {
+    this.pageEvent.on('rename', async(page, descendantPages, user) => {
+      const isRecursively = descendantPages != null;
+      const action = isRecursively ? SUPPORTED_ACTION_TYPE.ACTION_PAGE_RECURSIVELY_RENAME : SUPPORTED_ACTION_TYPE.ACTION_PAGE_RENAME;
+      const pages = [page];
+      if (isRecursively) {
+        descendantPages.forEach((element) => {
+          pages.push(element);
+        });
+      }
       try {
-        await this.createAndSendNotifications(page, user, SUPPORTED_ACTION_TYPE.ACTION_PAGE_RENAME);
+        await this.createAndSendNotifications(pages, user, action);
       }
       catch (err) {
         logger.error(err);
@@ -537,13 +546,12 @@ class PageService {
       update.updatedAt = new Date();
     }
     const renamedPage = await Page.findByIdAndUpdate(page._id, { $set: update }, { new: true });
-
     // create page redirect
     if (options.createRedirectPage) {
       const PageRedirect = mongoose.model('PageRedirect') as unknown as PageRedirectModel;
       await PageRedirect.create({ fromPath: page.path, toPath: newPagePath });
     }
-    this.pageEvent.emit('rename', page, user);
+    // this.pageEvent.emit('rename', page, user);
 
     // Set to Sub
     const pageOp = await PageOperation.findByIdAndUpdatePageActionStage(pageOpId, PageActionStage.Sub);
@@ -554,18 +562,19 @@ class PageService {
     /*
      * Sub Operation
      */
-    this.renameSubOperation(page, newPagePath, user, options, renamedPage, pageOp._id);
+    const descendantPages = await this.renameSubOperation(page, newPagePath, user, options, renamedPage, pageOp._id);
+    this.pageEvent.emit('rename', page, descendantPages, user);
 
     return renamedPage;
   }
 
-  async renameSubOperation(page, newPagePath: string, user, options, renamedPage, pageOpId: ObjectIdLike): Promise<void> {
+  async renameSubOperation(page, newPagePath: string, user, options, renamedPage, pageOpId: ObjectIdLike) {
     const Page = mongoose.model('Page') as unknown as PageModel;
 
     const exParentId = page.parent;
 
     // update descendants first
-    await this.renameDescendantsWithStream(page, newPagePath, user, options, false);
+    const descendantPages = await this.renameDescendantsWithStream(page, newPagePath, user, options, false);
 
     // reduce ancestore's descendantCount
     const nToReduce = -1 * ((page.isEmpty ? 0 : 1) + page.descendantCount);
@@ -582,6 +591,8 @@ class PageService {
     }
 
     await PageOperation.findByIdAndDelete(pageOpId);
+
+    return descendantPages;
   }
 
   private isRenamingToUnderTarget(fromPath: string, toPath: string): boolean {
@@ -759,6 +770,7 @@ class PageService {
     }
 
     this.pageEvent.emit('updateMany', pages, user);
+    return pages;
   }
 
   private async renameDescendantsV4(pages, user, options, oldPagePathPrefix, newPagePathPrefix) {
@@ -829,12 +841,13 @@ class PageService {
     const renameDescendants = this.renameDescendants.bind(this);
     const pageEvent = this.pageEvent;
     let count = 0;
+    let pages: ObjectId[] = [];
     const writeStream = new Writable({
       objectMode: true,
       async write(batch, encoding, callback) {
         try {
           count += batch.length;
-          await renameDescendants(
+          pages = await renameDescendants(
             batch, user, options, pathRegExp, newPagePathPrefix, shouldUseV4Process,
           );
           logger.debug(`Renaming pages progressing: (count=${count})`);
@@ -861,6 +874,7 @@ class PageService {
       .pipe(writeStream);
 
     await streamToPromise(writeStream);
+    return pages;
   }
 
   private async renameDescendantsWithStreamV4(targetPage, newPagePath, user, options = {}) {
@@ -1842,6 +1856,7 @@ class PageService {
         await this.deletePage(page, user, {}, isRecursively);
       }
     }
+    // Call the pageEvent function with the pagesToDelete as the parameter.
   }
 
   // use the same process in both v4 and v5
@@ -2230,23 +2245,28 @@ class PageService {
     return shortBodiesMap;
   }
 
-  private async createAndSendNotifications(page, user, action) {
+  private async createAndSendNotifications(pages, user, action) {
     const { activityService, inAppNotificationService } = this.crowi;
 
-    const snapshot = stringifySnapshot(page);
+    const snapshot = stringifySnapshot(pages[0]);
 
     // Create activity
     const parameters = {
       user: user._id,
       targetModel: SUPPORTED_TARGET_MODEL_TYPE.MODEL_PAGE,
-      target: page,
+      target: pages[0],
       action,
     };
     const activity = await activityService.createByParameters(parameters);
-
     // Get user to be notified
     const targetUsers = await activity.getNotificationTargetUsers();
-
+    if (action === SUPPORTED_ACTION_TYPE.ACTION_PAGE_RECURSIVELY_DELETE || action === SUPPORTED_ACTION_TYPE.ACTION_PAGE_RECURSIVELY_RENAME || action
+      === SUPPORTED_ACTION_TYPE.ACTION_PAGE_RECURSIVELY_DELETE) {
+      pages.forEach((page) => {
+        targetUsers.concat(Subscription.getSubscription(page));
+      });
+    }
+    console.log('The real target users are:\n', targetUsers);
     // Create and send notifications
     await inAppNotificationService.upsertByActivity(targetUsers, activity, snapshot);
     await inAppNotificationService.emitSocketIo(targetUsers);