Skip to content

Commit e68199f

Browse files
authored
set up Limits (#56)
* change connection/id/update to connection/id for updating * implement limits and bug fix * set up paddle payment * fix for docker producation
1 parent 3e89eb6 commit e68199f

41 files changed

Lines changed: 1439 additions & 402 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

@types/next-auth.d.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,17 @@ declare module "next-auth" {
1010
name?: string | null
1111
email?: string | null
1212
image?: string | null
13-
plan?: "Free" | "Basic" | "Pro" | "Business" | "Enterprise"
14-
volume?: number,
1513
};
1614
}
1715
interface User {
1816
id?: string
1917
name?: string | null
2018
email?: string | null
2119
image?: string | null
22-
plan?: "Free" | "Basic" | "Pro" | "Business" | "Enterprise"
23-
volume?: number,
2420

2521
}
2622
interface JWT {
2723
id?: string;
28-
plan?: "Free" | "Basic" | "Pro" | "Business" | "Enterprise"
29-
volume?: number,
3024
}
3125

3226
}

@types/plan.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

DataSource/Aws/setAwsConnection.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const setAWSConnection = async (formData: FormData) => {
1313
metadata: formData.get("metadata"),
1414
pageLimit: formData.get("pageLimit"),
1515
documentLimit: formData.get("documentLimit"),
16+
maxPages: formData.get("maxPages")
1617
})
1718

1819
if (!config.success) {
@@ -34,12 +35,14 @@ export const setAWSConnection = async (formData: FormData) => {
3435
metadata: config.data.metadata,
3536
isConfigSet: true,
3637
isSyncing: true,
38+
limitPages:config.data.pageLimit,
39+
limitFiles: config.data.documentLimit,
3740
}).where(eq(connections.id, config.data.connectionId))
3841

3942
return {
4043
connectionId: config.data.connectionId,
4144
service: "AWS",
42-
pageLimit: config.data.pageLimit,
45+
pageLimit: config.data.maxPages,
4346
fileLimit: config.data.documentLimit,
4447
metadata: config.data.metadata,
4548
files: [],

DataSource/DirectUpload/setDirectUploadConnection.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const directUploadConfig = z.object({
2020
return z.NEVER
2121
}
2222
}),
23-
pageLimit: z.string().nullable().transform((str, ctx): number | null => {
23+
pageLimit: z.string().transform((str, ctx): number | null => {
2424
try {
2525
if (str) return parseInt(str)
2626
return null
@@ -38,6 +38,14 @@ const directUploadConfig = z.object({
3838
return z.NEVER
3939
}
4040
}),
41+
maxPages: z.string().transform((str, ctx): number => {
42+
try {
43+
return parseInt(str)
44+
} catch (error) {
45+
ctx.addIssue({ code: 'invalid_date', message: "invalid page limit" })
46+
return z.NEVER
47+
}
48+
}),
4149
files: z.array(z.any().refine((file) => {
4250
return (
4351
file ||
@@ -76,7 +84,14 @@ const updateDirectUploadConfig = z.object({
7684
message: "Invalid File",
7785
})
7886
),
79-
87+
maxPages: z.string().transform((str, ctx): number => {
88+
try {
89+
return parseInt(str)
90+
} catch (error) {
91+
ctx.addIssue({ code: 'invalid_date', message: "invalid page limit" })
92+
return z.NEVER
93+
}
94+
}),
8095
links: z.array(z.string().min(5)),
8196
removedFiles: z.array(z.string().min(5))
8297
})
@@ -88,7 +103,8 @@ export const updateDirectUploadConnection = async (formData: FormData) => {
88103
metadata: formData.get("metadata") || "{}",
89104
files: formData.getAll("files") || [],
90105
links: formData.getAll("links") || [],
91-
removedFiles: formData.getAll("removedFiles") || []
106+
removedFiles: formData.getAll("removedFiles") || [],
107+
maxPages: formData.get("maxPages")
92108
})
93109

94110
if (!config.success) {
@@ -133,7 +149,7 @@ export const updateDirectUploadConnection = async (formData: FormData) => {
133149
metadata: config.data.metadata,
134150
files: await Promise.all(files),
135151
links: config.data.links,
136-
pageLimit: null,
152+
pageLimit: config.data.maxPages,
137153
fileLimit: null
138154
}
139155
}
@@ -146,6 +162,7 @@ export const setDirectUploadConnection = async (formData: FormData) => {
146162
metadata: formData.get("metadata") || "{}",
147163
pageLimit: formData.get("pageLimit"),
148164
documentLimit: formData.get("documentLimit"),
165+
maxPages: formData.get("maxPages"),
149166
files: formData.getAll("files"),
150167
links: formData.getAll("links"),
151168
})
@@ -173,6 +190,8 @@ export const setDirectUploadConnection = async (formData: FormData) => {
173190
metadata: metadata,
174191
isConfigSet: true,
175192
isSyncing: true,
193+
limitPages: pageLimit,
194+
limitFiles: documentLimit,
176195
}).returning({ id: connections.id })
177196

178197
const allFiles = files.map(async (file) => ({
@@ -189,7 +208,7 @@ export const setDirectUploadConnection = async (formData: FormData) => {
189208
metadata: metadata,
190209
files: await Promise.all(allFiles),
191210
links: links,
192-
pageLimit: pageLimit,
211+
pageLimit: config.data.maxPages,
193212
fileLimit: documentLimit
194213
}
195214
}

DataSource/Dropbox/setDropboxConnection.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ import { connectionConfig } from "../utils";
55

66

77
export const setDropboxConnection = async (formData: FormData) => {
8-
const config = connectionConfig.safeParse({
8+
const config = connectionConfig.safeParse({
99
connectionId: formData.get("connectionId"),
10-
identifier:formData.get("connectionName"),
10+
identifier: formData.get("connectionName"),
1111
folderName: formData.get("folderName"),
1212
folderId: formData.get("folderId"),
1313
metadata: formData.get("metadata"),
1414
pageLimit: formData.get("pageLimit"),
1515
documentLimit: formData.get("documentLimit"),
16+
maxPages: formData.get("maxPages"),
1617
})
1718

1819
if (!config.success) {
@@ -34,12 +35,14 @@ export const setDropboxConnection = async (formData: FormData) => {
3435
metadata: config.data.metadata,
3536
isConfigSet: true,
3637
isSyncing: true,
38+
limitFiles: config.data.documentLimit,
39+
limitPages: config.data.pageLimit,
3740
}).where(eq(connections.id, config.data.connectionId))
3841

3942
return {
4043
connectionId: config.data.connectionId,
4144
service: "DROPBOX",
42-
pageLimit: config.data.pageLimit,
45+
pageLimit: config.data.maxPages,
4346
fileLimit: config.data.documentLimit,
4447
metadata: config.data.metadata,
4548
files: [],

DataSource/GoogleDrive/setGoogleDriveConnection.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import { connectionConfig } from "../utils";
66
export const setGoogleDriveConnection = async (formData: FormData) => {
77
const config = connectionConfig.safeParse({
88
connectionId: formData.get("connectionId"),
9-
identifier:formData.get("connectionName"),
9+
identifier: formData.get("connectionName"),
1010
folderName: formData.get("folderName"),
1111
folderId: formData.get("folderId"),
1212
metadata: formData.get("metadata"),
1313
pageLimit: formData.get("pageLimit"),
1414
documentLimit: formData.get("documentLimit"),
15+
maxPages: formData.get("maxPages")
1516
})
1617

1718
if (!config.success) {
@@ -31,14 +32,16 @@ export const setGoogleDriveConnection = async (formData: FormData) => {
3132
folderId: config.data.folderId,
3233
} : undefined,
3334
metadata: config.data.metadata,
35+
limitPages: config.data.pageLimit,
36+
limitFiles: config.data.documentLimit,
3437
isConfigSet: true,
3538
isSyncing: true,
3639
}).where(eq(connections.id, config.data.connectionId))
3740

3841
return {
3942
connectionId: config.data.connectionId,
4043
service: "GOOGLE_DRIVE",
41-
pageLimit: config.data.pageLimit,
44+
pageLimit: config.data.maxPages,
4245
fileLimit: config.data.documentLimit,
4346
metadata: config.data.metadata,
4447
files: [],

DataSource/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ export const connectionConfig = z.object({
3030
return z.NEVER
3131
}
3232
}),
33+
maxPages: z.string().transform((str, ctx): number => {
34+
try {
35+
return parseInt(str)
36+
} catch (error) {
37+
ctx.addIssue({ code: 'invalid_date', message: "invalid page limit" })
38+
return z.NEVER
39+
}
40+
}),
3341
documentLimit: z.string().nullable().transform((str, ctx): number | null => {
3442
try {
3543
if (str) return parseInt(str)

actions/connctions/new/index.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
"use server"
2+
import { authOptions } from "@/auth";
3+
import { databaseDrizzle } from "@/db";
24
import { authDropbox } from "@/fileProcessors/connectors/dropbox";
35
import { authGoogleDrive } from "@/fileProcessors/connectors/googleDrive";
6+
import { Plans } from "@/lib/Plans";
47
import { fromErrorToFormState, toFormState } from "@/lib/zodErrorHandle";
8+
import { getServerSession } from "next-auth";
59
import { revalidatePath } from "next/cache";
610

711
type FormState = {
@@ -13,6 +17,32 @@ export async function newConnection(_: FormState, formData: FormData) {
1317
let redirectUrl: string;
1418

1519
try {
20+
const session = await getServerSession(authOptions)
21+
if (!session?.user?.id) throw new Error("forbidden");
22+
const user = await databaseDrizzle.query.users.findFirst({
23+
where: (u, ops) => ops.eq(u.id, session.user.id!),
24+
columns: {
25+
plan: true,
26+
},
27+
with: {
28+
connections: {
29+
columns: {
30+
id: true,
31+
}
32+
}
33+
}
34+
})
35+
if (!user) throw new Error("no such account")
36+
const plan = Plans[user.plan]
37+
const used = user.connections.length;
38+
if (used >= plan.connections) {
39+
throw new Error(
40+
`You’ve reached your connection limit for the ${user.plan.toLowerCase()} plan (` +
41+
`${used}/${plan.connections}). ` +
42+
`To add more connections, please upgrade your subscription.`
43+
);
44+
}
45+
1646
switch (connection) {
1747
case "google-drive":
1848
redirectUrl = authGoogleDrive()

actions/connctions/set/index.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"use server"
22
import { authOptions } from "@/auth";
3+
import { databaseDrizzle } from "@/db";
34
import { setConnectionToProcess } from "@/fileProcessors/connectors";
5+
import { Plans } from "@/lib/Plans";
46
import { fromErrorToFormState, toFormState } from "@/lib/zodErrorHandle";
57
import { addToProcessFilesQueue } from "@/workers/queues/jobs/processFiles.job";
68
import { getServerSession } from "next-auth";
@@ -12,8 +14,65 @@ type FormState = {
1214

1315
export async function setConnectionConfig(_: FormState, formData: FormData) {
1416
const session = await getServerSession(authOptions);
17+
const service = formData.get("service")
18+
const connectionId = formData.get("connectionId")
1519
try {
1620
if (!session?.user?.id) throw new Error("forbidden");
21+
const user = await databaseDrizzle.query.users.findFirst({
22+
where: (u, ops) => ops.eq(u.id, session.user.id!),
23+
columns: {
24+
plan: true,
25+
},
26+
with: {
27+
connections: {
28+
columns: {
29+
id: true,
30+
},
31+
with: {
32+
files: {
33+
columns: {
34+
totalPages: true,
35+
}
36+
}
37+
}
38+
}
39+
}
40+
})
41+
if (!user) throw new Error("no such account")
42+
const plan = Plans[user.plan]
43+
44+
if (service === "DIRECT_UPLOAD") {
45+
const used = user.connections.length;
46+
if (used >= plan.connections) {
47+
throw new Error(
48+
`You’ve reached your connection limit for the ${user.plan.toLowerCase()} plan (` +
49+
`${used}/${plan.connections}). ` +
50+
`To add more connections, please upgrade your subscription.`
51+
);
52+
}
53+
}
54+
55+
const pageProcessed = user.connections
56+
.filter(c => c.id !== connectionId)
57+
.flatMap(conn => conn.files || [])
58+
.reduce((sum, file) => sum + (file.totalPages || 0), 0);
59+
const pageLimit = formData.get("pageLimit")
60+
const remainingPages = plan.pages - pageProcessed;
61+
62+
if (pageLimit) {
63+
if (Number(pageLimit) > remainingPages) {
64+
throw new Error(
65+
`You requested to process ${pageLimit} pages, but your ` +
66+
`${user.plan.toLowerCase()} plan only allows ${remainingPages} ` +
67+
`more pages this billing period. Please lower the page count or upgrade your plan.`
68+
);
69+
} else {
70+
formData.set("maxPages", pageLimit)
71+
}
72+
} else {
73+
formData.set("maxPages", remainingPages.toString())
74+
}
75+
1776
formData.set("userId", session.user.id)
1877
const config = await setConnectionToProcess(formData)
1978
await addToProcessFilesQueue(config)

0 commit comments

Comments
 (0)