Просмотр исходного кода

Merge pull request #5933 from weseek/feat/move-model-method-to-service

feat: Move model methods to service
Yohei Shiina 3 лет назад
Родитель
Сommit
e219d5a2d3

+ 1 - 74
packages/app/src/server/models/page.ts

@@ -21,7 +21,7 @@ import { getPageSchema, extractToAncestorsPaths, populateDataToShowRevision } fr
 
 const { addTrailingSlash, normalizePath } = pathUtils;
 const {
-  isTopPage, collectAncestorPaths, hasSlash, generateChildrenRegExp,
+  isTopPage, collectAncestorPaths, hasSlash,
 } = pagePathUtils;
 
 const logger = loggerFactory('growi:models:page');
@@ -543,17 +543,6 @@ schema.statics.replaceTargetWithPage = async function(exPage, pageToReplaceWith?
   return this.findById(newTarget._id);
 };
 
-// Utility function to add viewer condition to PageQueryBuilder instance
-const addViewerCondition = async(queryBuilder: PageQueryBuilder, user, userGroups = null): Promise<void> => {
-  let relatedUserGroups = userGroups;
-  if (user != null && relatedUserGroups == null) {
-    const UserGroupRelation: any = mongoose.model('UserGroupRelation');
-    relatedUserGroups = await UserGroupRelation.findAllUserGroupIdsRelatedToUser(user);
-  }
-
-  queryBuilder.addConditionToFilteringByViewer(user, relatedUserGroups, false);
-};
-
 /*
  * Find pages by ID and viewer.
  */
@@ -659,68 +648,6 @@ schema.statics.findTargetAndAncestorsByPathOrId = async function(pathOrId: strin
   return { targetAndAncestors, rootPage };
 };
 
-/*
- * Find all children by parent's path or id. Using id should be prioritized
- */
-schema.statics.findChildrenByParentPathOrIdAndViewer = async function(parentPathOrId: string, user, userGroups = null): Promise<PageDocument[]> {
-  let queryBuilder: PageQueryBuilder;
-  if (hasSlash(parentPathOrId)) {
-    const path = parentPathOrId;
-    const regexp = generateChildrenRegExp(path);
-    queryBuilder = new PageQueryBuilder(this.find({ path: { $regex: regexp } }), true);
-  }
-  else {
-    const parentId = parentPathOrId;
-    queryBuilder = new PageQueryBuilder(this.find({ parent: parentId } as any), true); // TODO: improve type
-  }
-  await addViewerCondition(queryBuilder, user, userGroups);
-
-  return queryBuilder
-    .addConditionToSortPagesByAscPath()
-    .query
-    .lean()
-    .exec();
-};
-
-schema.statics.findAncestorsChildrenByPathAndViewer = async function(path: string, user, userGroups = null): Promise<Record<string, PageDocument[]>> {
-  const ancestorPaths = isTopPage(path) ? ['/'] : collectAncestorPaths(path); // root path is necessary for rendering
-  const regexps = ancestorPaths.map(path => new RegExp(generateChildrenRegExp(path))); // cannot use re2
-
-  // get pages at once
-  const queryBuilder = new PageQueryBuilder(this.find({ path: { $in: regexps } }), true);
-  await addViewerCondition(queryBuilder, user, userGroups);
-  const _pages = await queryBuilder
-    .addConditionAsOnTree()
-    .addConditionToMinimizeDataForRendering()
-    .addConditionToSortPagesByAscPath()
-    .query
-    .lean()
-    .exec();
-  // mark target
-  const pages = _pages.map((page: PageDocument & { isTarget?: boolean }) => {
-    if (page.path === path) {
-      page.isTarget = true;
-    }
-    return page;
-  });
-
-  /*
-   * If any non-migrated page is found during creating the pathToChildren map, it will stop incrementing at that moment
-   */
-  const pathToChildren: Record<string, PageDocument[]> = {};
-  const sortedPaths = ancestorPaths.sort((a, b) => a.length - b.length); // sort paths by path.length
-  sortedPaths.every((path) => {
-    const children = pages.filter(page => nodePath.dirname(page.path) === path);
-    if (children.length === 0) {
-      return false; // break when children do not exist
-    }
-    pathToChildren[path] = children;
-    return true;
-  });
-
-  return pathToChildren;
-};
-
 /**
  * Create empty pages at paths at which no pages exist
  * @param paths Page paths

+ 4 - 5
packages/app/src/server/routes/apiv3/page-listing.ts

@@ -69,10 +69,9 @@ export default (crowi: Crowi): Router => {
   router.get('/ancestors-children', accessTokenParser, loginRequired, ...validator.pagePathRequired, apiV3FormValidator, async(req: AuthorizedRequest, res: ApiV3Response): Promise<any> => {
     const { path } = req.query;
 
-    const Page: PageModel = crowi.model('Page');
-
+    const pageService: PageService = crowi.pageService!;
     try {
-      const ancestorsChildren = await Page.findAncestorsChildrenByPathAndViewer(path as string, req.user);
+      const ancestorsChildren = await pageService.findAncestorsChildrenByPathAndViewer(path as string, req.user);
       return res.apiv3({ ancestorsChildren });
     }
     catch (err) {
@@ -89,10 +88,10 @@ export default (crowi: Crowi): Router => {
   router.get('/children', accessTokenParser, loginRequired, validator.pageIdOrPathRequired, apiV3FormValidator, async(req: AuthorizedRequest, res: ApiV3Response) => {
     const { id, path } = req.query;
 
-    const Page: PageModel = crowi.model('Page');
+    const pageService: PageService = crowi.pageService!;
 
     try {
-      const pages = await Page.findChildrenByParentPathOrIdAndViewer((id || path)as string, req.user);
+      const pages = await pageService.findChildrenByParentPathOrIdAndViewer((id || path)as string, req.user);
       return res.apiv3({ children: pages });
     }
     catch (err) {

+ 67 - 2
packages/app/src/server/service/page.ts

@@ -20,7 +20,7 @@ import { IUserHasId } from '~/interfaces/user';
 import { PageMigrationErrorData, SocketEventName, UpdateDescCountRawData } from '~/interfaces/websocket';
 import { stringifySnapshot } from '~/models/serializers/in-app-notification-snapshot/page';
 import {
-  CreateMethod, PageCreateOptions, PageModel, PageDocument, pushRevision,
+  CreateMethod, PageCreateOptions, PageModel, PageDocument, pushRevision, PageQueryBuilder,
 } from '~/server/models/page';
 import { createBatchStream } from '~/server/util/batch-stream';
 import loggerFactory from '~/utils/logger';
@@ -39,7 +39,7 @@ const debug = require('debug')('growi:services:page');
 const logger = loggerFactory('growi:services:page');
 const {
   isTrashPage, isTopPage, omitDuplicateAreaPageFromPages,
-  collectAncestorPaths, isMovablePage, canMoveByPath,
+  collectAncestorPaths, isMovablePage, canMoveByPath, hasSlash, generateChildrenRegExp,
 } = pagePathUtils;
 
 const { addTrailingSlash } = pathUtils;
@@ -3454,6 +3454,71 @@ class PageService {
     return savedPage;
   }
 
+  /*
+   * Find all children by parent's path or id. Using id should be prioritized
+   */
+  async findChildrenByParentPathOrIdAndViewer(parentPathOrId: string, user, userGroups = null): Promise<PageDocument[]> {
+    const Page = mongoose.model('Page') as unknown as PageModel;
+    let queryBuilder: PageQueryBuilder;
+    if (hasSlash(parentPathOrId)) {
+      const path = parentPathOrId;
+      const regexp = generateChildrenRegExp(path);
+      queryBuilder = new PageQueryBuilder(Page.find({ path: { $regex: regexp } }), true);
+    }
+    else {
+      const parentId = parentPathOrId;
+      queryBuilder = new PageQueryBuilder(Page.find({ parent: parentId } as any), true); // TODO: improve type
+    }
+    await queryBuilder.addViewerCondition(user, userGroups);
+
+    return queryBuilder
+      .addConditionToSortPagesByAscPath()
+      .query
+      .lean()
+      .exec();
+  }
+
+  async findAncestorsChildrenByPathAndViewer(path: string, user, userGroups = null): Promise<Record<string, PageDocument[]>> {
+    const Page = mongoose.model('Page') as unknown as PageModel;
+
+    const ancestorPaths = isTopPage(path) ? ['/'] : collectAncestorPaths(path); // root path is necessary for rendering
+    const regexps = ancestorPaths.map(path => new RegExp(generateChildrenRegExp(path))); // cannot use re2
+
+    // get pages at once
+    const queryBuilder = new PageQueryBuilder(Page.find({ path: { $in: regexps } }), true);
+    await queryBuilder.addViewerCondition(user, userGroups);
+    const _pages = await queryBuilder
+      .addConditionAsOnTree()
+      .addConditionToMinimizeDataForRendering()
+      .addConditionToSortPagesByAscPath()
+      .query
+      .lean()
+      .exec();
+    // mark target
+    const pages = _pages.map((page: PageDocument & { isTarget?: boolean }) => {
+      if (page.path === path) {
+        page.isTarget = true;
+      }
+      return page;
+    });
+
+    /*
+     * If any non-migrated page is found during creating the pathToChildren map, it will stop incrementing at that moment
+     */
+    const pathToChildren: Record<string, PageDocument[]> = {};
+    const sortedPaths = ancestorPaths.sort((a, b) => a.length - b.length); // sort paths by path.length
+    sortedPaths.every((path) => {
+      const children = pages.filter(page => pathlib.dirname(page.path) === path);
+      if (children.length === 0) {
+        return false; // break when children do not exist
+      }
+      pathToChildren[path] = children;
+      return true;
+    });
+
+    return pathToChildren;
+  }
+
 }
 
 export default PageService;