updated verify max link logic

This commit is contained in:
daniel31x13 2024-10-26 13:44:52 -04:00
parent cfd33e9bd1
commit b09de5a8af
9 changed files with 185 additions and 68 deletions

View File

@ -44,11 +44,6 @@ export default async function postCollection(
const newCollection = await prisma.collection.create({ const newCollection = await prisma.collection.create({
data: { data: {
owner: {
connect: {
id: userId,
},
},
name: collection.name.trim(), name: collection.name.trim(),
description: collection.description, description: collection.description,
color: collection.color, color: collection.color,
@ -61,6 +56,16 @@ export default async function postCollection(
}, },
} }
: undefined, : undefined,
owner: {
connect: {
id: userId,
},
},
createdBy: {
connect: {
id: userId,
},
},
}, },
include: { include: {
_count: { _count: {

View File

@ -6,8 +6,7 @@ import {
PostLinkSchema, PostLinkSchema,
PostLinkSchemaType, PostLinkSchemaType,
} from "@/lib/shared/schemaValidation"; } from "@/lib/shared/schemaValidation";
import { hasPassedLimit } from "../../verifyCapacity";
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
export default async function postLink( export default async function postLink(
body: PostLinkSchemaType, body: PostLinkSchemaType,
@ -59,19 +58,14 @@ export default async function postLink(
}; };
} }
const numberOfLinksTheUserHas = await prisma.link.count({ const hasTooManyLinks = await hasPassedLimit(userId, 1);
where: {
collection: {
ownerId: linkCollection.ownerId,
},
},
});
if (numberOfLinksTheUserHas > MAX_LINKS_PER_USER) if (hasTooManyLinks) {
return { return {
response: `Each collection owner can only have a maximum of ${MAX_LINKS_PER_USER} Links.`, response: `Your subscription have reached the maximum number of links allowed.`,
status: 400, status: 400,
}; };
}
const { title, headers } = await fetchTitleAndHeaders(link.url || ""); const { title, headers } = await fetchTitleAndHeaders(link.url || "");
@ -98,6 +92,11 @@ export default async function postLink(
name, name,
description: link.description, description: link.description,
type: linkType, type: linkType,
createdBy: {
connect: {
id: userId,
},
},
collection: { collection: {
connect: { connect: {
id: linkCollection.id, id: linkCollection.id,

View File

@ -2,8 +2,7 @@ import { prisma } from "@/lib/api/db";
import createFolder from "@/lib/api/storage/createFolder"; import createFolder from "@/lib/api/storage/createFolder";
import { JSDOM } from "jsdom"; import { JSDOM } from "jsdom";
import { parse, Node, Element, TextNode } from "himalaya"; import { parse, Node, Element, TextNode } from "himalaya";
import { hasPassedLimit } from "../../verifyCapacity";
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
export default async function importFromHTMLFile( export default async function importFromHTMLFile(
userId: number, userId: number,
@ -20,19 +19,14 @@ export default async function importFromHTMLFile(
const bookmarks = document.querySelectorAll("A"); const bookmarks = document.querySelectorAll("A");
const totalImports = bookmarks.length; const totalImports = bookmarks.length;
const numberOfLinksTheUserHas = await prisma.link.count({ const hasTooManyLinks = await hasPassedLimit(userId, totalImports);
where: {
collection: {
ownerId: userId,
},
},
});
if (totalImports + numberOfLinksTheUserHas > MAX_LINKS_PER_USER) if (hasTooManyLinks) {
return { return {
response: `Each collection owner can only have a maximum of ${MAX_LINKS_PER_USER} Links.`, response: `Your subscription have reached the maximum number of links allowed.`,
status: 400, status: 400,
}; };
}
const jsonData = parse(document.documentElement.outerHTML); const jsonData = parse(document.documentElement.outerHTML);
@ -183,6 +177,11 @@ const createCollection = async (
id: userId, id: userId,
}, },
}, },
createdBy: {
connect: {
id: userId,
},
},
}, },
}); });
@ -222,28 +221,27 @@ const createLink = async (
url, url,
description, description,
collectionId, collectionId,
createdById: userId,
tags: tags:
tags && tags[0] tags && tags[0]
? { ? {
connectOrCreate: tags.map((tag: string) => { connectOrCreate: tags.map((tag: string) => {
return ( return {
{ where: {
where: { name_ownerId: {
name_ownerId: {
name: tag.trim(),
ownerId: userId,
},
},
create: {
name: tag.trim(), name: tag.trim(),
owner: { ownerId: userId,
connect: { },
id: userId, },
}, create: {
name: tag.trim(),
owner: {
connect: {
id: userId,
}, },
}, },
} || undefined },
); };
}), }),
} }
: undefined, : undefined,

View File

@ -1,8 +1,7 @@
import { prisma } from "@/lib/api/db"; import { prisma } from "@/lib/api/db";
import { Backup } from "@/types/global"; import { Backup } from "@/types/global";
import createFolder from "@/lib/api/storage/createFolder"; import createFolder from "@/lib/api/storage/createFolder";
import { hasPassedLimit } from "../../verifyCapacity";
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
export default async function importFromLinkwarden( export default async function importFromLinkwarden(
userId: number, userId: number,
@ -16,19 +15,14 @@ export default async function importFromLinkwarden(
totalImports += collection.links.length; totalImports += collection.links.length;
}); });
const numberOfLinksTheUserHas = await prisma.link.count({ const hasTooManyLinks = await hasPassedLimit(userId, totalImports);
where: {
collection: {
ownerId: userId,
},
},
});
if (totalImports + numberOfLinksTheUserHas > MAX_LINKS_PER_USER) if (hasTooManyLinks) {
return { return {
response: `Each collection owner can only have a maximum of ${MAX_LINKS_PER_USER} Links.`, response: `Your subscription have reached the maximum number of links allowed.`,
status: 400, status: 400,
}; };
}
await prisma await prisma
.$transaction( .$transaction(
@ -47,6 +41,11 @@ export default async function importFromLinkwarden(
name: e.name?.trim().slice(0, 254), name: e.name?.trim().slice(0, 254),
description: e.description?.trim().slice(0, 254), description: e.description?.trim().slice(0, 254),
color: e.color?.trim().slice(0, 50), color: e.color?.trim().slice(0, 50),
createdBy: {
connect: {
id: userId,
},
},
}, },
}); });
@ -72,6 +71,11 @@ export default async function importFromLinkwarden(
id: newCollection.id, id: newCollection.id,
}, },
}, },
createdBy: {
connect: {
id: userId,
},
},
// Import Tags // Import Tags
tags: { tags: {
connectOrCreate: link.tags.map((tag) => ({ connectOrCreate: link.tags.map((tag) => ({

View File

@ -1,7 +1,6 @@
import { prisma } from "@/lib/api/db"; import { prisma } from "@/lib/api/db";
import createFolder from "@/lib/api/storage/createFolder"; import createFolder from "@/lib/api/storage/createFolder";
import { hasPassedLimit } from "../../verifyCapacity";
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
type WallabagBackup = { type WallabagBackup = {
is_archived: number; is_archived: number;
@ -36,19 +35,14 @@ export default async function importFromWallabag(
let totalImports = backup.length; let totalImports = backup.length;
const numberOfLinksTheUserHas = await prisma.link.count({ const hasTooManyLinks = await hasPassedLimit(userId, totalImports);
where: {
collection: {
ownerId: userId,
},
},
});
if (totalImports + numberOfLinksTheUserHas > MAX_LINKS_PER_USER) if (hasTooManyLinks) {
return { return {
response: `Each collection owner can only have a maximum of ${MAX_LINKS_PER_USER} Links.`, response: `Your subscription have reached the maximum number of links allowed.`,
status: 400, status: 400,
}; };
}
await prisma await prisma
.$transaction( .$transaction(
@ -61,6 +55,11 @@ export default async function importFromWallabag(
}, },
}, },
name: "Imports", name: "Imports",
createdBy: {
connect: {
id: userId,
},
},
}, },
}); });
@ -89,6 +88,11 @@ export default async function importFromWallabag(
id: newCollection.id, id: newCollection.id,
}, },
}, },
createdBy: {
connect: {
id: userId,
},
},
tags: tags:
link.tags && link.tags[0] link.tags && link.tags[0]
? { ? {

View File

@ -45,6 +45,7 @@ const setLinkCollection = async (link: PostLinkSchemaType, userId: number) => {
data: { data: {
name: link.collection.name.trim(), name: link.collection.name.trim(),
ownerId: userId, ownerId: userId,
createdById: userId,
}, },
}); });
@ -78,6 +79,7 @@ const setLinkCollection = async (link: PostLinkSchemaType, userId: number) => {
name: "Unorganized", name: "Unorganized",
ownerId: userId, ownerId: userId,
parentId: null, parentId: null,
createdById: userId,
}, },
}); });
} }

68
lib/api/verifyCapacity.ts Normal file
View File

@ -0,0 +1,68 @@
import { prisma } from "./db";
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
const stripeEnabled = process.env.NEXT_PUBLIC_STRIPE === "true";
export const hasPassedLimit = async (
userId: number,
numberOfImports: number
) => {
if (!stripeEnabled) {
return false;
}
const user = await prisma.user.findUnique({
where: { id: userId },
include: {
parentSubscription: true,
subscriptions: true,
},
});
if (!user) {
return true;
}
if (
user.parentSubscription ||
(user.subscriptions && user.subscriptions?.quantity > 1)
) {
const subscription = user.parentSubscription || user.subscriptions;
if (!subscription) {
return true;
}
// Calculate the total allowed links for the organization
const totalCapacity = subscription.quantity * MAX_LINKS_PER_USER;
const totalLinks = await prisma.link.count({
where: {
createdBy: {
OR: [
{
parentSubscriptionId: subscription.id || undefined,
},
{
subscriptions: {
id: subscription.id || undefined,
},
},
],
},
},
});
return totalCapacity - (numberOfImports + totalLinks) < 0;
} else {
const totalLinks = await prisma.link.count({
where: {
createdBy: {
id: userId,
},
},
});
return MAX_LINKS_PER_USER - (numberOfImports + totalLinks) < 0;
}
};

View File

@ -0,0 +1,37 @@
/*
Warnings:
- Made the column `createdById` on table `Collection` required. This step will fail if there are existing NULL values in that column.
- Made the column `createdById` on table `Link` required. This step will fail if there are existing NULL values in that column.
*/
-- Update the Link table to set the createdBy based on the Collection's ownerId.
UPDATE "Link"
SET "createdById" = (
SELECT "ownerId"
FROM "Collection"
WHERE "Collection"."id" = "Link"."collectionId"
);
-- Set createdBy to ownerId for existing records
UPDATE "Collection"
SET "createdById" = "ownerId";
-- DropForeignKey
ALTER TABLE "Collection" DROP CONSTRAINT "Collection_createdById_fkey";
-- DropForeignKey
ALTER TABLE "Link" DROP CONSTRAINT "Link_createdById_fkey";
-- AlterTable
ALTER TABLE "Collection" ALTER COLUMN "createdById" SET NOT NULL;
-- AlterTable
ALTER TABLE "Link" ALTER COLUMN "createdById" SET NOT NULL;
-- AddForeignKey
ALTER TABLE "Collection" ADD CONSTRAINT "Collection_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Link" ADD CONSTRAINT "Link_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -115,8 +115,8 @@ model Collection {
ownerId Int ownerId Int
members UsersAndCollections[] members UsersAndCollections[]
teamId Int? teamId Int?
createdBy User? @relation("CreatedCollections", fields: [createdById], references: [id]) createdBy User @relation("CreatedCollections", fields: [createdById], references: [id])
createdById Int? createdById Int
links Link[] links Link[]
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt updatedAt DateTime @default(now()) @updatedAt
@ -145,8 +145,8 @@ model Link {
type String @default("url") type String @default("url")
description String @default("") description String @default("")
pinnedBy User[] @relation("PinnedLinks") pinnedBy User[] @relation("PinnedLinks")
createdBy User? @relation("CreatedLinks", fields: [createdById], references: [id]) createdBy User @relation("CreatedLinks", fields: [createdById], references: [id])
createdById Int? createdById Int
collection Collection @relation(fields: [collectionId], references: [id]) collection Collection @relation(fields: [collectionId], references: [id])
collectionId Int collectionId Int
tags Tag[] tags Tag[]