aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/lib/hooks
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-12-08 10:35:17 +0000
committerGitHub <noreply@github.com>2025-12-08 10:35:17 +0000
commit20d3761c89d566cf28ef1a22db14ad4f6eef2f17 (patch)
tree3a665014c098603f5e631970afc66cb17586d054 /apps/web/lib/hooks
parentb6c2dadd88540eb7181b1af157ea4577157763a5 (diff)
downloadkarakeep-20d3761c89d566cf28ef1a22db14ad4f6eef2f17.tar.zst
fix: check import quota before importing bookmarks (#2232)
* feat: check import quota before importing bookmarks Add quota validation before bookmark import to prevent users from exceeding their bookmark limits. The implementation includes: - New QuotaService.canImportBookmarks() method to check if user can import N bookmarks - New tRPC checkImportQuota procedure for client-side quota validation - Updated useBookmarkImport hook to parse files and check quota before import - Added error banner in ImportExport component to display quota errors - Optimized file parsing to avoid reading the file twice The quota check displays remaining bookmarks and provides clear error messages when the import would exceed the user's quota. * fix * some fixes --------- Co-authored-by: Claude <noreply@anthropic.com>
Diffstat (limited to 'apps/web/lib/hooks')
-rw-r--r--apps/web/lib/hooks/useBookmarkImport.ts43
1 files changed, 42 insertions, 1 deletions
diff --git a/apps/web/lib/hooks/useBookmarkImport.ts b/apps/web/lib/hooks/useBookmarkImport.ts
index d4ffda4e..0d9bbaaf 100644
--- a/apps/web/lib/hooks/useBookmarkImport.ts
+++ b/apps/web/lib/hooks/useBookmarkImport.ts
@@ -13,10 +13,12 @@ import {
useAddBookmarkToList,
useCreateBookmarkList,
} from "@karakeep/shared-react/hooks/lists";
+import { api } from "@karakeep/shared-react/trpc";
import {
importBookmarksFromFile,
ImportSource,
ParsedBookmark,
+ parseImportFile,
} from "@karakeep/shared/import-export";
import {
BookmarkTypes,
@@ -36,7 +38,9 @@ export function useBookmarkImport() {
const [importProgress, setImportProgress] = useState<ImportProgress | null>(
null,
);
+ const [quotaError, setQuotaError] = useState<string | null>(null);
+ const apiUtils = api.useUtils();
const { mutateAsync: createImportSession } = useCreateImportSession();
const { mutateAsync: createBookmark } = useCreateBookmarkWithPostHook();
const { mutateAsync: createList } = useCreateBookmarkList();
@@ -51,6 +55,36 @@ export function useBookmarkImport() {
file: File;
source: ImportSource;
}) => {
+ // Clear any previous quota error
+ setQuotaError(null);
+
+ // First, parse the file to count bookmarks
+ const textContent = await file.text();
+ const parsedBookmarks = parseImportFile(source, textContent);
+ const bookmarkCount = parsedBookmarks.length;
+
+ // Check quota before proceeding
+ if (bookmarkCount > 0) {
+ const quotaUsage =
+ await apiUtils.client.subscriptions.getQuotaUsage.query();
+
+ if (
+ !quotaUsage.bookmarks.unlimited &&
+ quotaUsage.bookmarks.quota !== null
+ ) {
+ const remaining =
+ quotaUsage.bookmarks.quota - quotaUsage.bookmarks.used;
+
+ if (remaining < bookmarkCount) {
+ const errorMsg = `Cannot import ${bookmarkCount} bookmarks. You have ${remaining} bookmark${remaining === 1 ? "" : "s"} remaining in your quota of ${quotaUsage.bookmarks.quota}.`;
+ setQuotaError(errorMsg);
+ throw new Error(errorMsg);
+ }
+ }
+ }
+
+ // Proceed with import if quota check passes
+ // Use a custom parser to avoid re-parsing the file
const result = await importBookmarksFromFile(
{
file,
@@ -122,7 +156,12 @@ export function useBookmarkImport() {
},
onProgress: (done, total) => setImportProgress({ done, total }),
},
- {},
+ {
+ // Use a custom parser to avoid re-parsing the file
+ parsers: {
+ [source]: () => parsedBookmarks,
+ },
+ },
);
return result;
},
@@ -158,6 +197,8 @@ export function useBookmarkImport() {
return {
importProgress,
+ quotaError,
+ clearQuotaError: () => setQuotaError(null),
runUploadBookmarkFile: uploadBookmarkFileMutation.mutateAsync,
isImporting: uploadBookmarkFileMutation.isPending,
};