refacto: error and error codes in services
This commit is contained in:
72
src/constants/errorCodes.ts
Normal file
72
src/constants/errorCodes.ts
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
export const ERROR_CODES = {
|
||||||
|
MONGODB: {
|
||||||
|
MISSING_URI: "MONGODB_MISSING_URI",
|
||||||
|
CONNECTION_FAILED: "MONGODB_CONNECTION_FAILED",
|
||||||
|
},
|
||||||
|
AUTH: {
|
||||||
|
UNAUTHENTICATED: "AUTH_UNAUTHENTICATED",
|
||||||
|
INVALID_CREDENTIALS: "AUTH_INVALID_CREDENTIALS",
|
||||||
|
PASSWORD_NOT_STRONG: "AUTH_PASSWORD_NOT_STRONG",
|
||||||
|
EMAIL_EXISTS: "AUTH_EMAIL_EXISTS",
|
||||||
|
INVALID_USER_DATA: "AUTH_INVALID_USER_DATA",
|
||||||
|
},
|
||||||
|
KOMGA: {
|
||||||
|
MISSING_CONFIG: "KOMGA_MISSING_CONFIG",
|
||||||
|
MISSING_CREDENTIALS: "KOMGA_MISSING_CREDENTIALS",
|
||||||
|
CONNECTION_ERROR: "KOMGA_CONNECTION_ERROR",
|
||||||
|
HTTP_ERROR: "KOMGA_HTTP_ERROR",
|
||||||
|
SERVER_UNREACHABLE: "KOMGA_SERVER_UNREACHABLE",
|
||||||
|
},
|
||||||
|
CONFIG: {
|
||||||
|
SAVE_ERROR: "CONFIG_SAVE_ERROR",
|
||||||
|
FETCH_ERROR: "CONFIG_FETCH_ERROR",
|
||||||
|
TTL_SAVE_ERROR: "CONFIG_TTL_SAVE_ERROR",
|
||||||
|
TTL_FETCH_ERROR: "CONFIG_TTL_FETCH_ERROR",
|
||||||
|
},
|
||||||
|
LIBRARY: {
|
||||||
|
NOT_FOUND: "LIBRARY_NOT_FOUND",
|
||||||
|
FETCH_ERROR: "LIBRARY_FETCH_ERROR",
|
||||||
|
},
|
||||||
|
SERIES: {
|
||||||
|
FETCH_ERROR: "SERIES_FETCH_ERROR",
|
||||||
|
NO_BOOKS_FOUND: "SERIES_NO_BOOKS_FOUND",
|
||||||
|
},
|
||||||
|
BOOK: {
|
||||||
|
NOT_FOUND: "BOOK_NOT_FOUND",
|
||||||
|
PROGRESS_UPDATE_ERROR: "BOOK_PROGRESS_UPDATE_ERROR",
|
||||||
|
PROGRESS_DELETE_ERROR: "BOOK_PROGRESS_DELETE_ERROR",
|
||||||
|
PAGES_FETCH_ERROR: "BOOK_PAGES_FETCH_ERROR",
|
||||||
|
DOWNLOAD_CANCELLED: "BOOK_DOWNLOAD_CANCELLED",
|
||||||
|
},
|
||||||
|
FAVORITE: {
|
||||||
|
ADD_ERROR: "FAVORITE_ADD_ERROR",
|
||||||
|
DELETE_ERROR: "FAVORITE_DELETE_ERROR",
|
||||||
|
FETCH_ERROR: "FAVORITE_FETCH_ERROR",
|
||||||
|
UPDATE_ERROR: "FAVORITE_UPDATE_ERROR",
|
||||||
|
},
|
||||||
|
PREFERENCES: {
|
||||||
|
FETCH_ERROR: "PREFERENCES_FETCH_ERROR",
|
||||||
|
UPDATE_ERROR: "PREFERENCES_UPDATE_ERROR",
|
||||||
|
CONTEXT_ERROR: "PREFERENCES_CONTEXT_ERROR",
|
||||||
|
},
|
||||||
|
CACHE: {
|
||||||
|
DELETE_ERROR: "CACHE_DELETE_ERROR",
|
||||||
|
},
|
||||||
|
UI: {
|
||||||
|
TABS_TRIGGER_ERROR: "UI_TABS_TRIGGER_ERROR",
|
||||||
|
TABS_CONTENT_ERROR: "UI_TABS_CONTENT_ERROR",
|
||||||
|
},
|
||||||
|
IMAGE: {
|
||||||
|
FETCH_ERROR: "IMAGE_FETCH_ERROR",
|
||||||
|
},
|
||||||
|
HOME: {
|
||||||
|
FETCH_ERROR: "HOME_FETCH_ERROR",
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
type ValueOf<T> = T[keyof T];
|
||||||
|
type ErrorCodeValues = ValueOf<{
|
||||||
|
[K in keyof typeof ERROR_CODES]: ValueOf<(typeof ERROR_CODES)[K]>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type ErrorCode = ErrorCodeValues;
|
||||||
69
src/constants/errorMessages.ts
Normal file
69
src/constants/errorMessages.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import { ERROR_CODES } from "./errorCodes";
|
||||||
|
|
||||||
|
export const ERROR_MESSAGES: Record<string, string> = {
|
||||||
|
// MongoDB
|
||||||
|
[ERROR_CODES.MONGODB.MISSING_URI]:
|
||||||
|
"Veuillez définir la variable d'environnement MONGODB_URI dans votre fichier .env",
|
||||||
|
[ERROR_CODES.MONGODB.CONNECTION_FAILED]: "La connexion à MongoDB a échoué",
|
||||||
|
|
||||||
|
// Auth
|
||||||
|
[ERROR_CODES.AUTH.UNAUTHENTICATED]: "Utilisateur non authentifié",
|
||||||
|
[ERROR_CODES.AUTH.INVALID_CREDENTIALS]: "Identifiants invalides",
|
||||||
|
[ERROR_CODES.AUTH.PASSWORD_NOT_STRONG]: "Le mot de passe n'est pas assez fort",
|
||||||
|
[ERROR_CODES.AUTH.EMAIL_EXISTS]: "Cette adresse email est déjà utilisée",
|
||||||
|
[ERROR_CODES.AUTH.INVALID_USER_DATA]: "Données utilisateur invalides",
|
||||||
|
|
||||||
|
// Komga
|
||||||
|
[ERROR_CODES.KOMGA.MISSING_CONFIG]: "Configuration Komga non trouvée",
|
||||||
|
[ERROR_CODES.KOMGA.MISSING_CREDENTIALS]: "Credentials Komga manquants",
|
||||||
|
[ERROR_CODES.KOMGA.CONNECTION_ERROR]: "Erreur lors du test de connexion",
|
||||||
|
[ERROR_CODES.KOMGA.HTTP_ERROR]: "Erreur HTTP: {status} {statusText}",
|
||||||
|
[ERROR_CODES.KOMGA.SERVER_UNREACHABLE]:
|
||||||
|
"Impossible de se connecter au serveur. Vérifiez l'URL et que le serveur est accessible.",
|
||||||
|
|
||||||
|
// Library
|
||||||
|
[ERROR_CODES.LIBRARY.NOT_FOUND]: "Bibliothèque {libraryId} non trouvée",
|
||||||
|
[ERROR_CODES.LIBRARY.FETCH_ERROR]: "Erreur lors de la récupération des bibliothèques",
|
||||||
|
|
||||||
|
// Series
|
||||||
|
[ERROR_CODES.SERIES.FETCH_ERROR]: "Erreur lors de la récupération des séries",
|
||||||
|
[ERROR_CODES.SERIES.NO_BOOKS_FOUND]: "Aucun livre trouvé dans la série",
|
||||||
|
|
||||||
|
// Book
|
||||||
|
[ERROR_CODES.BOOK.NOT_FOUND]: "Livre non trouvé",
|
||||||
|
[ERROR_CODES.BOOK.PROGRESS_UPDATE_ERROR]: "Erreur lors de la mise à jour de la progression",
|
||||||
|
[ERROR_CODES.BOOK.PROGRESS_DELETE_ERROR]: "Erreur lors de la suppression de la progression",
|
||||||
|
[ERROR_CODES.BOOK.PAGES_FETCH_ERROR]: "Erreur lors de la récupération des pages",
|
||||||
|
[ERROR_CODES.BOOK.DOWNLOAD_CANCELLED]: "Téléchargement annulé",
|
||||||
|
|
||||||
|
// Favorite
|
||||||
|
[ERROR_CODES.FAVORITE.ADD_ERROR]: "Erreur lors de l'ajout aux favoris",
|
||||||
|
[ERROR_CODES.FAVORITE.DELETE_ERROR]: "Erreur lors de la suppression des favoris",
|
||||||
|
[ERROR_CODES.FAVORITE.FETCH_ERROR]: "Erreur lors de la récupération des favoris",
|
||||||
|
[ERROR_CODES.FAVORITE.UPDATE_ERROR]: "Erreur lors de la modification des favoris",
|
||||||
|
|
||||||
|
// Preferences
|
||||||
|
[ERROR_CODES.PREFERENCES.FETCH_ERROR]: "Erreur lors de la récupération des préférences",
|
||||||
|
[ERROR_CODES.PREFERENCES.UPDATE_ERROR]: "Erreur lors de la mise à jour des préférences",
|
||||||
|
[ERROR_CODES.PREFERENCES.CONTEXT_ERROR]:
|
||||||
|
"usePreferences doit être utilisé dans un PreferencesProvider",
|
||||||
|
|
||||||
|
// Cache
|
||||||
|
[ERROR_CODES.CACHE.DELETE_ERROR]: "Erreur lors de la suppression du cache",
|
||||||
|
|
||||||
|
// UI
|
||||||
|
[ERROR_CODES.UI.TABS_TRIGGER_ERROR]: "TabsTrigger doit être utilisé dans un composant Tabs",
|
||||||
|
[ERROR_CODES.UI.TABS_CONTENT_ERROR]: "TabsContent doit être utilisé dans un composant Tabs",
|
||||||
|
|
||||||
|
// Image
|
||||||
|
[ERROR_CODES.IMAGE.FETCH_ERROR]: "Erreur lors de la récupération de l'image",
|
||||||
|
|
||||||
|
// Home
|
||||||
|
[ERROR_CODES.HOME.FETCH_ERROR]: "Erreur lors de la récupération des données de la page d'accueil",
|
||||||
|
|
||||||
|
// Config
|
||||||
|
[ERROR_CODES.CONFIG.SAVE_ERROR]: "Erreur lors de la sauvegarde de la configuration",
|
||||||
|
[ERROR_CODES.CONFIG.FETCH_ERROR]: "Erreur lors de la récupération de la configuration",
|
||||||
|
[ERROR_CODES.CONFIG.TTL_SAVE_ERROR]: "Erreur lors de la sauvegarde de la configuration TTL",
|
||||||
|
[ERROR_CODES.CONFIG.TTL_FETCH_ERROR]: "Erreur lors de la récupération de la configuration TTL",
|
||||||
|
} as const;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import mongoose from "mongoose";
|
import mongoose from "mongoose";
|
||||||
|
import { ERROR_CODES } from "../constants/errorCodes";
|
||||||
|
import { AppError } from "../utils/errors";
|
||||||
|
|
||||||
const MONGODB_URI = process.env.MONGODB_URI;
|
const MONGODB_URI = process.env.MONGODB_URI;
|
||||||
|
|
||||||
if (!MONGODB_URI) {
|
if (!MONGODB_URI) {
|
||||||
throw new Error(
|
throw new AppError(ERROR_CODES.MONGODB.MISSING_URI);
|
||||||
"Veuillez définir la variable d'environnement MONGODB_URI dans votre fichier .env"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MongooseCache {
|
interface MongooseCache {
|
||||||
@@ -42,7 +42,7 @@ async function connectDB(): Promise<typeof mongoose> {
|
|||||||
cached.conn = await cached.promise;
|
cached.conn = await cached.promise;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
cached.promise = null;
|
cached.promise = null;
|
||||||
throw e;
|
throw new AppError(ERROR_CODES.MONGODB.CONNECTION_FAILED, {}, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cached.conn;
|
return cached.conn;
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { cookies } from "next/headers";
|
|||||||
import connectDB from "@/lib/mongodb";
|
import connectDB from "@/lib/mongodb";
|
||||||
import { UserModel } from "@/lib/models/user.model";
|
import { UserModel } from "@/lib/models/user.model";
|
||||||
import bcrypt from "bcrypt";
|
import bcrypt from "bcrypt";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
interface UserData {
|
interface UserData {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -18,13 +20,13 @@ export class AuthServerService {
|
|||||||
|
|
||||||
//check if password is strong
|
//check if password is strong
|
||||||
if (!AuthServerService.isPasswordStrong(password)) {
|
if (!AuthServerService.isPasswordStrong(password)) {
|
||||||
throw new Error("PASSWORD_NOT_STRONG");
|
throw new AppError(ERROR_CODES.AUTH.PASSWORD_NOT_STRONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user already exists
|
// Check if user already exists
|
||||||
const existingUser = await UserModel.findOne({ email: email.toLowerCase() });
|
const existingUser = await UserModel.findOne({ email: email.toLowerCase() });
|
||||||
if (existingUser) {
|
if (existingUser) {
|
||||||
throw new Error("EMAIL_EXISTS");
|
throw new AppError(ERROR_CODES.AUTH.EMAIL_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash password
|
// Hash password
|
||||||
@@ -98,13 +100,15 @@ export class AuthServerService {
|
|||||||
await connectDB();
|
await connectDB();
|
||||||
|
|
||||||
const user = await UserModel.findOne({ email: email.toLowerCase() });
|
const user = await UserModel.findOne({ email: email.toLowerCase() });
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error("INVALID_CREDENTIALS");
|
throw new AppError(ERROR_CODES.AUTH.INVALID_CREDENTIALS);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPasswordValid = await bcrypt.compare(password, user.password);
|
const isPasswordValid = await bcrypt.compare(password, user.password);
|
||||||
|
|
||||||
if (!isPasswordValid) {
|
if (!isPasswordValid) {
|
||||||
throw new Error("INVALID_CREDENTIALS");
|
throw new AppError(ERROR_CODES.AUTH.INVALID_CREDENTIALS);
|
||||||
}
|
}
|
||||||
|
|
||||||
const userData: UserData = {
|
const userData: UserData = {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { AuthConfig } from "@/types/auth";
|
|||||||
import { getServerCacheService } from "./server-cache.service";
|
import { getServerCacheService } from "./server-cache.service";
|
||||||
import { ConfigDBService } from "./config-db.service";
|
import { ConfigDBService } from "./config-db.service";
|
||||||
import { DebugService } from "./debug.service";
|
import { DebugService } from "./debug.service";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
// Types de cache disponibles
|
// Types de cache disponibles
|
||||||
export type CacheType = "DEFAULT" | "HOME" | "LIBRARIES" | "SERIES" | "BOOKS" | "IMAGES";
|
export type CacheType = "DEFAULT" | "HOME" | "LIBRARIES" | "SERIES" | "BOOKS" | "IMAGES";
|
||||||
@@ -25,13 +27,13 @@ export abstract class BaseApiService {
|
|||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur lors de la récupération de la configuration:", error);
|
console.error("Erreur lors de la récupération de la configuration:", error);
|
||||||
throw new Error("Configuration Komga non trouvée");
|
throw new AppError(ERROR_CODES.KOMGA.MISSING_CONFIG, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static getAuthHeaders(config: AuthConfig): Headers {
|
protected static getAuthHeaders(config: AuthConfig): Headers {
|
||||||
if (!config.authHeader) {
|
if (!config.authHeader) {
|
||||||
throw new Error("Credentials Komga manquants");
|
throw new AppError(ERROR_CODES.KOMGA.MISSING_CREDENTIALS);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Headers({
|
return new Headers({
|
||||||
@@ -56,16 +58,6 @@ export abstract class BaseApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static handleError(error: unknown, defaultMessage: string): never {
|
|
||||||
console.error("API Error:", error);
|
|
||||||
|
|
||||||
if (error instanceof Error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(defaultMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static buildUrl(
|
protected static buildUrl(
|
||||||
config: AuthConfig,
|
config: AuthConfig,
|
||||||
path: string,
|
path: string,
|
||||||
@@ -114,7 +106,10 @@ export abstract class BaseApiService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Erreur HTTP: ${response.status} ${response.statusText}`);
|
throw new AppError(ERROR_CODES.KOMGA.HTTP_ERROR, {
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return options.isImage ? response : response.json();
|
return options.isImage ? response : response.json();
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { BaseApiService } from "./base-api.service";
|
|||||||
import { KomgaBook } from "@/types/komga";
|
import { KomgaBook } from "@/types/komga";
|
||||||
import { ImageService } from "./image.service";
|
import { ImageService } from "./image.service";
|
||||||
import { PreferencesService } from "./preferences.service";
|
import { PreferencesService } from "./preferences.service";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
export class BookService extends BaseApiService {
|
export class BookService extends BaseApiService {
|
||||||
static async getBook(bookId: string): Promise<{ book: KomgaBook; pages: number[] }> {
|
static async getBook(bookId: string): Promise<{ book: KomgaBook; pages: number[] }> {
|
||||||
@@ -25,7 +27,7 @@ export class BookService extends BaseApiService {
|
|||||||
"BOOKS"
|
"BOOKS"
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.handleError(error, "Impossible de récupérer le tome");
|
throw new AppError(ERROR_CODES.BOOK.NOT_FOUND, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,10 +49,13 @@ export class BookService extends BaseApiService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("Erreur lors de la mise à jour de la progression");
|
throw new AppError(ERROR_CODES.BOOK.PROGRESS_UPDATE_ERROR);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.handleError(error, "Impossible de mettre à jour la progression");
|
if (error instanceof AppError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new AppError(ERROR_CODES.BOOK.PROGRESS_UPDATE_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,10 +72,13 @@ export class BookService extends BaseApiService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("Erreur lors de la suppression de la progression");
|
throw new AppError(ERROR_CODES.BOOK.PROGRESS_DELETE_ERROR);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.handleError(error, "Impossible de supprimer la progression");
|
if (error instanceof AppError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new AppError(ERROR_CODES.BOOK.PROGRESS_DELETE_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +96,7 @@ export class BookService extends BaseApiService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw this.handleError(error, "Impossible de récupérer la page");
|
throw new AppError(ERROR_CODES.BOOK.PAGES_FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +119,7 @@ export class BookService extends BaseApiService {
|
|||||||
// Sinon, récupérer la première page
|
// Sinon, récupérer la première page
|
||||||
return this.getPage(bookId, 1);
|
return this.getPage(bookId, 1);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw this.handleError(error, "Impossible de récupérer la couverture");
|
throw new AppError(ERROR_CODES.BOOK.PAGES_FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +143,7 @@ export class BookService extends BaseApiService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw this.handleError(error, "Impossible de récupérer la miniature de la page");
|
throw new AppError(ERROR_CODES.BOOK.PAGES_FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { KomgaConfig } from "@/lib/models/config.model";
|
|||||||
import { TTLConfig } from "@/lib/models/ttl-config.model";
|
import { TTLConfig } from "@/lib/models/ttl-config.model";
|
||||||
import { DebugService } from "./debug.service";
|
import { DebugService } from "./debug.service";
|
||||||
import { AuthServerService } from "./auth-server.service";
|
import { AuthServerService } from "./auth-server.service";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -29,12 +31,13 @@ export class ConfigDBService {
|
|||||||
private static getCurrentUser(): User {
|
private static getCurrentUser(): User {
|
||||||
const user = AuthServerService.getCurrentUser();
|
const user = AuthServerService.getCurrentUser();
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error("Utilisateur non authentifié");
|
throw new AppError(ERROR_CODES.AUTH.UNAUTHENTICATED);
|
||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async saveConfig(data: KomgaConfigData) {
|
static async saveConfig(data: KomgaConfigData) {
|
||||||
|
try {
|
||||||
const user = this.getCurrentUser();
|
const user = this.getCurrentUser();
|
||||||
await connectDB();
|
await connectDB();
|
||||||
|
|
||||||
@@ -53,9 +56,16 @@ export class ConfigDBService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof AppError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new AppError(ERROR_CODES.CONFIG.SAVE_ERROR, {}, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getConfig() {
|
static async getConfig() {
|
||||||
|
try {
|
||||||
const user = this.getCurrentUser();
|
const user = this.getCurrentUser();
|
||||||
await connectDB();
|
await connectDB();
|
||||||
|
|
||||||
@@ -63,9 +73,16 @@ export class ConfigDBService {
|
|||||||
const config = await KomgaConfig.findOne({ userId: user.id });
|
const config = await KomgaConfig.findOne({ userId: user.id });
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof AppError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new AppError(ERROR_CODES.CONFIG.FETCH_ERROR, {}, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getTTLConfig() {
|
static async getTTLConfig() {
|
||||||
|
try {
|
||||||
const user = this.getCurrentUser();
|
const user = this.getCurrentUser();
|
||||||
await connectDB();
|
await connectDB();
|
||||||
|
|
||||||
@@ -73,9 +90,16 @@ export class ConfigDBService {
|
|||||||
const config = await TTLConfig.findOne({ userId: user.id });
|
const config = await TTLConfig.findOne({ userId: user.id });
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof AppError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new AppError(ERROR_CODES.CONFIG.TTL_FETCH_ERROR, {}, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async saveTTLConfig(data: TTLConfigData) {
|
static async saveTTLConfig(data: TTLConfigData) {
|
||||||
|
try {
|
||||||
const user = this.getCurrentUser();
|
const user = this.getCurrentUser();
|
||||||
await connectDB();
|
await connectDB();
|
||||||
|
|
||||||
@@ -90,5 +114,11 @@ export class ConfigDBService {
|
|||||||
);
|
);
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof AppError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new AppError(ERROR_CODES.CONFIG.TTL_SAVE_ERROR, {}, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import path from "path";
|
|||||||
import { CacheType } from "./base-api.service";
|
import { CacheType } from "./base-api.service";
|
||||||
import { AuthServerService } from "./auth-server.service";
|
import { AuthServerService } from "./auth-server.service";
|
||||||
import { PreferencesService } from "./preferences.service";
|
import { PreferencesService } from "./preferences.service";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
interface RequestTiming {
|
interface RequestTiming {
|
||||||
url: string;
|
url: string;
|
||||||
@@ -26,7 +28,7 @@ export class DebugService {
|
|||||||
private static getCurrentUserId(): string {
|
private static getCurrentUserId(): string {
|
||||||
const user = AuthServerService.getCurrentUser();
|
const user = AuthServerService.getCurrentUser();
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error("Utilisateur non authentifié");
|
throw new AppError(ERROR_CODES.AUTH.UNAUTHENTICATED);
|
||||||
}
|
}
|
||||||
return user.id;
|
return user.id;
|
||||||
}
|
}
|
||||||
@@ -73,7 +75,7 @@ export class DebugService {
|
|||||||
|
|
||||||
await fs.writeFile(filePath, JSON.stringify(logs, null, 2));
|
await fs.writeFile(filePath, JSON.stringify(logs, null, 2));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore les erreurs de logging
|
// On ignore les erreurs de logging mais on les trace quand même
|
||||||
console.error("Erreur lors de l'enregistrement du log:", error);
|
console.error("Erreur lors de l'enregistrement du log:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,7 +86,10 @@ export class DebugService {
|
|||||||
const filePath = this.getLogFilePath(userId);
|
const filePath = this.getLogFilePath(userId);
|
||||||
const content = await fs.readFile(filePath, "utf-8");
|
const content = await fs.readFile(filePath, "utf-8");
|
||||||
return JSON.parse(content);
|
return JSON.parse(content);
|
||||||
} catch {
|
} catch (error) {
|
||||||
|
if (error instanceof AppError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,8 +99,11 @@ export class DebugService {
|
|||||||
const userId = await this.getCurrentUserId();
|
const userId = await this.getCurrentUserId();
|
||||||
const filePath = this.getLogFilePath(userId);
|
const filePath = this.getLogFilePath(userId);
|
||||||
await fs.writeFile(filePath, "[]");
|
await fs.writeFile(filePath, "[]");
|
||||||
} catch {
|
} catch (error) {
|
||||||
// Ignore les erreurs si le fichier n'existe pas
|
if (error instanceof AppError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
// On ignore les autres erreurs si le fichier n'existe pas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,8 +144,8 @@ export class DebugService {
|
|||||||
|
|
||||||
await fs.writeFile(filePath, JSON.stringify(logs, null, 2));
|
await fs.writeFile(filePath, JSON.stringify(logs, null, 2));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore les erreurs de logging
|
// On ignore les erreurs de logging mais on les trace quand même
|
||||||
console.error("Erreur lors de l'enregistrement du log de page:", error);
|
console.error("Erreur lors de l'enregistrement du log de rendu:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import connectDB from "@/lib/mongodb";
|
|||||||
import { FavoriteModel } from "@/lib/models/favorite.model";
|
import { FavoriteModel } from "@/lib/models/favorite.model";
|
||||||
import { DebugService } from "./debug.service";
|
import { DebugService } from "./debug.service";
|
||||||
import { AuthServerService } from "./auth-server.service";
|
import { AuthServerService } from "./auth-server.service";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -21,7 +23,7 @@ export class FavoriteService {
|
|||||||
private static getCurrentUser(): User {
|
private static getCurrentUser(): User {
|
||||||
const user = AuthServerService.getCurrentUser();
|
const user = AuthServerService.getCurrentUser();
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error("Utilisateur non authentifié");
|
throw new AppError(ERROR_CODES.AUTH.UNAUTHENTICATED);
|
||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
@@ -65,8 +67,7 @@ export class FavoriteService {
|
|||||||
|
|
||||||
this.dispatchFavoritesChanged();
|
this.dispatchFavoritesChanged();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur lors de l'ajout aux favoris:", error);
|
throw new AppError(ERROR_CODES.FAVORITE.ADD_ERROR, {}, error);
|
||||||
throw new Error("Erreur lors de l'ajout aux favoris");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,8 +88,7 @@ export class FavoriteService {
|
|||||||
|
|
||||||
this.dispatchFavoritesChanged();
|
this.dispatchFavoritesChanged();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur lors de la suppression des favoris:", error);
|
throw new AppError(ERROR_CODES.FAVORITE.DELETE_ERROR, {}, error);
|
||||||
throw new Error("Erreur lors de la suppression des favoris");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { BaseApiService } from "./base-api.service";
|
|||||||
import { KomgaBook, KomgaSeries } from "@/types/komga";
|
import { KomgaBook, KomgaSeries } from "@/types/komga";
|
||||||
import { LibraryResponse } from "@/types/library";
|
import { LibraryResponse } from "@/types/library";
|
||||||
import { getServerCacheService } from "./server-cache.service";
|
import { getServerCacheService } from "./server-cache.service";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
interface HomeData {
|
interface HomeData {
|
||||||
ongoing: KomgaSeries[];
|
ongoing: KomgaSeries[];
|
||||||
@@ -78,15 +80,19 @@ export class HomeService extends BaseApiService {
|
|||||||
latestSeries: latestSeries.content || [],
|
latestSeries: latestSeries.content || [],
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.handleError(error, "Impossible de récupérer les données de la page d'accueil");
|
throw new AppError(ERROR_CODES.HOME.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async invalidateHomeCache(): Promise<void> {
|
static async invalidateHomeCache(): Promise<void> {
|
||||||
|
try {
|
||||||
const cacheService = await getServerCacheService();
|
const cacheService = await getServerCacheService();
|
||||||
await cacheService.delete("home-ongoing");
|
await cacheService.delete("home-ongoing");
|
||||||
await cacheService.delete("home-recently-read");
|
await cacheService.delete("home-recently-read");
|
||||||
await cacheService.delete("home-on-deck");
|
await cacheService.delete("home-on-deck");
|
||||||
await cacheService.delete("home-latest-series");
|
await cacheService.delete("home-latest-series");
|
||||||
|
} catch (error) {
|
||||||
|
throw new AppError(ERROR_CODES.CACHE.DELETE_ERROR, {}, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { BaseApiService } from "./base-api.service";
|
import { BaseApiService } from "./base-api.service";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
interface ImageResponse {
|
interface ImageResponse {
|
||||||
buffer: Buffer;
|
buffer: Buffer;
|
||||||
@@ -27,7 +29,7 @@ export class ImageService extends BaseApiService {
|
|||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur lors de la récupération de l'image:", error);
|
console.error("Erreur lors de la récupération de l'image:", error);
|
||||||
return this.handleError(error, "Impossible de récupérer l'image");
|
throw new AppError(ERROR_CODES.IMAGE.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { BaseApiService } from "./base-api.service";
|
|||||||
import { Library, LibraryResponse } from "@/types/library";
|
import { Library, LibraryResponse } from "@/types/library";
|
||||||
import { Series } from "@/types/series";
|
import { Series } from "@/types/series";
|
||||||
import { getServerCacheService } from "./server-cache.service";
|
import { getServerCacheService } from "./server-cache.service";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
export class LibraryService extends BaseApiService {
|
export class LibraryService extends BaseApiService {
|
||||||
static async getLibraries(): Promise<Library[]> {
|
static async getLibraries(): Promise<Library[]> {
|
||||||
@@ -12,17 +14,24 @@ export class LibraryService extends BaseApiService {
|
|||||||
"LIBRARIES"
|
"LIBRARIES"
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.handleError(error, "Impossible de récupérer les bibliothèques");
|
throw new AppError(ERROR_CODES.LIBRARY.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getLibrary(libraryId: string): Promise<Library> {
|
static async getLibrary(libraryId: string): Promise<Library> {
|
||||||
|
try {
|
||||||
const libraries = await this.getLibraries();
|
const libraries = await this.getLibraries();
|
||||||
const library = libraries.find((library) => library.id === libraryId);
|
const library = libraries.find((library) => library.id === libraryId);
|
||||||
if (!library) {
|
if (!library) {
|
||||||
throw new Error(`Bibliothèque ${libraryId} non trouvée`);
|
throw new AppError(ERROR_CODES.LIBRARY.NOT_FOUND, { libraryId });
|
||||||
}
|
}
|
||||||
return library;
|
return library;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof AppError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new AppError(ERROR_CODES.LIBRARY.FETCH_ERROR, {}, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getAllLibrarySeries(libraryId: string): Promise<Series[]> {
|
static async getAllLibrarySeries(libraryId: string): Promise<Series[]> {
|
||||||
@@ -60,7 +69,7 @@ export class LibraryService extends BaseApiService {
|
|||||||
|
|
||||||
return response.content;
|
return response.content;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.handleError(error, "Impossible de récupérer toutes les séries");
|
throw new AppError(ERROR_CODES.SERIES.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,12 +139,17 @@ export class LibraryService extends BaseApiService {
|
|||||||
totalPages,
|
totalPages,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.handleError(error, "Impossible de récupérer les séries");
|
throw new AppError(ERROR_CODES.SERIES.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async invalidateLibrarySeriesCache(libraryId: string): Promise<void> {
|
static async invalidateLibrarySeriesCache(libraryId: string): Promise<void> {
|
||||||
|
try {
|
||||||
const cacheService = await getServerCacheService();
|
const cacheService = await getServerCacheService();
|
||||||
await cacheService.delete(`library-${libraryId}-all-series`);
|
const cacheKey = `library-${libraryId}-all-series`;
|
||||||
|
await cacheService.delete(cacheKey);
|
||||||
|
} catch (error) {
|
||||||
|
throw new AppError(ERROR_CODES.CACHE.DELETE_ERROR, {}, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { PreferencesModel } from "@/lib/models/preferences.model";
|
import { PreferencesModel } from "@/lib/models/preferences.model";
|
||||||
import { AuthServerService } from "./auth-server.service";
|
import { AuthServerService } from "./auth-server.service";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -24,7 +26,7 @@ export class PreferencesService {
|
|||||||
static getCurrentUser(): User {
|
static getCurrentUser(): User {
|
||||||
const user = AuthServerService.getCurrentUser();
|
const user = AuthServerService.getCurrentUser();
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error("Utilisateur non authentifié");
|
throw new AppError(ERROR_CODES.AUTH.UNAUTHENTICATED);
|
||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
@@ -41,8 +43,10 @@ export class PreferencesService {
|
|||||||
...preferences.toObject(),
|
...preferences.toObject(),
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error getting preferences:", error);
|
if (error instanceof AppError) {
|
||||||
return defaultPreferences;
|
throw error;
|
||||||
|
}
|
||||||
|
throw new AppError(ERROR_CODES.PREFERENCES.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,8 +65,10 @@ export class PreferencesService {
|
|||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error updating preferences:", error);
|
if (error instanceof AppError) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
throw new AppError(ERROR_CODES.PREFERENCES.UPDATE_ERROR, {}, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { BookService } from "./book.service";
|
|||||||
import { ImageService } from "./image.service";
|
import { ImageService } from "./image.service";
|
||||||
import { PreferencesService } from "./preferences.service";
|
import { PreferencesService } from "./preferences.service";
|
||||||
import { getServerCacheService } from "./server-cache.service";
|
import { getServerCacheService } from "./server-cache.service";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
export class SeriesService extends BaseApiService {
|
export class SeriesService extends BaseApiService {
|
||||||
static async getSeries(seriesId: string): Promise<KomgaSeries> {
|
static async getSeries(seriesId: string): Promise<KomgaSeries> {
|
||||||
@@ -15,13 +17,17 @@ export class SeriesService extends BaseApiService {
|
|||||||
"SERIES"
|
"SERIES"
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.handleError(error, "Impossible de récupérer la série");
|
throw new AppError(ERROR_CODES.SERIES.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async invalidateSeriesCache(seriesId: string): Promise<void> {
|
static async invalidateSeriesCache(seriesId: string): Promise<void> {
|
||||||
|
try {
|
||||||
const cacheService = await getServerCacheService();
|
const cacheService = await getServerCacheService();
|
||||||
await cacheService.delete(`series-${seriesId}`);
|
await cacheService.delete(`series-${seriesId}`);
|
||||||
|
} catch (error) {
|
||||||
|
throw new AppError(ERROR_CODES.CACHE.DELETE_ERROR, {}, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getAllSeriesBooks(seriesId: string): Promise<KomgaBook[]> {
|
static async getAllSeriesBooks(seriesId: string): Promise<KomgaBook[]> {
|
||||||
@@ -57,9 +63,16 @@ export class SeriesService extends BaseApiService {
|
|||||||
"BOOKS"
|
"BOOKS"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!response.content.length) {
|
||||||
|
throw new AppError(ERROR_CODES.SERIES.NO_BOOKS_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
return response.content;
|
return response.content;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.handleError(error, "Impossible de récupérer tous les tomes");
|
if (error instanceof AppError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new AppError(ERROR_CODES.SERIES.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +135,7 @@ export class SeriesService extends BaseApiService {
|
|||||||
totalPages,
|
totalPages,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.handleError(error, "Impossible de récupérer les tomes");
|
throw new AppError(ERROR_CODES.SERIES.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +154,7 @@ export class SeriesService extends BaseApiService {
|
|||||||
params: { page: "0", size: "1" },
|
params: { page: "0", size: "1" },
|
||||||
});
|
});
|
||||||
if (!data.content || data.content.length === 0) {
|
if (!data.content || data.content.length === 0) {
|
||||||
throw new Error("Aucun livre trouvé dans la série");
|
throw new AppError(ERROR_CODES.SERIES.NO_BOOKS_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.content[0].id;
|
return data.content[0].id;
|
||||||
@@ -150,7 +163,7 @@ export class SeriesService extends BaseApiService {
|
|||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur lors de la récupération du premier livre:", error);
|
console.error("Erreur lors de la récupération du premier livre:", error);
|
||||||
return this.handleError(error, "Impossible de récupérer le premier livre");
|
throw new AppError(ERROR_CODES.SERIES.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +188,7 @@ export class SeriesService extends BaseApiService {
|
|||||||
const response = await BookService.getPage(firstBookId, 1);
|
const response = await BookService.getPage(firstBookId, 1);
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw this.handleError(error, "Impossible de récupérer la couverture");
|
throw new AppError(ERROR_CODES.SERIES.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +202,7 @@ export class SeriesService extends BaseApiService {
|
|||||||
const series = await Promise.all(seriesPromises);
|
const series = await Promise.all(seriesPromises);
|
||||||
return series.filter(Boolean);
|
return series.filter(Boolean);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return this.handleError(error, "Impossible de récupérer les séries");
|
throw new AppError(ERROR_CODES.SERIES.FETCH_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { BaseApiService } from "./base-api.service";
|
import { BaseApiService } from "./base-api.service";
|
||||||
import { AuthConfig } from "@/types/auth";
|
import { AuthConfig } from "@/types/auth";
|
||||||
import { KomgaLibrary } from "@/types/komga";
|
import { KomgaLibrary } from "@/types/komga";
|
||||||
|
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||||
|
import { AppError } from "../../utils/errors";
|
||||||
|
|
||||||
export class TestService extends BaseApiService {
|
export class TestService extends BaseApiService {
|
||||||
static async testConnection(config: AuthConfig): Promise<{ libraries: KomgaLibrary[] }> {
|
static async testConnection(config: AuthConfig): Promise<{ libraries: KomgaLibrary[] }> {
|
||||||
@@ -12,19 +14,20 @@ export class TestService extends BaseApiService {
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response.json().catch(() => ({}));
|
const errorData = await response.json().catch(() => ({}));
|
||||||
throw new Error(errorData.message || "Erreur lors du test de connexion");
|
throw new AppError(ERROR_CODES.KOMGA.CONNECTION_ERROR, { message: errorData.message });
|
||||||
}
|
}
|
||||||
|
|
||||||
const libraries = await response.json();
|
const libraries = await response.json();
|
||||||
return { libraries };
|
return { libraries };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur lors du test de connexion:", error);
|
console.error("Erreur lors du test de connexion:", error);
|
||||||
if (error instanceof Error && error.message.includes("fetch")) {
|
if (error instanceof AppError) {
|
||||||
throw new Error(
|
throw error;
|
||||||
"Impossible de se connecter au serveur. Vérifiez l'URL et que le serveur est accessible."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
throw error instanceof Error ? error : new Error("Erreur lors du test de connexion");
|
if (error instanceof Error && error.message.includes("fetch")) {
|
||||||
|
throw new AppError(ERROR_CODES.KOMGA.SERVER_UNREACHABLE);
|
||||||
|
}
|
||||||
|
throw new AppError(ERROR_CODES.KOMGA.CONNECTION_ERROR, {}, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
34
src/utils/errors.ts
Normal file
34
src/utils/errors.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { ERROR_MESSAGES } from "../constants/errorMessages";
|
||||||
|
import { ErrorCode } from "../constants/errorCodes";
|
||||||
|
|
||||||
|
export class AppError extends Error {
|
||||||
|
constructor(
|
||||||
|
public code: ErrorCode,
|
||||||
|
public params: Record<string, string | number> = {},
|
||||||
|
public originalError?: unknown
|
||||||
|
) {
|
||||||
|
let message = ERROR_MESSAGES[code];
|
||||||
|
|
||||||
|
// Replace parameters in message
|
||||||
|
Object.entries(params).forEach(([key, value]) => {
|
||||||
|
message = message.replace(`{${key}}`, String(value));
|
||||||
|
});
|
||||||
|
|
||||||
|
super(message);
|
||||||
|
this.name = "AppError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getErrorMessage = (
|
||||||
|
code: ErrorCode,
|
||||||
|
params: Record<string, string | number> = {}
|
||||||
|
): string => {
|
||||||
|
let message = ERROR_MESSAGES[code];
|
||||||
|
|
||||||
|
// Replace parameters in message
|
||||||
|
Object.entries(params).forEach(([key, value]) => {
|
||||||
|
message = message.replace(`{${key}}`, String(value));
|
||||||
|
});
|
||||||
|
|
||||||
|
return message;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user