| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- import type { GetServerSideProps, GetServerSidePropsContext } from 'next';
- import type { ColorScheme, IUserHasId } from '@growi/core';
- import mongoose from 'mongoose';
- import type { CrowiRequest } from '~/interfaces/crowi-request';
- import { getGrowiVersion } from '~/utils/growi-version';
- import loggerFactory from '~/utils/logger';
- const logger = loggerFactory('growi:pages:common-props:commons');
- export type CommonInitialProps = {
- isNextjsRoutingTypeInitial: true;
- appTitle: string;
- siteUrl: string | undefined;
- siteUrlWithEmptyValueWarn: string;
- confidential: string;
- growiVersion: string;
- isDefaultLogo: boolean;
- customTitleTemplate: string;
- growiCloudUri: string | undefined;
- growiAppIdForGrowiCloud: number | undefined;
- forcedColorScheme?: ColorScheme;
- };
- export const getServerSideCommonInitialProps: GetServerSideProps<
- CommonInitialProps
- > = async (context: GetServerSidePropsContext) => {
- const req = context.req as CrowiRequest;
- const { crowi } = req;
- const {
- appService,
- configManager,
- attachmentService,
- customizeService,
- growiInfoService,
- } = crowi;
- const isCustomizedLogoUploaded = await attachmentService.isBrandLogoExist();
- const isDefaultLogo =
- crowi.configManager.getConfig('customize:isDefaultLogo') ||
- !isCustomizedLogoUploaded;
- const forcedColorScheme = crowi.customizeService.forcedColorScheme;
- return {
- props: {
- isNextjsRoutingTypeInitial: true,
- appTitle: appService.getAppTitle(),
- siteUrl: configManager.getConfig('app:siteUrl'),
- siteUrlWithEmptyValueWarn: growiInfoService.getSiteUrl(),
- confidential: appService.getAppConfidential() || '',
- growiVersion: getGrowiVersion(),
- isDefaultLogo,
- customTitleTemplate: customizeService.customTitleTemplate,
- growiCloudUri: configManager.getConfig('app:growiCloudUri'),
- growiAppIdForGrowiCloud: configManager.getConfig(
- 'app:growiAppIdForCloud',
- ),
- forcedColorScheme,
- },
- };
- };
- export const isCommonInitialProps = (
- props: unknown,
- ): props is CommonInitialProps => {
- if (typeof props !== 'object' || props === null) {
- logger.warn('isCommonInitialProps: props is not an object or is null');
- return false;
- }
- const p = props as Record<string, unknown>;
- // Essential properties validation
- if (p.isNextjsRoutingTypeInitial !== true) {
- logger.warn(
- 'isCommonInitialProps: isNextjsRoutingTypeInitial is not true',
- { isNextjsRoutingTypeInitial: p.isNextjsRoutingTypeInitial },
- );
- return false;
- }
- return true;
- };
- export type CommonEachProps = {
- currentPathname: string;
- nextjsRoutingPage?: string; // must be set by each page
- currentUser?: IUserHasId;
- isMaintenanceMode: boolean;
- redirectDestination?: string | null;
- };
- /**
- * Type guard for SameRouteEachProps validation
- * Lightweight validation for same-route navigation
- */
- function isValidCommonEachRouteProps(
- props: unknown,
- shouldContainNextjsRoutingPage = false,
- ): props is CommonEachProps {
- if (typeof props !== 'object' || props === null) {
- logger.warn(
- 'isValidCommonEachRouteProps: props is not an object or is null',
- );
- return false;
- }
- const p = props as Record<string, unknown>;
- // Essential properties validation
- if (shouldContainNextjsRoutingPage) {
- if (
- typeof p.nextjsRoutingPage !== 'string' &&
- p.nextjsRoutingPage !== undefined
- ) {
- logger.warn(
- 'isValidCommonEachRouteProps: nextjsRoutingPage is not a string or null',
- { nextjsRoutingPage: p.nextjsRoutingPage },
- );
- return false;
- }
- }
- if (typeof p.currentPathname !== 'string') {
- logger.warn(
- 'isValidCommonEachRouteProps: currentPathname is not a string',
- { currentPathname: p.currentPathname },
- );
- return false;
- }
- if (typeof p.isMaintenanceMode !== 'boolean') {
- logger.warn(
- 'isValidCommonEachRouteProps: isMaintenanceMode is not a boolean',
- { isMaintenanceMode: p.isMaintenanceMode },
- );
- return false;
- }
- return true;
- }
- export const getServerSideCommonEachProps = async (
- context: GetServerSidePropsContext,
- nextjsRoutingPage?: string,
- ): ReturnType<GetServerSideProps<CommonEachProps>> => {
- const req = context.req as CrowiRequest;
- const { crowi, user } = req;
- const { appService } = crowi;
- const url = new URL(context.resolvedUrl, 'http://example.com');
- const currentPathname = decodeURIComponent(url.pathname);
- const isMaintenanceMode = appService.isMaintenanceMode();
- let currentUser: IUserHasId | undefined;
- if (user != null) {
- const User = mongoose.model<IUserHasId>('User');
- const userData = await User.findById(user.id).populate({
- path: 'imageAttachment',
- select: 'filePathProxied',
- });
- currentUser = userData?.toObject();
- }
- // Redirect destination for page transition by next/link
- let redirectDestination: string | null = null;
- if (!crowi.aclService.isGuestAllowedToRead() && currentUser == null) {
- redirectDestination = '/login';
- } else if (!isMaintenanceMode && currentPathname === '/maintenance') {
- redirectDestination = '/';
- } else if (
- isMaintenanceMode &&
- !currentPathname.match('/admin/*') &&
- !(currentPathname === '/maintenance')
- ) {
- redirectDestination = '/maintenance';
- } else {
- redirectDestination = null;
- }
- const props = {
- currentPathname,
- nextjsRoutingPage,
- currentUser,
- isMaintenanceMode,
- redirectDestination,
- };
- const shouldContainNextjsRoutingPage = nextjsRoutingPage != null;
- if (!isValidCommonEachRouteProps(props, shouldContainNextjsRoutingPage)) {
- throw new Error('Invalid common each route props structure');
- }
- return { props };
- };
|