add: add unit (per second) to lemonsqueezy after run, and sync to db table

This commit is contained in:
Karrix
2024-01-23 01:58:05 +08:00
parent 0ba1a6d1f0
commit f948fca78c
9 changed files with 1831 additions and 66 deletions
+61 -4
View File
@@ -1,6 +1,13 @@
import { parseDataSafe } from "../../../../lib/parseDataSafe";
import { db } from "@/db/db";
import { workflowRunOutputs, workflowRunsTable } from "@/db/schema";
import {
userUsageTable,
workflowRunOutputs,
workflowRunsTable,
workflowTable,
} from "@/db/schema";
import { getDuration } from "@/lib/getRelativeTime";
import { getSubscription, setUsage } from "@/server/linkToPricing";
import { eq } from "drizzle-orm";
import { NextResponse } from "next/server";
import { z } from "zod";
@@ -27,7 +34,6 @@ export async function POST(request: Request) {
data: output_data,
});
} else if (status) {
// console.log("status", status);
const workflow_run = await db
.update(workflowRunsTable)
.set({
@@ -35,8 +41,15 @@ export async function POST(request: Request) {
ended_at:
status === "success" || status === "failed" ? new Date() : null,
})
.where(eq(workflowRunsTable.id, run_id))
.returning();
.where(eq(workflowRunsTable.id, run_id));
// get data from workflowRunsTable
const userUsageTime = await importUserUsageData(run_id);
if (userUsageTime) {
// get the usage_time from userUsage
await addSubscriptionUnit(userUsageTime);
}
}
// const workflow_version = await db.query.workflowVersionTable.findFirst({
@@ -54,3 +67,47 @@ export async function POST(request: Request) {
}
);
}
async function addSubscriptionUnit(userUsageTime: number) {
const subscription = await getSubscription();
// round up userUsageTime to the nearest integer
const roundedUsageTime = Math.ceil(userUsageTime);
if (subscription) {
const usage = await setUsage(
subscription.data[0].attributes.first_subscription_item.id,
roundedUsageTime
);
}
}
async function importUserUsageData(run_id: string) {
const workflowRuns = await db.query.workflowRunsTable.findFirst({
where: eq(workflowRunsTable.id, run_id),
});
if (!workflowRuns?.workflow_id) return;
// find if workflowTable id column contains workflowRunsTable workflow_id
const workflow = await db.query.workflowTable.findFirst({
where: eq(workflowTable.id, workflowRuns.workflow_id),
});
if (workflowRuns?.ended_at === null || workflow == null) return;
const usageTime = parseFloat(
getDuration((workflowRuns?.ended_at - workflowRuns?.started_at) / 1000)
);
// add data to userUsageTable
const user_usage = await db.insert(userUsageTable).values({
user_id: workflow.user_id,
created_at: workflowRuns.ended_at,
org_id: workflow.org_id,
ended_at: workflowRuns.ended_at,
usage_time: usageTime,
});
return usageTime;
}
@@ -2,6 +2,7 @@ import { checkMarkIcon, crossMarkIcon } from "../const/Icon";
import { cn } from "@/lib/utils";
import {
getPricing,
getSubscription,
getSubscriptionItem,
getUsage,
setUsage,
@@ -89,12 +90,14 @@ export default function PricingList() {
// const currentUser = await getUserData();
const userUsage = await getUsage();
const userSubscription = await getSubscriptionItem();
const userSubscription = await getSubscription();
// const setUserUsage = await setUsage(236561, 10);
// console.log(currentUser);
console.log(userSubscription);
console.log(
userSubscription.data[0].attributes.first_subscription_item.id
);
})();
}, []);
+60 -60
View File
@@ -1,14 +1,14 @@
import { type InferSelectModel, relations } from "drizzle-orm";
import {
boolean,
integer,
jsonb,
pgEnum,
pgSchema,
text,
timestamp,
uuid,
real,
boolean,
integer,
jsonb,
pgEnum,
pgSchema,
text,
timestamp,
uuid,
real,
} from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { z } from "zod";
@@ -131,30 +131,30 @@ export const machinesStatus = pgEnum("machine_status", [
// We still want to keep the workflow run record.
export const workflowRunsTable = dbSchema.table("workflow_runs", {
id: uuid("id").primaryKey().defaultRandom().notNull(),
// when workflow version deleted, still want to keep this record
workflow_version_id: uuid("workflow_version_id").references(
() => workflowVersionTable.id,
{
onDelete: "set null",
},
),
workflow_inputs:
jsonb("workflow_inputs").$type<Record<string, string | number>>(),
workflow_id: uuid("workflow_id")
.notNull()
.references(() => workflowTable.id, {
onDelete: "cascade",
}),
// when machine deleted, still want to keep this record
machine_id: uuid("machine_id").references(() => machinesTable.id, {
onDelete: "set null",
}),
origin: workflowRunOrigin("origin").notNull().default("api"),
status: workflowRunStatus("status").notNull().default("not-started"),
ended_at: timestamp("ended_at"),
created_at: timestamp("created_at").defaultNow().notNull(),
started_at: timestamp("started_at"),
id: uuid("id").primaryKey().defaultRandom().notNull(),
// when workflow version deleted, still want to keep this record
workflow_version_id: uuid("workflow_version_id").references(
() => workflowVersionTable.id,
{
onDelete: "set null",
}
),
workflow_inputs:
jsonb("workflow_inputs").$type<Record<string, string | number>>(),
workflow_id: uuid("workflow_id")
.notNull()
.references(() => workflowTable.id, {
onDelete: "cascade",
}),
// when machine deleted, still want to keep this record
machine_id: uuid("machine_id").references(() => machinesTable.id, {
onDelete: "set null",
}),
origin: workflowRunOrigin("origin").notNull().default("api"),
status: workflowRunStatus("status").notNull().default("not-started"),
ended_at: timestamp("ended_at"),
created_at: timestamp("created_at").defaultNow().notNull(),
started_at: timestamp("started_at"),
});
export const workflowRunRelations = relations(
@@ -258,31 +258,31 @@ export const showcaseMediaNullable = z
.nullable();
export const deploymentsTable = dbSchema.table("deployments", {
id: uuid("id").primaryKey().defaultRandom().notNull(),
user_id: text("user_id")
.references(() => usersTable.id, {
onDelete: "cascade",
})
.notNull(),
org_id: text("org_id"),
workflow_version_id: uuid("workflow_version_id")
.notNull()
.references(() => workflowVersionTable.id),
workflow_id: uuid("workflow_id")
.notNull()
.references(() => workflowTable.id, {
onDelete: "cascade",
}),
machine_id: uuid("machine_id")
.notNull()
.references(() => machinesTable.id),
share_slug: text("share_slug").unique(),
description: text("description"),
showcase_media:
jsonb("showcase_media").$type<z.infer<typeof showcaseMedia>>(),
environment: deploymentEnvironment("environment").notNull(),
created_at: timestamp("created_at").defaultNow().notNull(),
updated_at: timestamp("updated_at").defaultNow().notNull(),
id: uuid("id").primaryKey().defaultRandom().notNull(),
user_id: text("user_id")
.references(() => usersTable.id, {
onDelete: "cascade",
})
.notNull(),
org_id: text("org_id"),
workflow_version_id: uuid("workflow_version_id")
.notNull()
.references(() => workflowVersionTable.id),
workflow_id: uuid("workflow_id")
.notNull()
.references(() => workflowTable.id, {
onDelete: "cascade",
}),
machine_id: uuid("machine_id")
.notNull()
.references(() => machinesTable.id),
share_slug: text("share_slug").unique(),
description: text("description"),
showcase_media:
jsonb("showcase_media").$type<z.infer<typeof showcaseMedia>>(),
environment: deploymentEnvironment("environment").notNull(),
created_at: timestamp("created_at").defaultNow().notNull(),
updated_at: timestamp("updated_at").defaultNow().notNull(),
});
export const publicShareDeployment = z.object({
@@ -334,15 +334,15 @@ export const apiKeyTable = dbSchema.table("api_keys", {
export const userUsageTable = dbSchema.table("user_usage", {
id: uuid("id").primaryKey().defaultRandom().notNull(),
org_id: text("org_id"),
user_id: text("user_id")
.references(() => usersTable.id, {
onDelete: "cascade",
})
.notNull(),
usage_time: real("usage_time").default(0).notNull(),
created_at: timestamp("created_at").defaultNow().notNull(),
updated_at: timestamp("updated_at").defaultNow().notNull(),
ended_at: timestamp("ended_at").defaultNow().notNull(),
});
export type UserType = InferSelectModel<typeof usersTable>;