ソースを参照

Implemented substr for revision body

Taichi Masuyama 4 年 前
コミット
505f3e60f7

+ 3 - 3
packages/app/src/components/SearchPage.jsx

@@ -142,7 +142,7 @@ class SearchPage extends React.Component {
   }
 
   async fetchShortBodiesMap(pageIds) {
-    const res = await this.props.appContainer.apiGet('/page-listing/short-bodies', { pageIds });
+    const res = await this.props.appContainer.apiv3Get('/page-listing/short-bodies', { pageIds });
     this.setState({ shortBodiesMap: res.data.shortBodiesMap });
   }
 
@@ -182,12 +182,12 @@ class SearchPage extends React.Component {
        * non-await asynchronous short body fetch
        */
       const pageIds = res.data.map((page) => {
-        if (page.pageMeta?.elasticsearchResult?.snippet != null) {
+        if (page.pageMeta?.elasticSearchResult != null && page.pageMeta?.elasticSearchResult?.snippet.length !== 0) {
           return null;
         }
 
         return page.pageData._id;
-      }).filter(page => page != null);
+      }).filter(id => id != null);
       this.fetchShortBodiesMap(pageIds);
 
       this.changeURL(keyword);

+ 48 - 0
packages/app/src/server/models/page.ts

@@ -359,3 +359,51 @@ export default (crowi: Crowi): any => {
 
   return getOrCreateModel<PageDocument, PageModel>('Page', schema);
 };
+
+/*
+ * Aggregation utilities
+ */
+export const generateGrantConditions = async(
+    user, _userGroups, showAnyoneKnowsLink = false, showPagesRestrictedByOwner = false, showPagesRestrictedByGroup = false,
+): Promise<{[key:string]: any | number | null}[]> => {
+  let userGroups = _userGroups;
+  if (user != null && userGroups == null) {
+    const UserGroupRelation: any = mongoose.model('UserGroupRelation');
+    userGroups = await UserGroupRelation.findAllUserGroupIdsRelatedToUser(user);
+  }
+
+  const grantConditions: {[key:string]: any | number | null}[] = [
+    { grant: null },
+    { grant: GRANT_PUBLIC },
+  ];
+
+  if (showAnyoneKnowsLink) {
+    grantConditions.push({ grant: GRANT_RESTRICTED });
+  }
+
+  if (showPagesRestrictedByOwner) {
+    grantConditions.push(
+      { grant: GRANT_SPECIFIED },
+      { grant: GRANT_OWNER },
+    );
+  }
+  else if (user != null) {
+    grantConditions.push(
+      { grant: GRANT_SPECIFIED, grantedUsers: user._id },
+      { grant: GRANT_OWNER, grantedUsers: user._id },
+    );
+  }
+
+  if (showPagesRestrictedByGroup) {
+    grantConditions.push(
+      { grant: GRANT_USER_GROUP },
+    );
+  }
+  else if (userGroups != null && userGroups.length > 0) {
+    grantConditions.push(
+      { grant: GRANT_USER_GROUP, grantedGroup: { $in: userGroups } },
+    );
+  }
+
+  return grantConditions;
+};

+ 68 - 3
packages/app/src/server/service/page.js

@@ -1,6 +1,7 @@
 import { pagePathUtils } from '@growi/core';
 
 import loggerFactory from '~/utils/logger';
+import { generateGrantConditions } from '~/server/models/page';
 
 const mongoose = require('mongoose');
 const escapeStringRegexp = require('escape-string-regexp');
@@ -771,9 +772,73 @@ class PageService {
     }
   }
 
-  async shortBodiesMapByPageIds(pageIds, user) {
-    // TODO: fetch
-    return {};
+  async shortBodiesMapByPageIds(pageIds = [], user) {
+    const Page = mongoose.model('Page');
+    const MAX_LENGTH = 350;
+
+    // aggregation options
+    const viewerConditions = await generateGrantConditions(user, null);
+    const filterByIds = {
+      _id: { $in: pageIds.map(id => mongoose.Types.ObjectId(id)) },
+    };
+    const filterByViewer = {
+      $or: viewerConditions,
+    };
+
+    let pages;
+    try {
+      pages = await Page
+        .aggregate([
+          // filter by pageIds
+          {
+            $match: filterByIds,
+          },
+          // filter by viewer
+          {
+            $match: filterByViewer,
+          },
+          // lookup
+          {
+            $lookup: {
+              from: 'revisions',
+              let: { localRevision: '$revision' },
+              pipeline: [
+                {
+                  $match: {
+                    $expr: {
+                      $eq: ['$_id', '$$localRevision'],
+                    },
+                  },
+                },
+                {
+                  $project: {
+                    revision: { $substr: ['$body', 0, MAX_LENGTH] },
+                  },
+                },
+              ],
+              as: 'revisionData',
+            },
+          },
+          // projection
+          {
+            $project: {
+              _id: 1,
+              revisionData: 1,
+            },
+          },
+        ]).exec();
+    }
+    catch (err) {
+      logger.error('Error occurred while generating shortBodiesMap');
+      throw err;
+    }
+
+    const shortBodiesMap = {};
+    pages.forEach((page) => {
+      shortBodiesMap[page._id] = page.revisionData?.[0]?.revision;
+    });
+
+    return shortBodiesMap;
   }
 
   validateCrowi() {