|
@@ -7,6 +7,7 @@ import {
|
|
|
IDataWithMeta, IPageInfoForEntity, IPagePopulatedToShowRevision, isClient, isIPageInfoForEntity, isServer, IUser, IUserHasId, pagePathUtils, pathUtils,
|
|
IDataWithMeta, IPageInfoForEntity, IPagePopulatedToShowRevision, isClient, isIPageInfoForEntity, isServer, IUser, IUserHasId, pagePathUtils, pathUtils,
|
|
|
} from '@growi/core';
|
|
} from '@growi/core';
|
|
|
import ExtensibleCustomError from 'extensible-custom-error';
|
|
import ExtensibleCustomError from 'extensible-custom-error';
|
|
|
|
|
+import mongoose from 'mongoose';
|
|
|
import {
|
|
import {
|
|
|
NextPage, GetServerSideProps, GetServerSidePropsContext,
|
|
NextPage, GetServerSideProps, GetServerSidePropsContext,
|
|
|
} from 'next';
|
|
} from 'next';
|
|
@@ -19,16 +20,19 @@ import superjson from 'superjson';
|
|
|
import { PageAlerts } from '~/components/PageAlert/PageAlerts';
|
|
import { PageAlerts } from '~/components/PageAlert/PageAlerts';
|
|
|
// import { PageComments } from '~/components/PageComment/PageComments';
|
|
// import { PageComments } from '~/components/PageComment/PageComments';
|
|
|
// import { useTranslation } from '~/i18n';
|
|
// import { useTranslation } from '~/i18n';
|
|
|
|
|
+import { PageContentFooter } from '~/components/PageContentFooter';
|
|
|
import { CrowiRequest } from '~/interfaces/crowi-request';
|
|
import { CrowiRequest } from '~/interfaces/crowi-request';
|
|
|
// import { renderScriptTagByName, renderHighlightJsStyleTag } from '~/service/cdn-resources-loader';
|
|
// import { renderScriptTagByName, renderHighlightJsStyleTag } from '~/service/cdn-resources-loader';
|
|
|
// import { useIndentSize } from '~/stores/editor';
|
|
// import { useIndentSize } from '~/stores/editor';
|
|
|
// import { useRendererSettings } from '~/stores/renderer';
|
|
// import { useRendererSettings } from '~/stores/renderer';
|
|
|
// import { EditorMode, useEditorMode, useIsMobile } from '~/stores/ui';
|
|
// import { EditorMode, useEditorMode, useIsMobile } from '~/stores/ui';
|
|
|
|
|
+import { EditorConfig } from '~/interfaces/editor-settings';
|
|
|
import { CustomWindow } from '~/interfaces/global';
|
|
import { CustomWindow } from '~/interfaces/global';
|
|
|
import { RendererConfig } from '~/interfaces/services/renderer';
|
|
import { RendererConfig } from '~/interfaces/services/renderer';
|
|
|
import { ISidebarConfig } from '~/interfaces/sidebar-config';
|
|
import { ISidebarConfig } from '~/interfaces/sidebar-config';
|
|
|
import { IUserUISettings } from '~/interfaces/user-ui-settings';
|
|
import { IUserUISettings } from '~/interfaces/user-ui-settings';
|
|
|
import { PageModel, PageDocument } from '~/server/models/page';
|
|
import { PageModel, PageDocument } from '~/server/models/page';
|
|
|
|
|
+import { PageRedirectModel } from '~/server/models/page-redirect';
|
|
|
import UserUISettings from '~/server/models/user-ui-settings';
|
|
import UserUISettings from '~/server/models/user-ui-settings';
|
|
|
import Xss from '~/services/xss';
|
|
import Xss from '~/services/xss';
|
|
|
import { useSWRxCurrentPage, useSWRxPageInfo } from '~/stores/page';
|
|
import { useSWRxCurrentPage, useSWRxPageInfo } from '~/stores/page';
|
|
@@ -37,12 +41,15 @@ import {
|
|
|
} from '~/stores/ui';
|
|
} from '~/stores/ui';
|
|
|
import loggerFactory from '~/utils/logger';
|
|
import loggerFactory from '~/utils/logger';
|
|
|
|
|
|
|
|
|
|
+
|
|
|
// import { isUserPage, isTrashPage, isSharedPage } from '~/utils/path-utils';
|
|
// import { isUserPage, isTrashPage, isSharedPage } from '~/utils/path-utils';
|
|
|
|
|
|
|
|
// import GrowiSubNavigation from '../client/js/components/Navbar/GrowiSubNavigation';
|
|
// import GrowiSubNavigation from '../client/js/components/Navbar/GrowiSubNavigation';
|
|
|
// import GrowiSubNavigationSwitcher from '../client/js/components/Navbar/GrowiSubNavigationSwitcher';
|
|
// import GrowiSubNavigationSwitcher from '../client/js/components/Navbar/GrowiSubNavigationSwitcher';
|
|
|
|
|
+import ForbiddenPage from '../components/ForbiddenPage';
|
|
|
import { BasicLayout } from '../components/Layout/BasicLayout';
|
|
import { BasicLayout } from '../components/Layout/BasicLayout';
|
|
|
import GrowiContextualSubNavigation from '../components/Navbar/GrowiContextualSubNavigation';
|
|
import GrowiContextualSubNavigation from '../components/Navbar/GrowiContextualSubNavigation';
|
|
|
|
|
+import { NotCreatablePage } from '../components/NotCreatablePage';
|
|
|
import DisplaySwitcher from '../components/Page/DisplaySwitcher';
|
|
import DisplaySwitcher from '../components/Page/DisplaySwitcher';
|
|
|
|
|
|
|
|
// import { serializeUserSecurely } from '../server/models/serializers/user-serializer';
|
|
// import { serializeUserSecurely } from '../server/models/serializers/user-serializer';
|
|
@@ -59,13 +66,13 @@ import {
|
|
|
useIsAclEnabled, useIsUserPage, useIsNotCreatable,
|
|
useIsAclEnabled, useIsUserPage, useIsNotCreatable,
|
|
|
useCsrfToken, useIsSearchScopeChildrenAsDefault, useCurrentPageId, useCurrentPathname,
|
|
useCsrfToken, useIsSearchScopeChildrenAsDefault, useCurrentPageId, useCurrentPathname,
|
|
|
useIsSlackConfigured, useIsBlinkedHeaderAtBoot, useRendererConfig, useEditingMarkdown,
|
|
useIsSlackConfigured, useIsBlinkedHeaderAtBoot, useRendererConfig, useEditingMarkdown,
|
|
|
|
|
+ useEditorConfig, useIsAllReplyShown,
|
|
|
} from '../stores/context';
|
|
} from '../stores/context';
|
|
|
import { useXss } from '../stores/xss';
|
|
import { useXss } from '../stores/xss';
|
|
|
|
|
|
|
|
import {
|
|
import {
|
|
|
CommonProps, getNextI18NextConfig, getServerSideCommonProps, useCustomTitle,
|
|
CommonProps, getNextI18NextConfig, getServerSideCommonProps, useCustomTitle,
|
|
|
} from './utils/commons';
|
|
} from './utils/commons';
|
|
|
-import { registerTransformerForObjectId } from './utils/objectid-transformer';
|
|
|
|
|
// import { useCurrentPageSWR } from '../stores/page';
|
|
// import { useCurrentPageSWR } from '../stores/page';
|
|
|
|
|
|
|
|
|
|
|
|
@@ -80,9 +87,6 @@ const { removeHeadingSlash } = pathUtils;
|
|
|
type IPageToShowRevisionWithMeta = IDataWithMeta<IPagePopulatedToShowRevision & PageDocument, IPageInfoForEntity>;
|
|
type IPageToShowRevisionWithMeta = IDataWithMeta<IPagePopulatedToShowRevision & PageDocument, IPageInfoForEntity>;
|
|
|
type IPageToShowRevisionWithMetaSerialized = IDataWithMeta<string, string>;
|
|
type IPageToShowRevisionWithMetaSerialized = IDataWithMeta<string, string>;
|
|
|
|
|
|
|
|
-// register custom serializer
|
|
|
|
|
-registerTransformerForObjectId();
|
|
|
|
|
-
|
|
|
|
|
superjson.registerCustom<IPageToShowRevisionWithMeta, IPageToShowRevisionWithMetaSerialized>(
|
|
superjson.registerCustom<IPageToShowRevisionWithMeta, IPageToShowRevisionWithMetaSerialized>(
|
|
|
{
|
|
{
|
|
|
isApplicable: (v): v is IPageToShowRevisionWithMeta => {
|
|
isApplicable: (v): v is IPageToShowRevisionWithMeta => {
|
|
@@ -123,8 +127,7 @@ type Props = CommonProps & {
|
|
|
|
|
|
|
|
pageWithMeta: IPageToShowRevisionWithMeta,
|
|
pageWithMeta: IPageToShowRevisionWithMeta,
|
|
|
// pageUser?: any,
|
|
// pageUser?: any,
|
|
|
- // redirectTo?: string;
|
|
|
|
|
- // redirectFrom?: string;
|
|
|
|
|
|
|
+ redirectFrom?: string;
|
|
|
|
|
|
|
|
// shareLinkId?: string;
|
|
// shareLinkId?: string;
|
|
|
isLatestRevision?: boolean
|
|
isLatestRevision?: boolean
|
|
@@ -148,9 +151,9 @@ type Props = CommonProps & {
|
|
|
// mathJax: string,
|
|
// mathJax: string,
|
|
|
// noCdn: string,
|
|
// noCdn: string,
|
|
|
// highlightJsStyle: string,
|
|
// highlightJsStyle: string,
|
|
|
- // isAllReplyShown: boolean,
|
|
|
|
|
|
|
+ isAllReplyShown: boolean,
|
|
|
// isContainerFluid: boolean,
|
|
// isContainerFluid: boolean,
|
|
|
- // editorConfig: any,
|
|
|
|
|
|
|
+ editorConfig: EditorConfig,
|
|
|
isEnabledStaleNotification: boolean,
|
|
isEnabledStaleNotification: boolean,
|
|
|
// isEnabledLinebreaks: boolean,
|
|
// isEnabledLinebreaks: boolean,
|
|
|
// isEnabledLinebreaksInComments: boolean,
|
|
// isEnabledLinebreaksInComments: boolean,
|
|
@@ -182,7 +185,7 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
|
|
|
|
|
|
|
|
// commons
|
|
// commons
|
|
|
useXss(new Xss());
|
|
useXss(new Xss());
|
|
|
- // useEditorConfig(props.editorConfig);
|
|
|
|
|
|
|
+ useEditorConfig(props.editorConfig);
|
|
|
useCsrfToken(props.csrfToken);
|
|
useCsrfToken(props.csrfToken);
|
|
|
|
|
|
|
|
// UserUISettings
|
|
// UserUISettings
|
|
@@ -226,7 +229,7 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
|
|
|
useRendererConfig(props.rendererConfig);
|
|
useRendererConfig(props.rendererConfig);
|
|
|
// useRendererSettings(props.rendererSettingsStr != null ? JSON.parse(props.rendererSettingsStr) : undefined);
|
|
// useRendererSettings(props.rendererSettingsStr != null ? JSON.parse(props.rendererSettingsStr) : undefined);
|
|
|
// useGrowiRendererConfig(props.growiRendererConfigStr != null ? JSON.parse(props.growiRendererConfigStr) : undefined);
|
|
// useGrowiRendererConfig(props.growiRendererConfigStr != null ? JSON.parse(props.growiRendererConfigStr) : undefined);
|
|
|
-
|
|
|
|
|
|
|
+ useIsAllReplyShown(props.isAllReplyShown);
|
|
|
|
|
|
|
|
// const { data: editorMode } = useEditorMode();
|
|
// const { data: editorMode } = useEditorMode();
|
|
|
|
|
|
|
@@ -302,10 +305,10 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
|
|
|
{ !props.isIdenticalPathPage && (
|
|
{ !props.isIdenticalPathPage && (
|
|
|
<>
|
|
<>
|
|
|
<PageAlerts />
|
|
<PageAlerts />
|
|
|
- { props.isForbidden
|
|
|
|
|
- ? <>ForbiddenPage</>
|
|
|
|
|
- : <DisplaySwitcher />
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ { props.isForbidden && <ForbiddenPage /> }
|
|
|
|
|
+ { props.IsNotCreatable && <NotCreatablePage />}
|
|
|
|
|
+ { !props.isForbidden && !props.IsNotCreatable && <DisplaySwitcher />}
|
|
|
|
|
+ {/* <DisplaySwitcher /> */}
|
|
|
<div id="page-editor-navbar-bottom-container" className="d-none d-edit-block"></div>
|
|
<div id="page-editor-navbar-bottom-container" className="d-none d-edit-block"></div>
|
|
|
{/* <PageStatusAlert /> */}
|
|
{/* <PageStatusAlert /> */}
|
|
|
PageStatusAlert
|
|
PageStatusAlert
|
|
@@ -326,6 +329,7 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
|
|
|
{/* <PageComments /> */}
|
|
{/* <PageComments /> */}
|
|
|
PageComments
|
|
PageComments
|
|
|
<CommentEditorLazyRenderer />
|
|
<CommentEditorLazyRenderer />
|
|
|
|
|
+ <PageContentFooter />
|
|
|
</footer>
|
|
</footer>
|
|
|
|
|
|
|
|
<UnsavedAlertDialog />
|
|
<UnsavedAlertDialog />
|
|
@@ -358,17 +362,28 @@ async function injectPageData(context: GetServerSidePropsContext, props: Props):
|
|
|
const { revisionId } = req.query;
|
|
const { revisionId } = req.query;
|
|
|
|
|
|
|
|
const Page = crowi.model('Page') as PageModel;
|
|
const Page = crowi.model('Page') as PageModel;
|
|
|
|
|
+ const PageRedirect = mongoose.model('PageRedirect') as PageRedirectModel;
|
|
|
const { pageService } = crowi;
|
|
const { pageService } = crowi;
|
|
|
|
|
|
|
|
- const { currentPathname } = props;
|
|
|
|
|
|
|
+ let currentPathname = props.currentPathname;
|
|
|
|
|
|
|
|
const pageId = getPageIdFromPathname(currentPathname);
|
|
const pageId = getPageIdFromPathname(currentPathname);
|
|
|
const isPermalink = _isPermalink(currentPathname);
|
|
const isPermalink = _isPermalink(currentPathname);
|
|
|
|
|
|
|
|
const { user } = req;
|
|
const { user } = req;
|
|
|
|
|
|
|
|
- // check whether the specified page path hits to multiple pages
|
|
|
|
|
if (!isPermalink) {
|
|
if (!isPermalink) {
|
|
|
|
|
+ // check redirects
|
|
|
|
|
+ const chains = await PageRedirect.retrievePageRedirectEndpoints(currentPathname);
|
|
|
|
|
+ if (chains != null) {
|
|
|
|
|
+ // overwrite currentPathname
|
|
|
|
|
+ currentPathname = chains.end.toPath;
|
|
|
|
|
+ props.currentPathname = currentPathname;
|
|
|
|
|
+ // set redirectFrom
|
|
|
|
|
+ props.redirectFrom = chains.start.fromPath;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // check whether the specified page path hits to multiple pages
|
|
|
const count = await Page.countByPathAndViewer(currentPathname, user, null, true);
|
|
const count = await Page.countByPathAndViewer(currentPathname, user, null, true);
|
|
|
if (count > 1) {
|
|
if (count > 1) {
|
|
|
throw new MultiplePagesHitsError(currentPathname);
|
|
throw new MultiplePagesHitsError(currentPathname);
|
|
@@ -414,9 +429,7 @@ async function injectRoutingInformation(context: GetServerSidePropsContext, prop
|
|
|
}
|
|
}
|
|
|
else if (page == null) {
|
|
else if (page == null) {
|
|
|
props.isNotFound = true;
|
|
props.isNotFound = true;
|
|
|
-
|
|
|
|
|
props.IsNotCreatable = !isCreatablePage(currentPathname);
|
|
props.IsNotCreatable = !isCreatablePage(currentPathname);
|
|
|
-
|
|
|
|
|
// check the page is forbidden or just does not exist.
|
|
// check the page is forbidden or just does not exist.
|
|
|
const count = isPermalink ? await Page.count({ _id: pageId }) : await Page.count({ path: currentPathname });
|
|
const count = isPermalink ? await Page.count({ _id: pageId }) : await Page.count({ path: currentPathname });
|
|
|
props.isForbidden = count > 0;
|
|
props.isForbidden = count > 0;
|
|
@@ -471,18 +484,18 @@ function injectServerConfigurations(context: GetServerSidePropsContext, props: P
|
|
|
// props.mathJax = configManager.getConfig('crowi', 'app:mathJax');
|
|
// props.mathJax = configManager.getConfig('crowi', 'app:mathJax');
|
|
|
// props.noCdn = configManager.getConfig('crowi', 'app:noCdn');
|
|
// props.noCdn = configManager.getConfig('crowi', 'app:noCdn');
|
|
|
// props.highlightJsStyle = configManager.getConfig('crowi', 'customize:highlightJsStyle');
|
|
// props.highlightJsStyle = configManager.getConfig('crowi', 'customize:highlightJsStyle');
|
|
|
- // props.isAllReplyShown = configManager.getConfig('crowi', 'customize:isAllReplyShown');
|
|
|
|
|
|
|
+ props.isAllReplyShown = configManager.getConfig('crowi', 'customize:isAllReplyShown');
|
|
|
// props.isContainerFluid = configManager.getConfig('crowi', 'customize:isContainerFluid');
|
|
// props.isContainerFluid = configManager.getConfig('crowi', 'customize:isContainerFluid');
|
|
|
props.isEnabledStaleNotification = configManager.getConfig('crowi', 'customize:isEnabledStaleNotification');
|
|
props.isEnabledStaleNotification = configManager.getConfig('crowi', 'customize:isEnabledStaleNotification');
|
|
|
// props.isEnabledLinebreaks = configManager.getConfig('markdown', 'markdown:isEnabledLinebreaks');
|
|
// props.isEnabledLinebreaks = configManager.getConfig('markdown', 'markdown:isEnabledLinebreaks');
|
|
|
// props.isEnabledLinebreaksInComments = configManager.getConfig('markdown', 'markdown:isEnabledLinebreaksInComments');
|
|
// props.isEnabledLinebreaksInComments = configManager.getConfig('markdown', 'markdown:isEnabledLinebreaksInComments');
|
|
|
props.disableLinkSharing = configManager.getConfig('crowi', 'security:disableLinkSharing');
|
|
props.disableLinkSharing = configManager.getConfig('crowi', 'security:disableLinkSharing');
|
|
|
- // props.editorConfig = {
|
|
|
|
|
- // upload: {
|
|
|
|
|
- // image: crowi.fileUploadService.getIsUploadable(),
|
|
|
|
|
- // file: crowi.fileUploadService.getFileUploadEnabled(),
|
|
|
|
|
- // },
|
|
|
|
|
- // };
|
|
|
|
|
|
|
+ props.editorConfig = {
|
|
|
|
|
+ upload: {
|
|
|
|
|
+ image: crowi.fileUploadService.getIsUploadable(),
|
|
|
|
|
+ file: crowi.fileUploadService.getFileUploadEnabled(),
|
|
|
|
|
+ },
|
|
|
|
|
+ };
|
|
|
// props.adminPreferredIndentSize = configManager.getConfig('markdown', 'markdown:adminPreferredIndentSize');
|
|
// props.adminPreferredIndentSize = configManager.getConfig('markdown', 'markdown:adminPreferredIndentSize');
|
|
|
// props.isIndentSizeForced = configManager.getConfig('markdown', 'markdown:isIndentSizeForced');
|
|
// props.isIndentSizeForced = configManager.getConfig('markdown', 'markdown:isIndentSizeForced');
|
|
|
|
|
|
|
@@ -491,7 +504,6 @@ function injectServerConfigurations(context: GetServerSidePropsContext, props: P
|
|
|
isEnabledLinebreaksInComments: configManager.getConfig('markdown', 'markdown:isEnabledLinebreaksInComments'),
|
|
isEnabledLinebreaksInComments: configManager.getConfig('markdown', 'markdown:isEnabledLinebreaksInComments'),
|
|
|
adminPreferredIndentSize: configManager.getConfig('markdown', 'markdown:adminPreferredIndentSize'),
|
|
adminPreferredIndentSize: configManager.getConfig('markdown', 'markdown:adminPreferredIndentSize'),
|
|
|
isIndentSizeForced: configManager.getConfig('markdown', 'markdown:isIndentSizeForced'),
|
|
isIndentSizeForced: configManager.getConfig('markdown', 'markdown:isIndentSizeForced'),
|
|
|
- isAllReplyShown: configManager.getConfig('crowi', 'customize:isAllReplyShown'),
|
|
|
|
|
|
|
|
|
|
plantumlUri: process.env.PLANTUML_URI ?? null,
|
|
plantumlUri: process.env.PLANTUML_URI ?? null,
|
|
|
blockdiagUri: process.env.BLOCKDIAG_URI ?? null,
|
|
blockdiagUri: process.env.BLOCKDIAG_URI ?? null,
|