mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-08 20:25:19 +02:00
fix: linting and document limit
This commit is contained in:
parent
0474a114d9
commit
c2897d7fbe
5 changed files with 193 additions and 194 deletions
|
|
@ -157,7 +157,7 @@ async def create_documents_file_upload(
|
|||
@router.get("/documents/", response_model=list[DocumentRead])
|
||||
async def read_documents(
|
||||
skip: int = 0,
|
||||
limit: int = 3000,
|
||||
limit: int = 300,
|
||||
search_space_id: int | None = None,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
user: User = Depends(current_active_user),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
"use client";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { toast } from "sonner";
|
||||
import { getAuthErrorDetails, shouldRetry, isNetworkError } from "@/lib/auth-errors";
|
||||
import { getAuthErrorDetails, isNetworkError, shouldRetry } from "@/lib/auth-errors";
|
||||
|
||||
export function LocalLoginForm() {
|
||||
const [username, setUsername] = useState("");
|
||||
|
|
@ -64,31 +64,30 @@ export function LocalLoginForm() {
|
|||
setTimeout(() => {
|
||||
router.push(`/auth/callback?token=${data.access_token}`);
|
||||
}, 500);
|
||||
|
||||
} catch (err) {
|
||||
// Use auth-errors utility to get proper error details
|
||||
let errorCode = "UNKNOWN_ERROR";
|
||||
|
||||
|
||||
if (err instanceof Error) {
|
||||
errorCode = err.message;
|
||||
} else if (isNetworkError(err)) {
|
||||
errorCode = "NETWORK_ERROR";
|
||||
}
|
||||
|
||||
|
||||
// Get detailed error information from auth-errors utility
|
||||
const errorDetails = getAuthErrorDetails(errorCode);
|
||||
|
||||
|
||||
// Set persistent error display
|
||||
setErrorTitle(errorDetails.title);
|
||||
setError(errorDetails.description);
|
||||
|
||||
|
||||
// Show error toast with conditional retry action
|
||||
const toastOptions: any = {
|
||||
id: loadingToast,
|
||||
description: errorDetails.description,
|
||||
duration: 6000,
|
||||
};
|
||||
|
||||
|
||||
// Add retry action if the error is retryable
|
||||
if (shouldRetry(errorCode)) {
|
||||
toastOptions.action = {
|
||||
|
|
@ -96,7 +95,7 @@ export function LocalLoginForm() {
|
|||
onClick: () => handleSubmit(e),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
toast.error(errorDetails.title, toastOptions);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
|
|
@ -136,9 +135,7 @@ export function LocalLoginForm() {
|
|||
</svg>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-semibold mb-1">{errorTitle}</p>
|
||||
<p className="text-sm text-red-700 dark:text-red-300">
|
||||
{error}
|
||||
</p>
|
||||
<p className="text-sm text-red-700 dark:text-red-300">{error}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
"use client";
|
||||
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { Suspense, useEffect, useState } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { toast } from "sonner";
|
||||
import { getAuthErrorDetails, shouldRetry } from "@/lib/auth-errors";
|
||||
import { Logo } from "@/components/Logo";
|
||||
import { getAuthErrorDetails, shouldRetry } from "@/lib/auth-errors";
|
||||
import { AmbientBackground } from "./AmbientBackground";
|
||||
import { GoogleLoginButton } from "./GoogleLoginButton";
|
||||
import { LocalLoginForm } from "./LocalLoginForm";
|
||||
|
|
@ -44,14 +44,14 @@ function LoginContent() {
|
|||
if (error) {
|
||||
// Use the auth-errors utility to get proper error details
|
||||
const errorDetails = getAuthErrorDetails(error);
|
||||
|
||||
|
||||
// If we have a custom message from URL params, use it as description
|
||||
const errorDescription = message ? decodeURIComponent(message) : errorDetails.description;
|
||||
|
||||
|
||||
// Set persistent error display
|
||||
setUrlError({
|
||||
title: errorDetails.title,
|
||||
message: errorDescription
|
||||
message: errorDescription,
|
||||
});
|
||||
|
||||
// Show toast with conditional retry action
|
||||
|
|
@ -59,7 +59,7 @@ function LoginContent() {
|
|||
description: errorDescription,
|
||||
duration: 6000,
|
||||
};
|
||||
|
||||
|
||||
// Add retry action if the error is retryable
|
||||
if (shouldRetry(error)) {
|
||||
toastOptions.action = {
|
||||
|
|
@ -67,7 +67,7 @@ function LoginContent() {
|
|||
onClick: () => window.location.reload(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
toast.error(errorDetails.title, toastOptions);
|
||||
}
|
||||
|
||||
|
|
@ -143,9 +143,7 @@ function LoginContent() {
|
|||
</svg>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-semibold mb-1">{urlError.title}</p>
|
||||
<p className="text-sm text-red-700 dark:text-red-300">
|
||||
{urlError.message}
|
||||
</p>
|
||||
<p className="text-sm text-red-700 dark:text-red-300">{urlError.message}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setUrlError(null)}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
"use client";
|
||||
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { toast } from "sonner";
|
||||
import { getAuthErrorDetails, shouldRetry, isNetworkError } from "@/lib/auth-errors";
|
||||
import { Logo } from "@/components/Logo";
|
||||
import { getAuthErrorDetails, isNetworkError, shouldRetry } from "@/lib/auth-errors";
|
||||
import { AmbientBackground } from "../login/AmbientBackground";
|
||||
|
||||
export default function RegisterPage() {
|
||||
|
|
@ -79,31 +79,30 @@ export default function RegisterPage() {
|
|||
setTimeout(() => {
|
||||
router.push("/login?registered=true");
|
||||
}, 500);
|
||||
|
||||
} catch (err) {
|
||||
// Use auth-errors utility to get proper error details
|
||||
let errorCode = "UNKNOWN_ERROR";
|
||||
|
||||
|
||||
if (err instanceof Error) {
|
||||
errorCode = err.message;
|
||||
} else if (isNetworkError(err)) {
|
||||
errorCode = "NETWORK_ERROR";
|
||||
}
|
||||
|
||||
|
||||
// Get detailed error information from auth-errors utility
|
||||
const errorDetails = getAuthErrorDetails(errorCode);
|
||||
|
||||
|
||||
// Set persistent error display
|
||||
setErrorTitle(errorDetails.title);
|
||||
setError(errorDetails.description);
|
||||
|
||||
|
||||
// Show error toast with conditional retry action
|
||||
const toastOptions: any = {
|
||||
id: loadingToast,
|
||||
description: errorDetails.description,
|
||||
duration: 6000,
|
||||
};
|
||||
|
||||
|
||||
// Add retry action if the error is retryable
|
||||
if (shouldRetry(errorCode)) {
|
||||
toastOptions.action = {
|
||||
|
|
@ -111,7 +110,7 @@ export default function RegisterPage() {
|
|||
onClick: () => handleSubmit(e),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
toast.error(errorDetails.title, toastOptions);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
|
|
@ -159,9 +158,7 @@ export default function RegisterPage() {
|
|||
</svg>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-semibold mb-1">{errorTitle}</p>
|
||||
<p className="text-sm text-red-700 dark:text-red-300">
|
||||
{error}
|
||||
</p>
|
||||
<p className="text-sm text-red-700 dark:text-red-300">{error}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
|
|
|
|||
|
|
@ -3,110 +3,110 @@
|
|||
*/
|
||||
|
||||
interface AuthErrorMapping {
|
||||
[key: string]: {
|
||||
title: string;
|
||||
description?: string;
|
||||
};
|
||||
[key: string]: {
|
||||
title: string;
|
||||
description?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const AUTH_ERROR_MESSAGES: AuthErrorMapping = {
|
||||
// Common HTTP errors
|
||||
"401": {
|
||||
title: "Invalid credentials",
|
||||
description: "Please check your email and password"
|
||||
},
|
||||
"403": {
|
||||
title: "Access denied",
|
||||
description: "Your account may be suspended or restricted"
|
||||
},
|
||||
"404": {
|
||||
title: "Account not found",
|
||||
description: "No account exists with this email address"
|
||||
},
|
||||
"409": {
|
||||
title: "Account conflict",
|
||||
description: "An account with this email already exists"
|
||||
},
|
||||
"429": {
|
||||
title: "Too many attempts",
|
||||
description: "Please wait before trying again"
|
||||
},
|
||||
"500": {
|
||||
title: "Server error",
|
||||
description: "Something went wrong on our end. Please try again"
|
||||
},
|
||||
"503": {
|
||||
title: "Service unavailable",
|
||||
description: "Login service is temporarily down"
|
||||
},
|
||||
// Common HTTP errors
|
||||
"401": {
|
||||
title: "Invalid credentials",
|
||||
description: "Please check your email and password",
|
||||
},
|
||||
"403": {
|
||||
title: "Access denied",
|
||||
description: "Your account may be suspended or restricted",
|
||||
},
|
||||
"404": {
|
||||
title: "Account not found",
|
||||
description: "No account exists with this email address",
|
||||
},
|
||||
"409": {
|
||||
title: "Account conflict",
|
||||
description: "An account with this email already exists",
|
||||
},
|
||||
"429": {
|
||||
title: "Too many attempts",
|
||||
description: "Please wait before trying again",
|
||||
},
|
||||
"500": {
|
||||
title: "Server error",
|
||||
description: "Something went wrong on our end. Please try again",
|
||||
},
|
||||
"503": {
|
||||
title: "Service unavailable",
|
||||
description: "Login service is temporarily down",
|
||||
},
|
||||
|
||||
// FastAPI specific errors
|
||||
"LOGIN_BAD_CREDENTIALS": {
|
||||
title: "Invalid credentials",
|
||||
description: "The email or password you entered is incorrect"
|
||||
},
|
||||
"LOGIN_USER_NOT_VERIFIED": {
|
||||
title: "Account not verified",
|
||||
description: "Please verify your email address before signing in"
|
||||
},
|
||||
"USER_INACTIVE": {
|
||||
title: "Account inactive",
|
||||
description: "Your account has been deactivated. Contact support for assistance"
|
||||
},
|
||||
"REGISTER_USER_ALREADY_EXISTS": {
|
||||
title: "Account already exists",
|
||||
description: "An account with this email address already exists"
|
||||
},
|
||||
"REGISTER_INVALID_PASSWORD": {
|
||||
title: "Invalid password",
|
||||
description: "Password must meet security requirements"
|
||||
},
|
||||
// FastAPI specific errors
|
||||
LOGIN_BAD_CREDENTIALS: {
|
||||
title: "Invalid credentials",
|
||||
description: "The email or password you entered is incorrect",
|
||||
},
|
||||
LOGIN_USER_NOT_VERIFIED: {
|
||||
title: "Account not verified",
|
||||
description: "Please verify your email address before signing in",
|
||||
},
|
||||
USER_INACTIVE: {
|
||||
title: "Account inactive",
|
||||
description: "Your account has been deactivated. Contact support for assistance",
|
||||
},
|
||||
REGISTER_USER_ALREADY_EXISTS: {
|
||||
title: "Account already exists",
|
||||
description: "An account with this email address already exists",
|
||||
},
|
||||
REGISTER_INVALID_PASSWORD: {
|
||||
title: "Invalid password",
|
||||
description: "Password must meet security requirements",
|
||||
},
|
||||
|
||||
// OAuth errors
|
||||
"access_denied": {
|
||||
title: "Access denied",
|
||||
description: "You denied access or cancelled the login process"
|
||||
},
|
||||
"invalid_request": {
|
||||
title: "Invalid request",
|
||||
description: "The login request was malformed"
|
||||
},
|
||||
"unauthorized_client": {
|
||||
title: "Authentication failed",
|
||||
description: "The application is not authorized to perform this action"
|
||||
},
|
||||
"unsupported_response_type": {
|
||||
title: "Login method not supported",
|
||||
description: "This login method is not currently available"
|
||||
},
|
||||
"invalid_scope": {
|
||||
title: "Invalid permissions",
|
||||
description: "The requested permissions are not valid"
|
||||
},
|
||||
"server_error": {
|
||||
title: "Server error",
|
||||
description: "An error occurred on the authentication server"
|
||||
},
|
||||
"temporarily_unavailable": {
|
||||
title: "Service unavailable",
|
||||
description: "Login is temporarily unavailable. Please try again later"
|
||||
},
|
||||
// OAuth errors
|
||||
access_denied: {
|
||||
title: "Access denied",
|
||||
description: "You denied access or cancelled the login process",
|
||||
},
|
||||
invalid_request: {
|
||||
title: "Invalid request",
|
||||
description: "The login request was malformed",
|
||||
},
|
||||
unauthorized_client: {
|
||||
title: "Authentication failed",
|
||||
description: "The application is not authorized to perform this action",
|
||||
},
|
||||
unsupported_response_type: {
|
||||
title: "Login method not supported",
|
||||
description: "This login method is not currently available",
|
||||
},
|
||||
invalid_scope: {
|
||||
title: "Invalid permissions",
|
||||
description: "The requested permissions are not valid",
|
||||
},
|
||||
server_error: {
|
||||
title: "Server error",
|
||||
description: "An error occurred on the authentication server",
|
||||
},
|
||||
temporarily_unavailable: {
|
||||
title: "Service unavailable",
|
||||
description: "Login is temporarily unavailable. Please try again later",
|
||||
},
|
||||
|
||||
// Network errors
|
||||
"NETWORK_ERROR": {
|
||||
title: "Connection failed",
|
||||
description: "Please check your internet connection and try again"
|
||||
},
|
||||
"TIMEOUT": {
|
||||
title: "Request timeout",
|
||||
description: "The login request took too long. Please try again"
|
||||
},
|
||||
// Network errors
|
||||
NETWORK_ERROR: {
|
||||
title: "Connection failed",
|
||||
description: "Please check your internet connection and try again",
|
||||
},
|
||||
TIMEOUT: {
|
||||
title: "Request timeout",
|
||||
description: "The login request took too long. Please try again",
|
||||
},
|
||||
|
||||
// Generic fallbacks
|
||||
"UNKNOWN_ERROR": {
|
||||
title: "Login failed",
|
||||
description: "An unexpected error occurred. Please try again"
|
||||
}
|
||||
// Generic fallbacks
|
||||
UNKNOWN_ERROR: {
|
||||
title: "Login failed",
|
||||
description: "An unexpected error occurred. Please try again",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -116,51 +116,51 @@ const AUTH_ERROR_MESSAGES: AuthErrorMapping = {
|
|||
* @returns Formatted error message
|
||||
*/
|
||||
export function getAuthErrorMessage(errorCode: string, returnTitle: boolean = false): string {
|
||||
if (!errorCode) {
|
||||
const fallback = AUTH_ERROR_MESSAGES.UNKNOWN_ERROR;
|
||||
return returnTitle ? fallback.title : fallback.description || fallback.title;
|
||||
}
|
||||
if (!errorCode) {
|
||||
const fallback = AUTH_ERROR_MESSAGES.UNKNOWN_ERROR;
|
||||
return returnTitle ? fallback.title : fallback.description || fallback.title;
|
||||
}
|
||||
|
||||
// Clean up the error code
|
||||
const cleanErrorCode = errorCode.trim().toUpperCase();
|
||||
|
||||
// Try exact match first
|
||||
let errorInfo = AUTH_ERROR_MESSAGES[cleanErrorCode] || AUTH_ERROR_MESSAGES[errorCode];
|
||||
|
||||
// Try partial matches for HTTP status codes
|
||||
if (!errorInfo) {
|
||||
const statusCodeMatch = errorCode.match(/(\d{3})/);
|
||||
if (statusCodeMatch) {
|
||||
errorInfo = AUTH_ERROR_MESSAGES[statusCodeMatch[1]];
|
||||
}
|
||||
}
|
||||
|
||||
// Try partial matches for common error patterns
|
||||
if (!errorInfo) {
|
||||
const patterns = [
|
||||
{ pattern: /credential|password|email/i, code: "LOGIN_BAD_CREDENTIALS" },
|
||||
{ pattern: /verify|verification/i, code: "LOGIN_USER_NOT_VERIFIED" },
|
||||
{ pattern: /inactive|disabled|suspended/i, code: "USER_INACTIVE" },
|
||||
{ pattern: /exists|duplicate/i, code: "REGISTER_USER_ALREADY_EXISTS" },
|
||||
{ pattern: /network|connection/i, code: "NETWORK_ERROR" },
|
||||
{ pattern: /timeout/i, code: "TIMEOUT" },
|
||||
{ pattern: /rate|limit|many/i, code: "429" },
|
||||
];
|
||||
// Clean up the error code
|
||||
const cleanErrorCode = errorCode.trim().toUpperCase();
|
||||
|
||||
for (const { pattern, code } of patterns) {
|
||||
if (pattern.test(errorCode)) {
|
||||
errorInfo = AUTH_ERROR_MESSAGES[code];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to unknown error
|
||||
if (!errorInfo) {
|
||||
errorInfo = AUTH_ERROR_MESSAGES.UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
return returnTitle ? errorInfo.title : errorInfo.description || errorInfo.title;
|
||||
// Try exact match first
|
||||
let errorInfo = AUTH_ERROR_MESSAGES[cleanErrorCode] || AUTH_ERROR_MESSAGES[errorCode];
|
||||
|
||||
// Try partial matches for HTTP status codes
|
||||
if (!errorInfo) {
|
||||
const statusCodeMatch = errorCode.match(/(\d{3})/);
|
||||
if (statusCodeMatch) {
|
||||
errorInfo = AUTH_ERROR_MESSAGES[statusCodeMatch[1]];
|
||||
}
|
||||
}
|
||||
|
||||
// Try partial matches for common error patterns
|
||||
if (!errorInfo) {
|
||||
const patterns = [
|
||||
{ pattern: /credential|password|email/i, code: "LOGIN_BAD_CREDENTIALS" },
|
||||
{ pattern: /verify|verification/i, code: "LOGIN_USER_NOT_VERIFIED" },
|
||||
{ pattern: /inactive|disabled|suspended/i, code: "USER_INACTIVE" },
|
||||
{ pattern: /exists|duplicate/i, code: "REGISTER_USER_ALREADY_EXISTS" },
|
||||
{ pattern: /network|connection/i, code: "NETWORK_ERROR" },
|
||||
{ pattern: /timeout/i, code: "TIMEOUT" },
|
||||
{ pattern: /rate|limit|many/i, code: "429" },
|
||||
];
|
||||
|
||||
for (const { pattern, code } of patterns) {
|
||||
if (pattern.test(errorCode)) {
|
||||
errorInfo = AUTH_ERROR_MESSAGES[code];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to unknown error
|
||||
if (!errorInfo) {
|
||||
errorInfo = AUTH_ERROR_MESSAGES.UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
return returnTitle ? errorInfo.title : errorInfo.description || errorInfo.title;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -169,10 +169,10 @@ export function getAuthErrorMessage(errorCode: string, returnTitle: boolean = fa
|
|||
* @returns Object with title and description
|
||||
*/
|
||||
export function getAuthErrorDetails(errorCode: string): { title: string; description: string } {
|
||||
const title = getAuthErrorMessage(errorCode, true);
|
||||
const description = getAuthErrorMessage(errorCode, false);
|
||||
|
||||
return { title, description };
|
||||
const title = getAuthErrorMessage(errorCode, true);
|
||||
const description = getAuthErrorMessage(errorCode, false);
|
||||
|
||||
return { title, description };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -181,15 +181,15 @@ export function getAuthErrorDetails(errorCode: string): { title: string; descrip
|
|||
* @returns True if it's a network error
|
||||
*/
|
||||
export function isNetworkError(error: unknown): boolean {
|
||||
if (error instanceof TypeError && error.message.includes('fetch')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof error === 'string') {
|
||||
return /network|connection|fetch|cors/i.test(error);
|
||||
}
|
||||
|
||||
return false;
|
||||
if (error instanceof TypeError && error.message.includes("fetch")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof error === "string") {
|
||||
return /network|connection|fetch|cors/i.test(error);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -198,10 +198,17 @@ export function isNetworkError(error: unknown): boolean {
|
|||
* @returns True if retry is recommended
|
||||
*/
|
||||
export function shouldRetry(errorCode: string): boolean {
|
||||
const retryableCodes = ['500', '503', '429', 'NETWORK_ERROR', 'TIMEOUT', 'server_error', 'temporarily_unavailable'];
|
||||
|
||||
return retryableCodes.some(code =>
|
||||
errorCode.includes(code) ||
|
||||
errorCode.toUpperCase().includes(code)
|
||||
);
|
||||
const retryableCodes = [
|
||||
"500",
|
||||
"503",
|
||||
"429",
|
||||
"NETWORK_ERROR",
|
||||
"TIMEOUT",
|
||||
"server_error",
|
||||
"temporarily_unavailable",
|
||||
];
|
||||
|
||||
return retryableCodes.some(
|
||||
(code) => errorCode.includes(code) || errorCode.toUpperCase().includes(code)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue