Merge branch 'main' into feat/debugmode
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { cookies } from "next/headers";
|
||||
import connectDB from "@/lib/mongodb";
|
||||
import { UserModel } from "@/lib/models/user.model";
|
||||
import bcrypt from "bcrypt";
|
||||
|
||||
interface UserData {
|
||||
id: string;
|
||||
@@ -10,6 +11,8 @@ interface UserData {
|
||||
}
|
||||
|
||||
export class AuthServerService {
|
||||
private static readonly SALT_ROUNDS = 10;
|
||||
|
||||
static async createUser(email: string, password: string): Promise<UserData> {
|
||||
await connectDB();
|
||||
|
||||
@@ -24,10 +27,13 @@ export class AuthServerService {
|
||||
throw new Error("EMAIL_EXISTS");
|
||||
}
|
||||
|
||||
// Hash password
|
||||
const hashedPassword = await bcrypt.hash(password, this.SALT_ROUNDS);
|
||||
|
||||
// Create new user
|
||||
const user = await UserModel.create({
|
||||
email: email.toLowerCase(),
|
||||
password,
|
||||
password: hashedPassword,
|
||||
roles: ["ROLE_USER"],
|
||||
authenticated: true,
|
||||
});
|
||||
@@ -41,6 +47,7 @@ export class AuthServerService {
|
||||
|
||||
return userData;
|
||||
}
|
||||
|
||||
static isPasswordStrong(password: string): boolean {
|
||||
//check if password is strong
|
||||
if (password.length < 8) {
|
||||
@@ -52,9 +59,9 @@ export class AuthServerService {
|
||||
if (!/[0-9]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
if (!/[!@#$%^&*]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
// if (!/[!@#$%^&*]/.test(password)) {
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -95,7 +102,8 @@ export class AuthServerService {
|
||||
throw new Error("INVALID_CREDENTIALS");
|
||||
}
|
||||
|
||||
if (user.password !== password) {
|
||||
const isPasswordValid = await bcrypt.compare(password, user.password);
|
||||
if (!isPasswordValid) {
|
||||
throw new Error("INVALID_CREDENTIALS");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AuthConfig } from "@/types/auth";
|
||||
import { serverCacheService } from "./server-cache.service";
|
||||
import { getServerCacheService } from "./server-cache.service";
|
||||
import { ConfigDBService } from "./config-db.service";
|
||||
import { DebugService } from "./debug.service";
|
||||
|
||||
@@ -52,10 +52,11 @@ export abstract class BaseApiService {
|
||||
fetcher: () => Promise<T>,
|
||||
type: CacheType = "DEFAULT"
|
||||
): Promise<T> {
|
||||
const cacheService = await getServerCacheService();
|
||||
const startTime = performance.now();
|
||||
|
||||
try {
|
||||
const result = await serverCacheService.getOrSet(key, fetcher, type);
|
||||
const result = await cacheService.getOrSet(key, fetcher, type);
|
||||
const endTime = performance.now();
|
||||
|
||||
// Log la requête avec l'indication du cache
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { cookies } from "next/headers";
|
||||
import connectDB from "@/lib/mongodb";
|
||||
import { KomgaConfig } from "@/lib/models/config.model";
|
||||
import { TTLConfig } from "@/lib/models/ttl-config.model";
|
||||
@@ -34,6 +33,24 @@ export class ConfigDBService {
|
||||
return user;
|
||||
}
|
||||
|
||||
static async saveConfig(data: KomgaConfigData) {
|
||||
const user = this.getCurrentUser();
|
||||
await connectDB();
|
||||
|
||||
const config = await KomgaConfig.findOneAndUpdate(
|
||||
{ userId: user.id },
|
||||
{
|
||||
userId: user.id,
|
||||
url: data.url,
|
||||
username: data.username,
|
||||
password: data.password,
|
||||
},
|
||||
{ upsert: true, new: true }
|
||||
);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
static async getConfig() {
|
||||
const user = this.getCurrentUser();
|
||||
await connectDB();
|
||||
@@ -44,25 +61,6 @@ export class ConfigDBService {
|
||||
});
|
||||
}
|
||||
|
||||
static async saveConfig(data: KomgaConfigData) {
|
||||
const user = this.getCurrentUser();
|
||||
await connectDB();
|
||||
|
||||
return DebugService.measureMongoOperation("saveConfig", async () => {
|
||||
const config = await KomgaConfig.findOneAndUpdate(
|
||||
{ userId: user.id },
|
||||
{
|
||||
userId: user.id,
|
||||
url: data.url,
|
||||
username: data.username,
|
||||
password: data.password,
|
||||
},
|
||||
{ upsert: true, new: true }
|
||||
);
|
||||
return config;
|
||||
});
|
||||
}
|
||||
|
||||
static async getTTLConfig() {
|
||||
const user = this.getCurrentUser();
|
||||
await connectDB();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { cookies } from "next/headers";
|
||||
import connectDB from "@/lib/mongodb";
|
||||
import { FavoriteModel } from "@/lib/models/favorite.model";
|
||||
import { DebugService } from "./debug.service";
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import { BaseApiService } from "./base-api.service";
|
||||
import { KomgaBook, KomgaSeries } from "@/types/komga";
|
||||
import { LibraryResponse } from "@/types/library";
|
||||
import { serverCacheService } from "./server-cache.service";
|
||||
import { getServerCacheService } from "./server-cache.service";
|
||||
|
||||
interface HomeData {
|
||||
ongoing: KomgaSeries[];
|
||||
recentlyRead: KomgaBook[];
|
||||
onDeck: KomgaBook[];
|
||||
latestSeries: KomgaSeries[];
|
||||
}
|
||||
|
||||
export class HomeService extends BaseApiService {
|
||||
static async getHomeData(): Promise<HomeData> {
|
||||
try {
|
||||
// Appels API parallèles avec cache individuel
|
||||
const [ongoing, recentlyRead, onDeck] = await Promise.all([
|
||||
const [ongoing, recentlyRead, onDeck, latestSeries] = await Promise.all([
|
||||
this.fetchWithCache<LibraryResponse<KomgaSeries>>(
|
||||
"home-ongoing",
|
||||
async () =>
|
||||
@@ -55,21 +56,36 @@ export class HomeService extends BaseApiService {
|
||||
}),
|
||||
"HOME"
|
||||
),
|
||||
this.fetchWithCache<LibraryResponse<KomgaSeries>>(
|
||||
"home-latest-series",
|
||||
async () =>
|
||||
this.fetchFromApi<LibraryResponse<KomgaSeries>>({
|
||||
path: "series/latest",
|
||||
params: {
|
||||
page: "0",
|
||||
size: "10",
|
||||
media_status: "READY",
|
||||
},
|
||||
}),
|
||||
"HOME"
|
||||
),
|
||||
]);
|
||||
|
||||
return {
|
||||
ongoing: ongoing.content || [],
|
||||
recentlyRead: recentlyRead.content || [],
|
||||
onDeck: onDeck.content || [],
|
||||
latestSeries: latestSeries.content || [],
|
||||
};
|
||||
} catch (error) {
|
||||
return this.handleError(error, "Impossible de récupérer les données de la page d'accueil");
|
||||
}
|
||||
}
|
||||
|
||||
static async clearHomeCache() {
|
||||
serverCacheService.delete("home-ongoing");
|
||||
serverCacheService.delete("home-recently-read");
|
||||
serverCacheService.delete("home-on-deck");
|
||||
static async invalidateHomeCache(): Promise<void> {
|
||||
const cacheService = await getServerCacheService();
|
||||
cacheService.delete("home-ongoing");
|
||||
cacheService.delete("home-recently-read");
|
||||
cacheService.delete("home-on-deck");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BaseApiService } from "./base-api.service";
|
||||
import { Library, LibraryResponse } from "@/types/library";
|
||||
import { Series } from "@/types/series";
|
||||
import { serverCacheService } from "./server-cache.service";
|
||||
import { getServerCacheService } from "./server-cache.service";
|
||||
|
||||
export class LibraryService extends BaseApiService {
|
||||
static async getLibraries(): Promise<Library[]> {
|
||||
@@ -134,7 +134,8 @@ export class LibraryService extends BaseApiService {
|
||||
}
|
||||
}
|
||||
|
||||
static async clearLibrarySeriesCache(libraryId: string) {
|
||||
serverCacheService.delete(`library-${libraryId}-all-series`);
|
||||
static async invalidateLibrarySeriesCache(libraryId: string): Promise<void> {
|
||||
const cacheService = await getServerCacheService();
|
||||
cacheService.delete(`library-${libraryId}-all-series`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { cookies } from "next/headers";
|
||||
import { PreferencesModel } from "@/lib/models/preferences.model";
|
||||
import { AuthServerService } from "./auth-server.service";
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { KomgaBook, KomgaSeries } from "@/types/komga";
|
||||
import { BookService } from "./book.service";
|
||||
import { ImageService } from "./image.service";
|
||||
import { PreferencesService } from "./preferences.service";
|
||||
import { serverCacheService } from "./server-cache.service";
|
||||
import { getServerCacheService } from "./server-cache.service";
|
||||
|
||||
export class SeriesService extends BaseApiService {
|
||||
static async getSeries(seriesId: string): Promise<KomgaSeries> {
|
||||
@@ -19,8 +19,9 @@ export class SeriesService extends BaseApiService {
|
||||
}
|
||||
}
|
||||
|
||||
static async clearSeriesCache(seriesId: string) {
|
||||
serverCacheService.delete(`series-${seriesId}`);
|
||||
static async invalidateSeriesCache(seriesId: string): Promise<void> {
|
||||
const cacheService = await getServerCacheService();
|
||||
cacheService.delete(`series-${seriesId}`);
|
||||
}
|
||||
|
||||
static async getAllSeriesBooks(seriesId: string): Promise<KomgaBook[]> {
|
||||
@@ -125,8 +126,9 @@ export class SeriesService extends BaseApiService {
|
||||
}
|
||||
}
|
||||
|
||||
static async clearSeriesBooksCache(seriesId: string) {
|
||||
serverCacheService.delete(`series-${seriesId}-all-books`);
|
||||
static async invalidateSeriesBooksCache(seriesId: string): Promise<void> {
|
||||
const cacheService = await getServerCacheService();
|
||||
cacheService.delete(`series-${seriesId}-all-books`);
|
||||
}
|
||||
|
||||
static async getFirstBook(seriesId: string): Promise<string> {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { PreferencesService } from "./preferences.service";
|
||||
|
||||
type CacheMode = "file" | "memory";
|
||||
|
||||
@@ -37,6 +38,17 @@ class ServerCacheService {
|
||||
this.cacheDir = path.join(process.cwd(), ".cache");
|
||||
this.ensureCacheDirectory();
|
||||
this.cleanExpiredCache();
|
||||
this.initializeCacheMode();
|
||||
}
|
||||
|
||||
private async initializeCacheMode(): Promise<void> {
|
||||
try {
|
||||
const preferences = await PreferencesService.getPreferences();
|
||||
this.setCacheMode(preferences.cacheMode);
|
||||
} catch (error) {
|
||||
console.error("Error initializing cache mode from preferences:", error);
|
||||
// Keep default memory mode if preferences can't be loaded
|
||||
}
|
||||
}
|
||||
|
||||
private ensureCacheDirectory(): void {
|
||||
@@ -117,9 +129,10 @@ class ServerCacheService {
|
||||
cleanDirectory(this.cacheDir);
|
||||
}
|
||||
|
||||
public static getInstance(): ServerCacheService {
|
||||
public static async getInstance(): Promise<ServerCacheService> {
|
||||
if (!ServerCacheService.instance) {
|
||||
ServerCacheService.instance = new ServerCacheService();
|
||||
await ServerCacheService.instance.initializeCacheMode();
|
||||
}
|
||||
return ServerCacheService.instance;
|
||||
}
|
||||
@@ -376,4 +389,15 @@ class ServerCacheService {
|
||||
}
|
||||
}
|
||||
|
||||
export const serverCacheService = ServerCacheService.getInstance();
|
||||
// Créer une instance initialisée du service
|
||||
let initializedInstance: Promise<ServerCacheService>;
|
||||
|
||||
export const getServerCacheService = async (): Promise<ServerCacheService> => {
|
||||
if (!initializedInstance) {
|
||||
initializedInstance = ServerCacheService.getInstance();
|
||||
}
|
||||
return initializedInstance;
|
||||
};
|
||||
|
||||
// Exporter aussi la classe pour les tests
|
||||
export { ServerCacheService };
|
||||
|
||||
Reference in New Issue
Block a user