updated verify max link logic
This commit is contained in:
parent
cfd33e9bd1
commit
b09de5a8af
|
@ -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: {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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) => ({
|
||||||
|
|
|
@ -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]
|
||||||
? {
|
? {
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
};
|
|
@ -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;
|
|
@ -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[]
|
||||||
|
|
Ŝarĝante…
Reference in New Issue