mirror of
https://github.com/docmost/docmost.git
synced 2026-05-07 06:23:06 +08:00
refactor
This commit is contained in:
@@ -623,7 +623,7 @@
|
|||||||
"Upgrade your plan": "Upgrade your plan",
|
"Upgrade your plan": "Upgrade your plan",
|
||||||
"Available with a paid license": "Available with a paid license",
|
"Available with a paid license": "Available with a paid license",
|
||||||
"Upgrade your license tier.": "Upgrade your license tier.",
|
"Upgrade your license tier.": "Upgrade your license tier.",
|
||||||
"AI features require a paid plan. Visit docmost.com for more information.": "AI features require a paid plan. Visit docmost.com for more information.",
|
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.": "AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.",
|
||||||
"AI & MCP": "AI & MCP",
|
"AI & MCP": "AI & MCP",
|
||||||
"AI": "AI",
|
"AI": "AI",
|
||||||
"MCP": "MCP",
|
"MCP": "MCP",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { isCloud } from "@/lib/config.ts";
|
import { isCloud } from "@/lib/config.ts";
|
||||||
import useUserRole from "@/hooks/use-user-role.tsx";
|
import useUserRole from "@/hooks/use-user-role.tsx";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom";
|
import { entitlementAtom } from "@/ee/entitlement/entitlement-atom";
|
||||||
import { Feature } from "@/ee/features";
|
import { Feature } from "@/ee/features";
|
||||||
import { useUpgradeLabel } from "@/ee/hooks/use-upgrade-label";
|
import { useUpgradeLabel } from "@/ee/hooks/use-upgrade-label";
|
||||||
import {
|
import {
|
||||||
@@ -136,7 +136,7 @@ export default function SettingsSidebar() {
|
|||||||
const [active, setActive] = useState(location.pathname);
|
const [active, setActive] = useState(location.pathname);
|
||||||
const { goBack } = useSettingsNavigation();
|
const { goBack } = useSettingsNavigation();
|
||||||
const { isAdmin, isOwner } = useUserRole();
|
const { isAdmin, isOwner } = useUserRole();
|
||||||
const [workspace] = useAtom(workspaceAtom);
|
const [entitlements] = useAtom(entitlementAtom);
|
||||||
const upgradeLabel = useUpgradeLabel();
|
const upgradeLabel = useUpgradeLabel();
|
||||||
const [mobileSidebarOpened] = useAtom(mobileSidebarAtom);
|
const [mobileSidebarOpened] = useAtom(mobileSidebarAtom);
|
||||||
const toggleMobileSidebar = useToggleSidebar(mobileSidebarAtom);
|
const toggleMobileSidebar = useToggleSidebar(mobileSidebarAtom);
|
||||||
@@ -146,7 +146,7 @@ export default function SettingsSidebar() {
|
|||||||
}, [location.pathname]);
|
}, [location.pathname]);
|
||||||
|
|
||||||
const hasFeature = (f: string) =>
|
const hasFeature = (f: string) =>
|
||||||
workspace?.features?.includes(f) ?? false;
|
entitlements?.features?.includes(f) ?? false;
|
||||||
|
|
||||||
const canShowItem = (item: DataItem) => {
|
const canShowItem = (item: DataItem) => {
|
||||||
if (item.env === "cloud" && !isCloud()) return false;
|
if (item.env === "cloud" && !isCloud()) return false;
|
||||||
@@ -191,7 +191,7 @@ export default function SettingsSidebar() {
|
|||||||
prefetchHandler = prefetchBilling;
|
prefetchHandler = prefetchBilling;
|
||||||
break;
|
break;
|
||||||
case "License & Edition":
|
case "License & Edition":
|
||||||
if (workspace?.hasLicenseKey) {
|
if (entitlements?.tier !== "free") {
|
||||||
prefetchHandler = prefetchLicense;
|
prefetchHandler = prefetchLicense;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export default function AiSettings() {
|
|||||||
mb="lg"
|
mb="lg"
|
||||||
>
|
>
|
||||||
{t(
|
{t(
|
||||||
"AI features require a paid plan. Visit docmost.com for more information.",
|
"AI is only available in the Docmost enterprise edition. Contact sales@docmost.com.",
|
||||||
)}
|
)}
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export default function SsoLogin() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(data.features?.length > 0) && (
|
{data.authProviders.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<Stack align="stretch" justify="center" gap="sm">
|
<Stack align="stretch" justify="center" gap="sm">
|
||||||
{data.authProviders.map((provider) => (
|
{data.authProviders.map((provider) => (
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { atom } from "jotai";
|
||||||
|
import type { Entitlements } from "./entitlement.types";
|
||||||
|
|
||||||
|
const initialValue: Entitlements | null = null;
|
||||||
|
export const entitlementAtom = atom(initialValue);
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import api from "@/lib/api-client";
|
||||||
|
import { Entitlements } from "./entitlement.types";
|
||||||
|
|
||||||
|
export async function getEntitlements(): Promise<Entitlements> {
|
||||||
|
const req = await api.post<Entitlements>("/workspace/entitlements");
|
||||||
|
return req.data as Entitlements;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export type Tier = "free" | "standard" | "business" | "enterprise";
|
||||||
|
|
||||||
|
export type Entitlements = {
|
||||||
|
cloud: boolean;
|
||||||
|
tier: Tier;
|
||||||
|
features: string[];
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { useQuery, UseQueryResult } from "@tanstack/react-query";
|
||||||
|
import { getEntitlements } from "./entitlement-service";
|
||||||
|
import { Entitlements } from "./entitlement.types";
|
||||||
|
|
||||||
|
export function useEntitlements(): UseQueryResult<Entitlements> {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["entitlements"],
|
||||||
|
queryFn: getEntitlements,
|
||||||
|
staleTime: 5 * 60 * 1000,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,12 +1,7 @@
|
|||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom";
|
import { entitlementAtom } from "@/ee/entitlement/entitlement-atom";
|
||||||
|
|
||||||
export const useHasFeature = (feature: string): boolean => {
|
export const useHasFeature = (feature: string): boolean => {
|
||||||
const [workspace] = useAtom(workspaceAtom);
|
const [entitlements] = useAtom(entitlementAtom);
|
||||||
return workspace?.features?.includes(feature) ?? false;
|
return entitlements?.features?.includes(feature) ?? false;
|
||||||
};
|
|
||||||
|
|
||||||
export const useHasAnyFeature = (): boolean => {
|
|
||||||
const [workspace] = useAtom(workspaceAtom);
|
|
||||||
return (workspace?.features?.length ?? 0) > 0;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom";
|
import { entitlementAtom } from "@/ee/entitlement/entitlement-atom";
|
||||||
import { isCloud } from "@/lib/config";
|
import { isCloud } from "@/lib/config";
|
||||||
|
|
||||||
export function useUpgradeLabel(): string {
|
export function useUpgradeLabel(): string {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [workspace] = useAtom(workspaceAtom);
|
const [entitlements] = useAtom(entitlementAtom);
|
||||||
|
|
||||||
if (!isCloud()) {
|
if (!isCloud()) {
|
||||||
return workspace?.hasLicenseKey
|
return entitlements != null && entitlements.tier !== "free"
|
||||||
? t("Upgrade your license tier.")
|
? t("Upgrade your license tier.")
|
||||||
: t("Available with a paid license");
|
: t("Available with a paid license");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,21 +7,22 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { useActivateMutation } from "@/ee/licence/queries/license-query.ts";
|
import { useActivateMutation } from "@/ee/licence/queries/license-query.ts";
|
||||||
import { useDisclosure } from "@mantine/hooks";
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
import { entitlementAtom } from "@/ee/entitlement/entitlement-atom";
|
||||||
import RemoveLicense from "@/ee/licence/components/remove-license.tsx";
|
import RemoveLicense from "@/ee/licence/components/remove-license.tsx";
|
||||||
|
|
||||||
export default function ActivateLicense() {
|
export default function ActivateLicense() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
const [workspace] = useAtom(workspaceAtom);
|
const [entitlements] = useAtom(entitlementAtom);
|
||||||
|
const hasLicense = entitlements != null && entitlements.tier !== "free";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group justify="flex-end" wrap="nowrap" mb="sm">
|
<Group justify="flex-end" wrap="nowrap" mb="sm">
|
||||||
<Button onClick={open}>
|
<Button onClick={open}>
|
||||||
{workspace?.hasLicenseKey ? t("Update license") : t("Add license")}
|
{hasLicense ? t("Update license") : t("Add license")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{workspace?.hasLicenseKey && <RemoveLicense />}
|
{hasLicense && <RemoveLicense />}
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
size="550"
|
size="550"
|
||||||
@@ -59,7 +60,7 @@ export function ActivateLicenseForm({ onClose }: ActivateLicenseFormProps) {
|
|||||||
async function handleSubmit(data: { licenseKey: string }) {
|
async function handleSubmit(data: { licenseKey: string }) {
|
||||||
await activateLicenseMutation.mutateAsync(data.licenseKey);
|
await activateLicenseMutation.mutateAsync(data.licenseKey);
|
||||||
form.reset();
|
form.reset();
|
||||||
onClose();
|
onClose?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ import ActivateLicenseForm from "@/ee/licence/components/activate-license-modal.
|
|||||||
import InstallationDetails from "@/ee/licence/components/installation-details.tsx";
|
import InstallationDetails from "@/ee/licence/components/installation-details.tsx";
|
||||||
import OssDetails from "@/ee/licence/components/oss-details.tsx";
|
import OssDetails from "@/ee/licence/components/oss-details.tsx";
|
||||||
import { useAtom } from "jotai/index";
|
import { useAtom } from "jotai/index";
|
||||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
import { entitlementAtom } from "@/ee/entitlement/entitlement-atom";
|
||||||
|
|
||||||
export default function License() {
|
export default function License() {
|
||||||
const [workspace] = useAtom(workspaceAtom);
|
const [entitlements] = useAtom(entitlementAtom);
|
||||||
|
const hasLicense = entitlements != null && entitlements.tier !== "free";
|
||||||
const { isAdmin } = useUserRole();
|
const { isAdmin } = useUserRole();
|
||||||
|
|
||||||
if (!isAdmin) {
|
if (!isAdmin) {
|
||||||
@@ -29,7 +30,7 @@ export default function License() {
|
|||||||
|
|
||||||
<InstallationDetails />
|
<InstallationDetails />
|
||||||
|
|
||||||
{workspace?.hasLicenseKey ? <LicenseDetails /> : <OssDetails />}
|
{hasLicense ? <LicenseDetails /> : <OssDetails />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export function useActivateMutation() {
|
|||||||
queryKey: ["license"],
|
queryKey: ["license"],
|
||||||
});
|
});
|
||||||
queryClient.refetchQueries({ queryKey: ["currentUser"] });
|
queryClient.refetchQueries({ queryKey: ["currentUser"] });
|
||||||
|
queryClient.refetchQueries({ queryKey: ["entitlements"] });
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
const errorMessage = error["response"]?.data?.message;
|
const errorMessage = error["response"]?.data?.message;
|
||||||
@@ -47,6 +48,7 @@ export function useRemoveLicenseMutation() {
|
|||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.refetchQueries({ queryKey: ["license"] });
|
queryClient.refetchQueries({ queryKey: ["license"] });
|
||||||
queryClient.refetchQueries({ queryKey: ["currentUser"] });
|
queryClient.refetchQueries({ queryKey: ["currentUser"] });
|
||||||
|
queryClient.refetchQueries({ queryKey: ["entitlements"] });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useAtom } from "jotai";
|
import { useAtom, useSetAtom } from "jotai";
|
||||||
import { currentUserAtom } from "@/features/user/atoms/current-user-atom";
|
import { currentUserAtom } from "@/features/user/atoms/current-user-atom";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import useCurrentUser from "@/features/user/hooks/use-current-user";
|
import useCurrentUser from "@/features/user/hooks/use-current-user";
|
||||||
@@ -11,10 +11,14 @@ import { useTreeSocket } from "@/features/websocket/use-tree-socket.ts";
|
|||||||
import { useNotificationSocket } from "@/features/notification/hooks/use-notification-socket.ts";
|
import { useNotificationSocket } from "@/features/notification/hooks/use-notification-socket.ts";
|
||||||
import { useCollabToken } from "@/features/auth/queries/auth-query.tsx";
|
import { useCollabToken } from "@/features/auth/queries/auth-query.tsx";
|
||||||
import { Error404 } from "@/components/ui/error-404.tsx";
|
import { Error404 } from "@/components/ui/error-404.tsx";
|
||||||
|
import { useEntitlements } from "@/ee/entitlement/use-entitlements";
|
||||||
|
import { entitlementAtom } from "@/ee/entitlement/entitlement-atom";
|
||||||
|
|
||||||
export function UserProvider({ children }: React.PropsWithChildren) {
|
export function UserProvider({ children }: React.PropsWithChildren) {
|
||||||
const [, setCurrentUser] = useAtom(currentUserAtom);
|
const [, setCurrentUser] = useAtom(currentUserAtom);
|
||||||
|
const setEntitlements = useSetAtom(entitlementAtom);
|
||||||
const { data, isLoading, error, isError } = useCurrentUser();
|
const { data, isLoading, error, isError } = useCurrentUser();
|
||||||
|
const { data: entitlements } = useEntitlements();
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const [, setSocket] = useAtom(socketAtom);
|
const [, setSocket] = useAtom(socketAtom);
|
||||||
// fetch collab token on load
|
// fetch collab token on load
|
||||||
@@ -56,6 +60,12 @@ export function UserProvider({ children }: React.PropsWithChildren) {
|
|||||||
}
|
}
|
||||||
}, [data, isLoading]);
|
}, [data, isLoading]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (entitlements) {
|
||||||
|
setEntitlements(entitlements);
|
||||||
|
}
|
||||||
|
}, [entitlements]);
|
||||||
|
|
||||||
if (isLoading) return <></>;
|
if (isLoading) return <></>;
|
||||||
|
|
||||||
if (isError && error?.["response"]?.status === 404) {
|
if (isError && error?.["response"]?.status === 404) {
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ export interface IWorkspace {
|
|||||||
emailDomains: string[];
|
emailDomains: string[];
|
||||||
memberCount?: number;
|
memberCount?: number;
|
||||||
plan?: string;
|
plan?: string;
|
||||||
hasLicenseKey?: boolean;
|
|
||||||
features?: string[];
|
|
||||||
enforceMfa?: boolean;
|
enforceMfa?: boolean;
|
||||||
aiSearch?: boolean;
|
aiSearch?: boolean;
|
||||||
generativeAi?: boolean;
|
generativeAi?: boolean;
|
||||||
@@ -85,7 +83,6 @@ export interface IPublicWorkspace {
|
|||||||
hostname: string;
|
hostname: string;
|
||||||
enforceSso: boolean;
|
enforceSso: boolean;
|
||||||
authProviders: IAuthProvider[];
|
authProviders: IAuthProvider[];
|
||||||
features?: string[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVersion {
|
export interface IVersion {
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
|
|||||||
import { AuthWorkspace } from '../../common/decorators/auth-workspace.decorator';
|
import { AuthWorkspace } from '../../common/decorators/auth-workspace.decorator';
|
||||||
import { User, Workspace } from '@docmost/db/types/entity.types';
|
import { User, Workspace } from '@docmost/db/types/entity.types';
|
||||||
import { WorkspaceRepo } from '@docmost/db/repos/workspace/workspace.repo';
|
import { WorkspaceRepo } from '@docmost/db/repos/workspace/workspace.repo';
|
||||||
import { LicenseCheckService } from '../../integrations/environment/license-check.service';
|
|
||||||
|
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Controller('users')
|
@Controller('users')
|
||||||
@@ -21,7 +20,6 @@ export class UserController {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly workspaceRepo: WorkspaceRepo,
|
private readonly workspaceRepo: WorkspaceRepo,
|
||||||
private readonly licenseCheckService: LicenseCheckService,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@@ -36,16 +34,9 @@ export class UserController {
|
|||||||
|
|
||||||
const { licenseKey, ...rest } = workspace;
|
const { licenseKey, ...rest } = workspace;
|
||||||
|
|
||||||
const features = this.licenseCheckService.resolveFeatures(
|
|
||||||
licenseKey,
|
|
||||||
rest.plan,
|
|
||||||
);
|
|
||||||
|
|
||||||
const workspaceInfo = {
|
const workspaceInfo = {
|
||||||
...rest,
|
...rest,
|
||||||
memberCount,
|
memberCount,
|
||||||
hasLicenseKey: Boolean(licenseKey),
|
|
||||||
features,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return { user: authUser, workspace: workspaceInfo };
|
return { user: authUser, workspace: workspaceInfo };
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ import {
|
|||||||
} from '../../casl/interfaces/workspace-ability.type';
|
} from '../../casl/interfaces/workspace-ability.type';
|
||||||
import { FastifyReply } from 'fastify';
|
import { FastifyReply } from 'fastify';
|
||||||
import { EnvironmentService } from '../../../integrations/environment/environment.service';
|
import { EnvironmentService } from '../../../integrations/environment/environment.service';
|
||||||
|
import { LicenseCheckService } from '../../../integrations/environment/license-check.service';
|
||||||
import { CheckHostnameDto } from '../dto/check-hostname.dto';
|
import { CheckHostnameDto } from '../dto/check-hostname.dto';
|
||||||
import { RemoveWorkspaceUserDto } from '../dto/remove-workspace-user.dto';
|
import { RemoveWorkspaceUserDto } from '../dto/remove-workspace-user.dto';
|
||||||
|
import { WorkspaceRepo } from '@docmost/db/repos/workspace/workspace.repo';
|
||||||
|
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Controller('workspace')
|
@Controller('workspace')
|
||||||
@@ -42,7 +44,9 @@ export class WorkspaceController {
|
|||||||
private readonly workspaceService: WorkspaceService,
|
private readonly workspaceService: WorkspaceService,
|
||||||
private readonly workspaceInvitationService: WorkspaceInvitationService,
|
private readonly workspaceInvitationService: WorkspaceInvitationService,
|
||||||
private readonly workspaceAbility: WorkspaceAbilityFactory,
|
private readonly workspaceAbility: WorkspaceAbilityFactory,
|
||||||
|
private readonly workspaceRepo: WorkspaceRepo,
|
||||||
private environmentService: EnvironmentService,
|
private environmentService: EnvironmentService,
|
||||||
|
private licenseCheckService: LicenseCheckService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Public()
|
@Public()
|
||||||
@@ -58,6 +62,23 @@ export class WorkspaceController {
|
|||||||
return this.workspaceService.getWorkspaceInfo(workspace.id);
|
return this.workspaceService.getWorkspaceInfo(workspace.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@Post('entitlements')
|
||||||
|
async getEntitlements(@AuthWorkspace() workspace: Workspace) {
|
||||||
|
let { licenseKey } = workspace;
|
||||||
|
const { plan } = workspace;
|
||||||
|
|
||||||
|
if (!licenseKey) {
|
||||||
|
licenseKey = await this.workspaceRepo.findLicenseKeyById(workspace.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
cloud: this.environmentService.isCloud(),
|
||||||
|
tier: this.licenseCheckService.resolveTier(licenseKey, plan),
|
||||||
|
features: this.licenseCheckService.resolveFeatures(licenseKey, plan),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post('update')
|
@Post('update')
|
||||||
async updateWorkspace(
|
async updateWorkspace(
|
||||||
|
|||||||
@@ -106,13 +106,9 @@ export class WorkspaceService {
|
|||||||
throw new NotFoundException('Workspace not found');
|
throw new NotFoundException('Workspace not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { licenseKey, ...rest } = workspace;
|
const { licenseKey, plan, ...rest } = workspace;
|
||||||
|
|
||||||
return {
|
return rest;
|
||||||
...rest,
|
|
||||||
hasLicenseKey: Boolean(licenseKey),
|
|
||||||
features: this.licenseCheckService.resolveFeatures(licenseKey, rest.plan),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(
|
async create(
|
||||||
@@ -337,6 +333,10 @@ export class WorkspaceService {
|
|||||||
.where('id', '=', workspaceId)
|
.where('id', '=', workspaceId)
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
|
|
||||||
|
if (!ws) {
|
||||||
|
throw new NotFoundException('Workspace not found');
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.licenseCheckService.hasFeature(ws.licenseKey, 'security:settings')) {
|
if (!this.licenseCheckService.hasFeature(ws.licenseKey, 'security:settings')) {
|
||||||
throw new ForbiddenException(
|
throw new ForbiddenException(
|
||||||
'This feature requires a valid license',
|
'This feature requires a valid license',
|
||||||
@@ -504,11 +504,7 @@ export class WorkspaceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { licenseKey, ...rest } = workspace;
|
const { licenseKey, ...rest } = workspace;
|
||||||
return {
|
return rest;
|
||||||
...rest,
|
|
||||||
hasLicenseKey: Boolean(licenseKey),
|
|
||||||
features: this.licenseCheckService.resolveFeatures(licenseKey, rest.plan),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getWorkspaceUsers(
|
async getWorkspaceUsers(
|
||||||
|
|||||||
@@ -69,4 +69,25 @@ export class LicenseCheckService {
|
|||||||
|
|
||||||
return this.getFeatures(licenseKey);
|
return this.getFeatures(licenseKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveTier(licenseKey: string, plan: string): string {
|
||||||
|
if (this.environmentService.isCloud()) {
|
||||||
|
return plan ?? 'standard';
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getLicenseType(licenseKey) ?? 'free';
|
||||||
|
}
|
||||||
|
|
||||||
|
private getLicenseType(licenseKey: string): string | null {
|
||||||
|
try {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
|
const LicenseModule = require('../../ee/licence/license.service');
|
||||||
|
const licenseService = this.moduleRef.get(LicenseModule.LicenseService, {
|
||||||
|
strict: false,
|
||||||
|
});
|
||||||
|
return licenseService.getLicenseType(licenseKey);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user