feat(user): add bookmarkedTemplates column to user table and update related API methods

- Introduced a new column `bookmarkedTemplates` to the user table to store user-specific template bookmarks.
- Updated API methods to manage bookmarked templates, replacing the deprecated user_template_bookmarks table.
- Adjusted queries to retrieve and toggle bookmarks directly from the user record.
This commit is contained in:
Mauricio Siu
2026-04-03 21:50:12 -06:00
parent d8e15a60f0
commit 2eb460ba63
6 changed files with 8311 additions and 53 deletions

View File

@@ -1,12 +1,11 @@
import { paths } from "@dokploy/server/constants";
import { relations } from "drizzle-orm";
import { relations, sql } from "drizzle-orm";
import {
boolean,
integer,
pgTable,
text,
timestamp,
unique,
} from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
@@ -67,26 +66,11 @@ export const user = pgTable("user", {
stripeSubscriptionId: text("stripeSubscriptionId"),
serversQuantity: integer("serversQuantity").notNull().default(0),
trustedOrigins: text("trustedOrigins").array(),
bookmarkedTemplates: text("bookmarkedTemplates")
.array()
.default(sql`ARRAY[]::text[]`),
});
export const userTemplateBookmarks = pgTable(
"user_template_bookmarks",
{
id: text("id")
.notNull()
.primaryKey()
.$defaultFn(() => nanoid()),
userId: text("userId")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
templateId: text("templateId").notNull(),
createdAt: timestamp("createdAt").notNull().defaultNow(),
},
(table) => ({
uniqueUserTemplate: unique().on(table.userId, table.templateId),
}),
);
export const usersRelations = relations(user, ({ one, many }) => ({
account: one(account, {
fields: [user.id],
@@ -98,25 +82,15 @@ export const usersRelations = relations(user, ({ one, many }) => ({
ssoProviders: many(ssoProvider),
backups: many(backups),
schedules: many(schedules),
templateBookmarks: many(userTemplateBookmarks),
}));
export const userTemplateBookmarksRelations = relations(
userTemplateBookmarks,
({ one }) => ({
user: one(user, {
fields: [userTemplateBookmarks.userId],
references: [user.id],
}),
}),
);
const createSchema = createInsertSchema(user, {
id: z.string().min(1),
isRegistered: z.boolean().optional(),
}).omit({
role: true,
trustedOrigins: true,
bookmarkedTemplates: true,
isValidEnterpriseLicense: true,
});

View File

@@ -272,7 +272,7 @@ const parseSizeToBytes = (size: string): number => {
const match = size.match(/^([\d.]+)\s*([KMGT]?B)$/i);
if (!match) return 0;
const value = Number.parseFloat(match[1] as string);
const unit = match[2].toUpperCase();
const unit = (match[2] as string).toUpperCase();
const multipliers: Record<string, number> = {
B: 1,
KB: 1024,