feat(licenses): update database schema and enhance license management

- Refactored migration script to import schema from the correct path.
- Updated package.json scripts for improved execution of migration and truncation tasks.
- Added new SQL file to define license-related types and table structure.
- Enhanced license management with new fields for Stripe customer and subscription IDs.
- Implemented license deactivation logic and improved error handling in license validation.
- Introduced health check endpoint for database connectivity verification.
This commit is contained in:
Mauricio Siu
2025-03-19 01:31:38 -06:00
parent 473d729416
commit 78682fa359
8 changed files with 199 additions and 34 deletions

View File

@@ -1,25 +1,29 @@
import { randomBytes } from "node:crypto";
import { db } from "../db";
import { licenses } from "../schema";
import { type License, licenses } from "../schema";
import { eq } from "drizzle-orm";
export const generateLicenseKey = () => {
return randomBytes(32).toString("hex");
};
export const createLicense = async ({
customerId,
productId,
type,
billingType,
email,
}: {
customerId: string;
interface CreateLicenseProps {
productId: string;
type: "basic" | "premium" | "business";
billingType: "monthly" | "annual";
email: string;
}) => {
stripeCustomerId: string;
stripeSubscriptionId: string;
}
export const createLicense = async ({
productId,
type,
billingType,
email,
stripeCustomerId,
stripeSubscriptionId,
}: CreateLicenseProps) => {
const licenseKey = `dokploy-${generateLicenseKey()}`;
const expiresAt = new Date();
expiresAt.setMonth(
@@ -29,13 +33,14 @@ export const createLicense = async ({
const license = await db
.insert(licenses)
.values({
customerId,
productId,
licenseKey,
type,
billingType,
expiresAt,
email,
stripeCustomerId,
stripeSubscriptionId,
})
.returning();
@@ -55,7 +60,10 @@ export const validateLicense = async (
}
if (license.status !== "active") {
return { isValid: false, error: "License is not active" };
return {
isValid: false,
error: `License is ${getLicenseStatus(license)}`,
};
}
if (new Date() > license.expiresAt) {
@@ -117,3 +125,36 @@ export const activateLicense = async (licenseKey: string, serverIp: string) => {
return updatedLicense[0];
};
export const deactivateLicense = async (stripeSubscriptionId: string) => {
const license = await db.query.licenses.findFirst({
where: eq(licenses.stripeSubscriptionId, stripeSubscriptionId),
});
if (!license) {
throw new Error("License not found");
}
await db
.update(licenses)
.set({ status: "cancelled" })
.where(eq(licenses.id, license.id));
};
export const getLicenseStatus = (license: License) => {
if (license.status === "active") {
return "active";
}
if (license.status === "expired") {
return "expired";
}
if (license.status === "cancelled") {
return "cancelled";
}
if (license.status === "payment_pending") {
return "pending payment";
}
};