Refactor: Move license check to getServerSideProps for Admin Pages (#1726)

This commit is contained in:
Kiran K 2023-10-06 14:25:19 +05:30 committed by GitHub
parent 7c567bc034
commit 446dde1709
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 80 additions and 90 deletions

View File

@ -1,35 +1,11 @@
import useSWR from 'swr';
import { fetcher } from '@lib/ui/utils';
import EmptyState from './EmptyState';
import Loading from './Loading';
type Props = {
children: React.ReactNode;
};
const LicenseRequired = (props: Props) => {
const { children } = props;
const { data, isLoading } = useSWR<{ data: { status: boolean } }>('/api/admin/license', fetcher);
if (isLoading) {
return <Loading />;
}
const hasValidLicense = data?.data.status;
const LicenseRequired = () => {
return (
<>
{hasValidLicense ? (
children
) : (
<EmptyState
title='This is an Enterprise feature.'
description="Please add a valid license to use this feature. If you don't have a license, please contact BoxyHQ Support."
/>
)}
</>
<EmptyState
title='This is an Enterprise feature.'
description="Please add a valid license to use this feature. If you don't have a license, please contact BoxyHQ Support."
/>
);
};

View File

@ -1,4 +1,3 @@
import type { NextPage } from 'next';
import { useState, useEffect } from 'react';
import { useTranslation } from 'next-i18next';
import { ButtonPrimary } from '@components/ButtonPrimary';
@ -7,7 +6,7 @@ import type { ApiResponse } from 'types';
import type { AdminPortalBranding } from '@boxyhq/saml-jackson';
import LicenseRequired from '@components/LicenseRequired';
const Branding: NextPage = () => {
const Branding = ({ hasValidLicense }: { hasValidLicense: boolean }) => {
const { t } = useTranslation('common');
const [loading, setLoading] = useState(false);
const [branding, setBranding] = useState<AdminPortalBranding>({
@ -17,6 +16,10 @@ const Branding: NextPage = () => {
primaryColor: '',
});
useEffect(() => {
fetchSettings();
}, []);
// Fetch settings
const fetchSettings = async () => {
const rawResponse = await fetch('/api/admin/branding', {
@ -70,12 +73,12 @@ const Branding: NextPage = () => {
});
};
useEffect(() => {
fetchSettings();
}, []);
if (!hasValidLicense) {
return <LicenseRequired />;
}
return (
<LicenseRequired>
<>
<h2 className='mt-5 font-bold text-gray-700 md:text-xl'>{t('settings_branding_title')}</h2>
<p className='py-3 text-base leading-6 text-gray-800'>{t('settings_branding_description')}</p>
<div className='rounded border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-800'>
@ -144,7 +147,7 @@ const Branding: NextPage = () => {
</div>
</form>
</div>
</LicenseRequired>
</>
);
};

View File

@ -1,4 +1,3 @@
import type { NextPage } from 'next';
import type { AdminPortalBranding, SAMLFederationApp } from '@boxyhq/saml-jackson';
import { useEffect, useState } from 'react';
import useSWR from 'swr';
@ -7,7 +6,6 @@ import { useTranslation } from 'next-i18next';
import { fetcher } from '@lib/ui/utils';
import Loading from '@components/Loading';
import LicenseRequired from '@components/LicenseRequired';
import { errorToast, successToast } from '@components/Toaster';
import ConfirmationModal from '@components/ConfirmationModal';
import type { ApiError, ApiResponse, ApiSuccess } from 'types';
@ -15,8 +13,9 @@ import { LinkBack } from '@components/LinkBack';
import { ButtonPrimary } from '@components/ButtonPrimary';
import { ButtonDanger } from '@components/ButtonDanger';
import { LinkOutline } from '@components/LinkOutline';
import LicenseRequired from '@components/LicenseRequired';
const UpdateApp: NextPage = () => {
const UpdateApp = ({ hasValidLicense }: { hasValidLicense: boolean }) => {
const { t } = useTranslation('common');
const router = useRouter();
const [loading, setLoading] = useState(false);
@ -48,6 +47,10 @@ const UpdateApp: NextPage = () => {
}
}, [data]);
if (!hasValidLicense) {
return <LicenseRequired />;
}
if (error) {
errorToast(error.message);
return null;
@ -94,7 +97,7 @@ const UpdateApp: NextPage = () => {
};
return (
<LicenseRequired>
<>
<LinkBack href='/admin/federated-saml' />
<div className='mb-5 flex items-center justify-between'>
<h2 className='mt-5 font-bold text-gray-700 md:text-xl'>{t('saml_federation_update_app')}</h2>
@ -214,7 +217,7 @@ const UpdateApp: NextPage = () => {
</form>
</div>
<DeleteApp app={app} />
</LicenseRequired>
</>
);
};

View File

@ -1,5 +1,4 @@
import { useEffect } from 'react';
import type { NextPage } from 'next';
import type { SAMLFederationApp } from '@boxyhq/saml-jackson';
import useSWR from 'swr';
import { useTranslation } from 'next-i18next';
@ -7,7 +6,6 @@ import type { ApiError, ApiSuccess } from 'types';
import { fetcher } from '@lib/ui/utils';
import Loading from '@components/Loading';
import EmptyState from '@components/EmptyState';
import LicenseRequired from '@components/LicenseRequired';
import { LinkPrimary } from '@components/LinkPrimary';
import { pageLimit, Pagination, NoMoreResults } from '@components/Pagination';
import usePaginate from '@lib/ui/hooks/usePaginate';
@ -16,9 +14,10 @@ import { IconButton } from '@components/IconButton';
import PencilIcon from '@heroicons/react/24/outline/PencilIcon';
import PlusIcon from '@heroicons/react/24/outline/PlusIcon';
import router from 'next/router';
import Alert from '@components/Alert';
import LicenseRequired from '@components/LicenseRequired';
import { errorToast } from '@components/Toaster';
const AppsList: NextPage = () => {
const AppsList = ({ hasValidLicense }: { hasValidLicense: boolean }) => {
const { t } = useTranslation('common');
const { paginate, setPaginate, pageTokenMap, setPageTokenMap } = usePaginate();
@ -40,16 +39,17 @@ const AppsList: NextPage = () => {
}
}, [nextPageToken, paginate.offset]);
if (!hasValidLicense) {
return <LicenseRequired />;
}
if (isLoading) {
return <Loading />;
}
if (error) {
return (
<LicenseRequired>
<Alert type='error' message={error.message} />
</LicenseRequired>
);
errorToast(error.message);
return;
}
const apps = data?.data || [];
@ -57,7 +57,7 @@ const AppsList: NextPage = () => {
const noMoreResults = apps.length === 0 && paginate.offset > 0;
return (
<LicenseRequired>
<>
<div className='mb-5 flex items-center justify-between'>
<h2 className='font-bold text-gray-700 dark:text-white md:text-xl'>{t('saml_federation_apps')}</h2>
<div className='flex'>
@ -138,7 +138,7 @@ const AppsList: NextPage = () => {
/>
</>
)}
</LicenseRequired>
</>
);
};

View File

@ -4,12 +4,24 @@ import type { SAMLFederationAppWithMetadata } from '@boxyhq/saml-jackson';
import { Toaster } from '@components/Toaster';
import { InputWithCopyButton, CopyToClipboardButton } from '@components/ClipboardButton';
import { LinkOutline } from '@components/LinkOutline';
import LicenseRequired from '@components/LicenseRequired';
type Metadata = Pick<SAMLFederationAppWithMetadata, 'metadata'>['metadata'];
type MetadataProps = {
metadata: Pick<SAMLFederationAppWithMetadata, 'metadata'>['metadata'];
hasValidLicense: boolean;
};
const Metadata = ({ metadata }: { metadata: Metadata }) => {
const Metadata = ({ metadata, hasValidLicense }: MetadataProps) => {
const { t } = useTranslation('common');
if (!hasValidLicense) {
return (
<div className='p-10'>
<LicenseRequired />
</div>
);
}
return (
<>
<Toaster />

View File

@ -1,16 +1,15 @@
import type { NextPage } from 'next';
import { useState } from 'react';
import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import type { SAMLFederationApp } from '@boxyhq/saml-jackson';
import type { ApiResponse } from 'types';
import LicenseRequired from '@components/LicenseRequired';
import { LinkBack } from '@components/LinkBack';
import { ButtonPrimary } from '@components/ButtonPrimary';
import { errorToast, successToast } from '@components/Toaster';
import LicenseRequired from '@components/LicenseRequired';
const NewApp: NextPage = () => {
const NewApp = ({ hasValidLicense }: { hasValidLicense: boolean }) => {
const { t } = useTranslation('common');
const router = useRouter();
const [loading, setLoading] = useState(false);
@ -22,6 +21,10 @@ const NewApp: NextPage = () => {
entityId: '',
});
if (!hasValidLicense) {
return <LicenseRequired />;
}
const onSubmit = async (event: React.FormEvent) => {
event.preventDefault();
@ -60,7 +63,7 @@ const NewApp: NextPage = () => {
};
return (
<LicenseRequired>
<>
<LinkBack href='/admin/federated-saml' />
<h2 className='mb-5 mt-5 font-bold text-gray-700 md:text-xl'>{t('saml_federation_add_new_app')}</h2>
<div className='rounded border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-800'>
@ -138,7 +141,7 @@ const NewApp: NextPage = () => {
</div>
</form>
</div>
</LicenseRequired>
</>
);
};

View File

@ -488,6 +488,8 @@ export class App {
// Get the metadata for the app
public async getMetadata() {
await throwIfInvalidLicense(this.opts.boxyhqLicenseKey);
const { publicKey } = await getDefaultCertificate();
const ssoUrl = `${this.opts.externalUrl}/api/federated-saml/sso`;

View File

@ -1,11 +1,16 @@
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import jackson from '@lib/jackson';
export { default } from 'ee/federated-saml/pages/edit';
export async function getServerSideProps({ locale }) {
const { checkLicense } = await jackson();
return {
props: {
...(await serverSideTranslations(locale, ['common'])),
hasValidLicense: await checkLicense(),
},
};
}

View File

@ -1,11 +1,16 @@
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import jackson from '@lib/jackson';
export { default } from 'ee/federated-saml/pages/index';
export async function getServerSideProps({ locale }) {
const { checkLicense } = await jackson();
return {
props: {
...(await serverSideTranslations(locale, ['common'])),
hasValidLicense: await checkLicense(),
},
};
}

View File

@ -1,11 +1,16 @@
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import jackson from '@lib/jackson';
export { default } from 'ee/federated-saml/pages/new';
export async function getServerSideProps({ locale }) {
const { checkLicense } = await jackson();
return {
props: {
...(await serverSideTranslations(locale, ['common'])),
hasValidLicense: await checkLicense(),
},
};
}

View File

@ -1,11 +1,16 @@
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import jackson from '@lib/jackson';
export { default } from 'ee/branding/pages/index';
export async function getServerSideProps({ locale }) {
const { checkLicense } = await jackson();
return {
props: {
...(await serverSideTranslations(locale, ['common'])),
hasValidLicense: await checkLicense(),
},
};
}

View File

@ -1,30 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import jackson from '@lib/jackson';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method } = req;
try {
switch (method) {
case 'GET':
return await handleGET(req, res);
default:
res.setHeader('Allow', 'GET');
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } });
}
} catch (error: any) {
const { message, statusCode = 500 } = error;
return res.status(statusCode).json({ error: { message } });
}
}
// Check License key
const handleGET = async (req: NextApiRequest, res: NextApiResponse) => {
const { checkLicense } = await jackson();
const hasValidLicense = await checkLicense();
return res.status(200).json({ data: { status: hasValidLicense } });
};

View File

@ -4,7 +4,7 @@ import jackson from '@lib/jackson';
export { default } from 'ee/federated-saml/pages/metadata';
export async function getServerSideProps({ locale }) {
const { samlFederatedController } = await jackson();
const { samlFederatedController, checkLicense } = await jackson();
const metadata = await samlFederatedController.app.getMetadata();
@ -12,6 +12,7 @@ export async function getServerSideProps({ locale }) {
props: {
...(await serverSideTranslations(locale, ['common'])),
metadata,
hasValidLicense: await checkLicense(),
},
};
}