|
|
@@ -10,7 +10,6 @@ import type {
|
|
|
import {
|
|
|
AllSubscriptionStatusType,
|
|
|
getIdForRef,
|
|
|
- getIdStringForRef,
|
|
|
isIPageNotFoundInfo,
|
|
|
PageGrant,
|
|
|
SCOPE,
|
|
|
@@ -40,7 +39,6 @@ import loginRequiredFactory from '~/server/middlewares/login-required';
|
|
|
import { GlobalNotificationSettingEvent } from '~/server/models/GlobalNotificationSetting';
|
|
|
import type { PageDocument, PageModel } from '~/server/models/page';
|
|
|
import { Revision } from '~/server/models/revision';
|
|
|
-import ShareLink from '~/server/models/share-link';
|
|
|
import Subscription from '~/server/models/subscription';
|
|
|
import { configManager } from '~/server/service/config-manager';
|
|
|
import { exportService } from '~/server/service/export';
|
|
|
@@ -53,10 +51,12 @@ import loggerFactory from '~/utils/logger';
|
|
|
import type { ApiV3Response } from '../interfaces/apiv3-response';
|
|
|
import { checkPageExistenceHandlersFactory } from './check-page-existence';
|
|
|
import { createPageHandlersFactory } from './create-page';
|
|
|
+import { getPageByShareLinkHandlerFactory } from './get-page-by-share-link';
|
|
|
import { getPageInfoHandlerFactory } from './get-page-info';
|
|
|
import { getPagePathsWithDescendantCountFactory } from './get-page-paths-with-descendant-count';
|
|
|
import { getYjsDataHandlerFactory } from './get-yjs-data';
|
|
|
import { publishPageHandlersFactory } from './publish-page';
|
|
|
+import { respondWithSinglePage } from './respond-with-single-page';
|
|
|
import { syncLatestRevisionBodyToYjsDraftHandlerFactory } from './sync-latest-revision-body-to-yjs-draft';
|
|
|
import { unpublishPageHandlersFactory } from './unpublish-page';
|
|
|
import { updatePageHandlersFactory } from './update-page';
|
|
|
@@ -89,9 +89,6 @@ const router = express.Router();
|
|
|
module.exports = (crowi: Crowi) => {
|
|
|
const loginRequired = loginRequiredFactory(crowi, true);
|
|
|
const loginRequiredStrictly = loginRequiredFactory(crowi);
|
|
|
- const certifySharedPage = require('../../../middlewares/certify-shared-page')(
|
|
|
- crowi,
|
|
|
- );
|
|
|
const addActivity = generateAddActivityMiddleware();
|
|
|
|
|
|
const globalNotificationService = crowi.globalNotificationService;
|
|
|
@@ -105,7 +102,6 @@ module.exports = (crowi: Crowi) => {
|
|
|
query('pageId').isMongoId().optional().isString(),
|
|
|
query('path').optional().isString(),
|
|
|
query('findAll').optional().isBoolean(),
|
|
|
- query('shareLinkId').optional().isMongoId(),
|
|
|
query('includeEmpty').optional().isBoolean(),
|
|
|
],
|
|
|
likes: [body('pageId').isString(), body('bool').isBoolean()],
|
|
|
@@ -183,11 +179,6 @@ module.exports = (crowi: Crowi) => {
|
|
|
* description: Specific revision ID to retrieve
|
|
|
* schema:
|
|
|
* $ref: '#/components/schemas/ObjectId'
|
|
|
- * - name: shareLinkId
|
|
|
- * in: query
|
|
|
- * description: Share link ID for shared page access
|
|
|
- * schema:
|
|
|
- * $ref: '#/components/schemas/ObjectId'
|
|
|
* - name: includeEmpty
|
|
|
* in: query
|
|
|
* description: Include empty pages in results when using findAll
|
|
|
@@ -204,110 +195,26 @@ module.exports = (crowi: Crowi) => {
|
|
|
router.get(
|
|
|
'/',
|
|
|
accessTokenParser([SCOPE.READ.FEATURES.PAGE], { acceptLegacy: true }),
|
|
|
- certifySharedPage,
|
|
|
loginRequired,
|
|
|
validator.getPage,
|
|
|
apiV3FormValidator,
|
|
|
async (req, res) => {
|
|
|
- const { user, isSharedPage } = req;
|
|
|
- const { pageId, path, findAll, revisionId, shareLinkId, includeEmpty } =
|
|
|
- req.query;
|
|
|
+ const { user } = req;
|
|
|
+ const { pageId, path, findAll, revisionId, includeEmpty } = req.query;
|
|
|
|
|
|
const disableUserPages = crowi.configManager.getConfig(
|
|
|
'security:disableUserPages',
|
|
|
);
|
|
|
|
|
|
- const respondWithSinglePage = async (
|
|
|
- pageWithMeta:
|
|
|
- | IDataWithMeta<HydratedDocument<PageDocument>, IPageInfoExt>
|
|
|
- | IDataWithMeta<null, IPageNotFoundInfo>,
|
|
|
- ) => {
|
|
|
- let { data: page } = pageWithMeta;
|
|
|
- const { meta } = pageWithMeta;
|
|
|
-
|
|
|
- if (isIPageNotFoundInfo(meta)) {
|
|
|
- if (meta.isForbidden) {
|
|
|
- return res.apiv3Err(
|
|
|
- new ErrorV3(
|
|
|
- 'Page is forbidden',
|
|
|
- 'page-is-forbidden',
|
|
|
- undefined,
|
|
|
- meta,
|
|
|
- ),
|
|
|
- 403,
|
|
|
- );
|
|
|
- }
|
|
|
- return res.apiv3Err(
|
|
|
- new ErrorV3('Page is not found', 'page-not-found', undefined, meta),
|
|
|
- 404,
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- if (disableUserPages && page != null) {
|
|
|
- const isTargetUserPage =
|
|
|
- isUserPage(page.path) || isUsersTopPage(page.path);
|
|
|
-
|
|
|
- if (isTargetUserPage) {
|
|
|
- return res.apiv3Err(
|
|
|
- new ErrorV3('Page is forbidden', 'page-is-forbidden'),
|
|
|
- 403,
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (page != null) {
|
|
|
- try {
|
|
|
- page.initLatestRevisionField(revisionId);
|
|
|
-
|
|
|
- // populate
|
|
|
- page = await page.populateDataToShowRevision();
|
|
|
- } catch (err) {
|
|
|
- logger.error('populate-page-failed', err);
|
|
|
- return res.apiv3Err(
|
|
|
- new ErrorV3(
|
|
|
- 'Failed to populate page',
|
|
|
- 'populate-page-failed',
|
|
|
- undefined,
|
|
|
- { err, meta },
|
|
|
- ),
|
|
|
- 500,
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return res.apiv3({ page, pages: undefined, meta });
|
|
|
- };
|
|
|
-
|
|
|
- const isValid =
|
|
|
- (shareLinkId != null && pageId != null && path == null) ||
|
|
|
- (shareLinkId == null && (pageId != null || path != null));
|
|
|
+ const isValid = pageId != null || path != null;
|
|
|
if (!isValid) {
|
|
|
return res.apiv3Err(
|
|
|
- new Error(
|
|
|
- 'Either parameter of (pageId or path) or (pageId and shareLinkId) is required.',
|
|
|
- ),
|
|
|
+ new Error('Either pageId or path is required.'),
|
|
|
400,
|
|
|
);
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
- if (isSharedPage) {
|
|
|
- const shareLink = await ShareLink.findOne({
|
|
|
- _id: { $eq: shareLinkId },
|
|
|
- });
|
|
|
- if (shareLink == null) {
|
|
|
- return res.apiv3Err('ShareLink is not found', 404);
|
|
|
- }
|
|
|
- return respondWithSinglePage(
|
|
|
- await findPageAndMetaDataByViewer(pageService, pageGrantService, {
|
|
|
- pageId: getIdStringForRef(shareLink.relatedPage),
|
|
|
- path,
|
|
|
- user,
|
|
|
- isSharedPage: true,
|
|
|
- }),
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
if (findAll != null) {
|
|
|
const pages = await Page.findByPathAndViewer(
|
|
|
path,
|
|
|
@@ -327,11 +234,13 @@ module.exports = (crowi: Crowi) => {
|
|
|
}
|
|
|
|
|
|
return respondWithSinglePage(
|
|
|
+ res,
|
|
|
await findPageAndMetaDataByViewer(pageService, pageGrantService, {
|
|
|
pageId,
|
|
|
path,
|
|
|
user,
|
|
|
}),
|
|
|
+ { revisionId, disableUserPages },
|
|
|
);
|
|
|
} catch (err) {
|
|
|
logger.error('get-page-failed', err);
|
|
|
@@ -587,6 +496,8 @@ module.exports = (crowi: Crowi) => {
|
|
|
},
|
|
|
);
|
|
|
|
|
|
+ router.get('/shared', getPageByShareLinkHandlerFactory(crowi));
|
|
|
+
|
|
|
router.get('/info', getPageInfoHandlerFactory(crowi));
|
|
|
|
|
|
/**
|