From 7a3c46c6c164825d01e0802a1f59b0d49b806077 Mon Sep 17 00:00:00 2001 From: Rafi Arrafif Date: Thu, 19 Feb 2026 14:16:12 +0700 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20internal=20endpoi?= =?UTF-8?q?nt=20to=20purge=20user=20session?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../purgeUnusedSession.controller.ts | 18 ++++++++++++++++++ src/modules/internal/index.ts | 4 +++- .../deleteAllUnusedUserSession.repository.ts | 17 +++++++++++++++++ .../http/purgeUnusedSession.service.ts | 10 ++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 src/modules/internal/controllers/purgeUnusedSession.controller.ts create mode 100644 src/modules/internal/repositories/deleteAllUnusedUserSession.repository.ts create mode 100644 src/modules/internal/services/http/purgeUnusedSession.service.ts diff --git a/src/modules/internal/controllers/purgeUnusedSession.controller.ts b/src/modules/internal/controllers/purgeUnusedSession.controller.ts new file mode 100644 index 0000000..b109204 --- /dev/null +++ b/src/modules/internal/controllers/purgeUnusedSession.controller.ts @@ -0,0 +1,18 @@ +import { Context } from "elysia"; +import { mainErrorHandler } from "../../../helpers/error/handler"; +import { returnWriteResponse } from "../../../helpers/callback/httpResponse"; +import { purgeUnusedSessionService } from "../services/http/purgeUnusedSession.service"; + +export const purgeUnusedSessionController = async (ctx: Context) => { + try { + const result = await purgeUnusedSessionService(); + return returnWriteResponse( + ctx.set, + 200, + "Successfully purged all unused user sessions", + result, + ); + } catch (error) { + return mainErrorHandler(ctx.set, error); + } +}; diff --git a/src/modules/internal/index.ts b/src/modules/internal/index.ts index 683667b..4e9b58c 100644 --- a/src/modules/internal/index.ts +++ b/src/modules/internal/index.ts @@ -4,10 +4,12 @@ import { bulkInsertMediaController } from "./controllers/bulkInsertMedia.control import { createVideoServiceInternalController } from "./controllers/createVideoService.controller"; import { bulkInsertVideoController } from "./controllers/bulkInsertVideo.controller"; import { updateAllEpisodeThumbnailController } from "./controllers/updateAllEpisodeThumbnail.controller"; +import { purgeUnusedSessionController } from "./controllers/purgeUnusedSession.controller"; export const internalModule = new Elysia({ prefix: "/internal" }) .post("/media/bulk-insert", bulkInsertMediaController) .post("/episode/bulk-insert", bulkInsertEpisodeController) .put("/episode/update-thumbnails", updateAllEpisodeThumbnailController) .post("/video/bulk-insert", bulkInsertVideoController) - .post("/video-service", createVideoServiceInternalController); + .post("/video-service", createVideoServiceInternalController) + .post("/user-session/purge-unused", purgeUnusedSessionController); diff --git a/src/modules/internal/repositories/deleteAllUnusedUserSession.repository.ts b/src/modules/internal/repositories/deleteAllUnusedUserSession.repository.ts new file mode 100644 index 0000000..e213196 --- /dev/null +++ b/src/modules/internal/repositories/deleteAllUnusedUserSession.repository.ts @@ -0,0 +1,17 @@ +import { AppError } from "../../../helpers/error/instances/app"; +import { prisma } from "../../../utils/databases/prisma/connection"; + +export const deleteAllUnusedUserSessionRepository = async () => { + try { + return await prisma.userSession.deleteMany({ + where: { + isAuthenticated: false, + deletedAt: { + not: null, + }, + }, + }); + } catch (error) { + throw new AppError(500, "Failed to delete all unused user sessions", error); + } +}; diff --git a/src/modules/internal/services/http/purgeUnusedSession.service.ts b/src/modules/internal/services/http/purgeUnusedSession.service.ts new file mode 100644 index 0000000..5be408b --- /dev/null +++ b/src/modules/internal/services/http/purgeUnusedSession.service.ts @@ -0,0 +1,10 @@ +import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder"; +import { deleteAllUnusedUserSessionRepository } from "../../repositories/deleteAllUnusedUserSession.repository"; + +export const purgeUnusedSessionService = async () => { + try { + return await deleteAllUnusedUserSessionRepository(); + } catch (error) { + ErrorForwarder(error); + } +}; From 133ebb4668942d991f24e67ab2b01109c4b8a218 Mon Sep 17 00:00:00 2001 From: Rafi Arrafif Date: Thu, 19 Feb 2026 14:23:37 +0700 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=97=83=EF=B8=8F=20db:=20add=20composi?= =?UTF-8?q?te=20index=20to=20userSession?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- prisma/schema.prisma | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 0c255ec..52a0fd0 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -395,6 +395,8 @@ model UserSession { logs UserLog[] @relation("UserSessionLogs") episode_likes EpisodeLike[] @relation("SessionEpisodeLikes") watch_histories WatchHistory[] @relation("SessionWatchHistories") + + @@index([userId, isAuthenticated, deletedAt]) @@map("user_sessions") }