mirror of
https://github.com/lukevella/rallly.git
synced 2025-07-25 12:17:26 +02:00
♻️ Refactor licensing feature (#1831)
This commit is contained in:
parent
b4cbb629b7
commit
c9b5527432
9 changed files with 51 additions and 18 deletions
|
@ -2,8 +2,8 @@ import type { Stripe } from "@rallly/billing";
|
||||||
import { stripe } from "@rallly/billing";
|
import { stripe } from "@rallly/billing";
|
||||||
import { posthog } from "@rallly/posthog/server";
|
import { posthog } from "@rallly/posthog/server";
|
||||||
import { env } from "@/env";
|
import { env } from "@/env";
|
||||||
import { licensingClient } from "@/features/licensing/client";
|
|
||||||
import { licenseCheckoutMetadataSchema } from "@/features/licensing/schema";
|
import { licenseCheckoutMetadataSchema } from "@/features/licensing/schema";
|
||||||
|
import { licenseManager } from "@/features/licensing/server";
|
||||||
import { subscriptionCheckoutMetadataSchema } from "@/features/subscription/schema";
|
import { subscriptionCheckoutMetadataSchema } from "@/features/subscription/schema";
|
||||||
import { getEmailClient } from "@/utils/emails";
|
import { getEmailClient } from "@/utils/emails";
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ async function handleSelfHostedCheckoutSessionCompleted(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const license = await licensingClient.createLicense({
|
const license = await licenseManager.createLicense({
|
||||||
type: licenseType,
|
type: licenseType,
|
||||||
licenseeEmail: email,
|
licenseeEmail: email,
|
||||||
licenseeName: customerDetails.name ?? undefined,
|
licenseeName: customerDetails.name ?? undefined,
|
||||||
|
|
24
apps/web/src/features/licensing/actions.ts
Normal file
24
apps/web/src/features/licensing/actions.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
import { prisma } from "@rallly/database";
|
||||||
|
import { adminActionClient } from "@/features/safe-action/server";
|
||||||
|
|
||||||
|
export const removeInstanceLicenseAction = adminActionClient
|
||||||
|
.metadata({
|
||||||
|
actionName: "remove_instance_license",
|
||||||
|
})
|
||||||
|
.action(async () => {
|
||||||
|
try {
|
||||||
|
await prisma.instanceLicense.deleteMany();
|
||||||
|
} catch (_error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Failed to delete license",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "License deleted successfully",
|
||||||
|
};
|
||||||
|
});
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { prisma } from "@rallly/database";
|
import { prisma } from "@rallly/database";
|
||||||
import { rateLimit } from "@/features/rate-limit";
|
import { rateLimit } from "@/features/rate-limit";
|
||||||
import { licensingClient } from "../client";
|
import { licenseManager } from "../server";
|
||||||
|
|
||||||
export async function validateLicenseKey(key: string) {
|
export async function validateLicenseKey(key: string) {
|
||||||
const { success } = await rateLimit("validate_license_key", 10, "1 m");
|
const { success } = await rateLimit("validate_license_key", 10, "1 m");
|
||||||
|
@ -14,7 +14,7 @@ export async function validateLicenseKey(key: string) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = await licensingClient.validateLicenseKey({
|
const { data } = await licenseManager.validateLicenseKey({
|
||||||
key,
|
key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
import { env } from "@/env";
|
|
||||||
import { LicensingClient } from "./lib/licensing-client";
|
|
||||||
|
|
||||||
export const licensingClient = new LicensingClient({
|
|
||||||
apiUrl: env.LICENSE_API_URL,
|
|
||||||
authToken: env.LICENSE_API_AUTH_TOKEN,
|
|
||||||
});
|
|
|
@ -14,15 +14,15 @@ import {
|
||||||
} from "@rallly/ui/dialog";
|
} from "@rallly/ui/dialog";
|
||||||
import { Icon } from "@rallly/ui/icon";
|
import { Icon } from "@rallly/ui/icon";
|
||||||
import { XIcon } from "lucide-react";
|
import { XIcon } from "lucide-react";
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
import { useTransition } from "react";
|
import { useTransition } from "react";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { removeInstanceLicense } from "../mutations";
|
import { useSafeAction } from "@/features/safe-action/client";
|
||||||
|
import { removeInstanceLicenseAction } from "../actions";
|
||||||
|
|
||||||
export function RemoveLicenseButton() {
|
export function RemoveLicenseButton() {
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
const router = useRouter();
|
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
|
const removeInstanceLicense = useSafeAction(removeInstanceLicenseAction);
|
||||||
return (
|
return (
|
||||||
<Dialog {...dialog.dialogProps}>
|
<Dialog {...dialog.dialogProps}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
|
@ -56,8 +56,7 @@ export function RemoveLicenseButton() {
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
startTransition(async () => {
|
startTransition(async () => {
|
||||||
await removeInstanceLicense();
|
await removeInstanceLicense.executeAsync();
|
||||||
router.refresh();
|
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export { LicensingClient } from "./lib/licensing-client";
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
validateLicenseKeyResponseSchema,
|
validateLicenseKeyResponseSchema,
|
||||||
} from "../schema";
|
} from "../schema";
|
||||||
|
|
||||||
export class LicensingClient {
|
export class LicenseManager {
|
||||||
apiUrl: string;
|
apiUrl: string;
|
||||||
authToken?: string;
|
authToken?: string;
|
||||||
|
|
7
apps/web/src/features/licensing/server.ts
Normal file
7
apps/web/src/features/licensing/server.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { env } from "@/env";
|
||||||
|
import { LicenseManager } from "./lib/licensing-manager";
|
||||||
|
|
||||||
|
export const licenseManager = new LicenseManager({
|
||||||
|
apiUrl: env.LICENSE_API_URL,
|
||||||
|
authToken: env.LICENSE_API_AUTH_TOKEN,
|
||||||
|
});
|
|
@ -88,3 +88,14 @@ export const authActionClient = actionClient
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.use(posthogMiddleware);
|
.use(posthogMiddleware);
|
||||||
|
|
||||||
|
export const adminActionClient = authActionClient.use(async ({ ctx, next }) => {
|
||||||
|
if (ctx.user.role !== "admin") {
|
||||||
|
throw new ActionError({
|
||||||
|
code: "FORBIDDEN",
|
||||||
|
message: "You do not have permission to perform this action.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue