Compare commits
1 Commits
main
...
a6200605f8
| Author | SHA1 | Date | |
|---|---|---|---|
| a6200605f8 |
@ -28,11 +28,10 @@ Table medias {
|
|||||||
deletedAt DateTime
|
deletedAt DateTime
|
||||||
createdAt DateTime [default: `now()`, not null]
|
createdAt DateTime [default: `now()`, not null]
|
||||||
updatedAt DateTime [default: `now()`, not null]
|
updatedAt DateTime [default: `now()`, not null]
|
||||||
bannerPromotion hero_banner [not null]
|
|
||||||
logs media_logs [not null]
|
logs media_logs [not null]
|
||||||
episodes episodes [not null]
|
episodes episodes [not null]
|
||||||
|
collections collections [not null]
|
||||||
reviews movie_reviews [not null]
|
reviews movie_reviews [not null]
|
||||||
inCollections CollectionMedia [not null]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Table media_logs {
|
Table media_logs {
|
||||||
@ -369,7 +368,7 @@ Table user_logs {
|
|||||||
Table collections {
|
Table collections {
|
||||||
id String [pk]
|
id String [pk]
|
||||||
name String [not null]
|
name String [not null]
|
||||||
slug String [not null]
|
medias medias [not null]
|
||||||
owner users [not null]
|
owner users [not null]
|
||||||
ownerId String [not null]
|
ownerId String [not null]
|
||||||
accessStatus AccessStatus [not null, default: 'private']
|
accessStatus AccessStatus [not null, default: 'private']
|
||||||
@ -379,24 +378,6 @@ Table collections {
|
|||||||
deletedAt DateTime
|
deletedAt DateTime
|
||||||
createdAt DateTime [default: `now()`, not null]
|
createdAt DateTime [default: `now()`, not null]
|
||||||
updatedAt DateTime [default: `now()`, not null]
|
updatedAt DateTime [default: `now()`, not null]
|
||||||
media_saved CollectionMedia [not null]
|
|
||||||
|
|
||||||
indexes {
|
|
||||||
(slug, ownerId) [unique]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Table CollectionMedia {
|
|
||||||
id String [pk]
|
|
||||||
collection collections [not null]
|
|
||||||
collectionId String [not null]
|
|
||||||
media medias [not null]
|
|
||||||
mediaId String [not null]
|
|
||||||
savedAt DateTime [default: `now()`, not null]
|
|
||||||
|
|
||||||
indexes {
|
|
||||||
(collectionId, mediaId) [unique]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Table watch_histories {
|
Table watch_histories {
|
||||||
@ -515,8 +496,12 @@ Table email_system_histories {
|
|||||||
Table hero_banner {
|
Table hero_banner {
|
||||||
id String [pk]
|
id String [pk]
|
||||||
orderPriority Int [unique]
|
orderPriority Int [unique]
|
||||||
mediaId String [not null]
|
isClickable Boolean [not null, default: false]
|
||||||
media medias [not null]
|
title String
|
||||||
|
tags String[] [not null]
|
||||||
|
description String
|
||||||
|
buttonContent String
|
||||||
|
buttonLink String
|
||||||
imageUrl String
|
imageUrl String
|
||||||
startDate DateTime [not null]
|
startDate DateTime [not null]
|
||||||
endDate DateTime [not null]
|
endDate DateTime [not null]
|
||||||
@ -575,9 +560,9 @@ Table MediaCharacters {
|
|||||||
mediasId String [ref: > medias.id]
|
mediasId String [ref: > medias.id]
|
||||||
}
|
}
|
||||||
|
|
||||||
Table CollectionMedia {
|
Table MediaCollections {
|
||||||
incollectionsId String [ref: > CollectionMedia.id]
|
collectionsId String [ref: > collections.id]
|
||||||
media_savedId String [ref: > CollectionMedia.id]
|
mediasId String [ref: > medias.id]
|
||||||
}
|
}
|
||||||
|
|
||||||
Table UserFavoriteGenres {
|
Table UserFavoriteGenres {
|
||||||
@ -765,10 +750,6 @@ Ref: user_logs.sessionId > user_sessions.id
|
|||||||
|
|
||||||
Ref: collections.ownerId > users.id
|
Ref: collections.ownerId > users.id
|
||||||
|
|
||||||
Ref: CollectionMedia.collectionId > collections.id
|
|
||||||
|
|
||||||
Ref: CollectionMedia.mediaId > medias.id
|
|
||||||
|
|
||||||
Ref: watch_histories.id > episodes.id
|
Ref: watch_histories.id > episodes.id
|
||||||
|
|
||||||
Ref: watch_histories.userId > users.id
|
Ref: watch_histories.userId > users.id
|
||||||
@ -799,8 +780,6 @@ Ref: email_system_accounts.createdBy > users.id
|
|||||||
|
|
||||||
Ref: email_system_histories.userRelated > users.id
|
Ref: email_system_histories.userRelated > users.id
|
||||||
|
|
||||||
Ref: hero_banner.mediaId > medias.id
|
|
||||||
|
|
||||||
Ref: hero_banner.creatorId > users.id
|
Ref: hero_banner.creatorId > users.id
|
||||||
|
|
||||||
Ref: system_notifications.createdBy > users.id
|
Ref: system_notifications.createdBy > users.id
|
||||||
|
|||||||
@ -7,9 +7,6 @@ CREATE TYPE "MediaType" AS ENUM ('TV', 'ONA', 'OVA', 'Movie', 'Special', 'Music'
|
|||||||
-- CreateEnum
|
-- CreateEnum
|
||||||
CREATE TYPE "Country" AS ENUM ('Japanese', 'English', 'Indonesia', 'Korea');
|
CREATE TYPE "Country" AS ENUM ('Japanese', 'English', 'Indonesia', 'Korea');
|
||||||
|
|
||||||
-- CreateEnum
|
|
||||||
CREATE TYPE "Season" AS ENUM ('Winter', 'Spring', 'Summer', 'Fall');
|
|
||||||
|
|
||||||
-- CreateEnum
|
-- CreateEnum
|
||||||
CREATE TYPE "CharacterRole" AS ENUM ('Main', 'Supporting');
|
CREATE TYPE "CharacterRole" AS ENUM ('Main', 'Supporting');
|
||||||
|
|
||||||
@ -75,8 +72,6 @@ CREATE TABLE "medias" (
|
|||||||
"deletedAt" TIMESTAMP(3),
|
"deletedAt" TIMESTAMP(3),
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"season" "Season",
|
|
||||||
"yearReleased" SMALLINT NOT NULL,
|
|
||||||
|
|
||||||
CONSTRAINT "medias_pkey" PRIMARY KEY ("id")
|
CONSTRAINT "medias_pkey" PRIMARY KEY ("id")
|
||||||
);
|
);
|
||||||
@ -211,8 +206,7 @@ CREATE TABLE "videos" (
|
|||||||
"id" UUID NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
"episodeId" UUID NOT NULL,
|
"episodeId" UUID NOT NULL,
|
||||||
"serviceId" UUID NOT NULL,
|
"serviceId" UUID NOT NULL,
|
||||||
"videoCode" VARCHAR(255) NOT NULL,
|
"code" VARCHAR(255) NOT NULL,
|
||||||
"thumbnailCode" TEXT,
|
|
||||||
"pendingUpload" BOOLEAN NOT NULL DEFAULT true,
|
"pendingUpload" BOOLEAN NOT NULL DEFAULT true,
|
||||||
"uploadedBy" UUID NOT NULL,
|
"uploadedBy" UUID NOT NULL,
|
||||||
"deletedAt" TIMESTAMP(3),
|
"deletedAt" TIMESTAMP(3),
|
||||||
@ -372,7 +366,7 @@ CREATE TABLE "user_logs" (
|
|||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "collections" (
|
CREATE TABLE "collections" (
|
||||||
"id" UUID NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
"name" VARCHAR(115) NOT NULL,
|
"name" VARCHAR(255) NOT NULL,
|
||||||
"ownerId" UUID NOT NULL,
|
"ownerId" UUID NOT NULL,
|
||||||
"accessStatus" "AccessStatus" NOT NULL DEFAULT 'private',
|
"accessStatus" "AccessStatus" NOT NULL DEFAULT 'private',
|
||||||
"password" VARCHAR(255),
|
"password" VARCHAR(255),
|
||||||
@ -380,21 +374,10 @@ CREATE TABLE "collections" (
|
|||||||
"deletedAt" TIMESTAMP(3),
|
"deletedAt" TIMESTAMP(3),
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"slug" VARCHAR(115) NOT NULL,
|
|
||||||
|
|
||||||
CONSTRAINT "collections_pkey" PRIMARY KEY ("id")
|
CONSTRAINT "collections_pkey" PRIMARY KEY ("id")
|
||||||
);
|
);
|
||||||
|
|
||||||
-- CreateTable
|
|
||||||
CREATE TABLE "CollectionMedia" (
|
|
||||||
"id" UUID NOT NULL,
|
|
||||||
"collectionId" UUID NOT NULL,
|
|
||||||
"mediaId" UUID NOT NULL,
|
|
||||||
"savedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
|
|
||||||
CONSTRAINT "CollectionMedia_pkey" PRIMARY KEY ("id")
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "watch_histories" (
|
CREATE TABLE "watch_histories" (
|
||||||
"id" UUID NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
@ -514,21 +497,6 @@ CREATE TABLE "email_system_histories" (
|
|||||||
CONSTRAINT "email_system_histories_pkey" PRIMARY KEY ("id")
|
CONSTRAINT "email_system_histories_pkey" PRIMARY KEY ("id")
|
||||||
);
|
);
|
||||||
|
|
||||||
-- CreateTable
|
|
||||||
CREATE TABLE "hero_banner" (
|
|
||||||
"id" UUID NOT NULL,
|
|
||||||
"orderPriority" INTEGER,
|
|
||||||
"imageUrl" TEXT,
|
|
||||||
"startDate" TIMESTAMP(3) NOT NULL,
|
|
||||||
"endDate" TIMESTAMP(3) NOT NULL,
|
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"creatorId" UUID NOT NULL,
|
|
||||||
"mediaId" UUID NOT NULL,
|
|
||||||
|
|
||||||
CONSTRAINT "hero_banner_pkey" PRIMARY KEY ("id")
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "system_preferences" (
|
CREATE TABLE "system_preferences" (
|
||||||
"id" UUID NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
@ -602,6 +570,14 @@ CREATE TABLE "_MediaCharacters" (
|
|||||||
CONSTRAINT "_MediaCharacters_AB_pkey" PRIMARY KEY ("A","B")
|
CONSTRAINT "_MediaCharacters_AB_pkey" PRIMARY KEY ("A","B")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "_MediaCollections" (
|
||||||
|
"A" UUID NOT NULL,
|
||||||
|
"B" UUID NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "_MediaCollections_AB_pkey" PRIMARY KEY ("A","B")
|
||||||
|
);
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "_UserSelectedSharingCollention" (
|
CREATE TABLE "_UserSelectedSharingCollention" (
|
||||||
"A" UUID NOT NULL,
|
"A" UUID NOT NULL,
|
||||||
@ -653,7 +629,7 @@ CREATE UNIQUE INDEX "lang_va_char_language_vaId_charId_key" ON "lang_va_char"("l
|
|||||||
CREATE UNIQUE INDEX "episodes_mediaId_episode_key" ON "episodes"("mediaId", "episode");
|
CREATE UNIQUE INDEX "episodes_mediaId_episode_key" ON "episodes"("mediaId", "episode");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "videos_serviceId_videoCode_key" ON "videos"("serviceId", "videoCode");
|
CREATE UNIQUE INDEX "videos_serviceId_code_key" ON "videos"("serviceId", "code");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "video_services_name_key" ON "video_services"("name");
|
CREATE UNIQUE INDEX "video_services_name_key" ON "video_services"("name");
|
||||||
@ -676,12 +652,6 @@ CREATE UNIQUE INDEX "user_roles_name_key" ON "user_roles"("name");
|
|||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "user_sessions_userId_isAuthenticated_deletedAt_idx" ON "user_sessions"("userId", "isAuthenticated", "deletedAt");
|
CREATE INDEX "user_sessions_userId_isAuthenticated_deletedAt_idx" ON "user_sessions"("userId", "isAuthenticated", "deletedAt");
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE UNIQUE INDEX "collections_slug_ownerId_key" ON "collections"("slug", "ownerId");
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE UNIQUE INDEX "CollectionMedia_collectionId_mediaId_key" ON "CollectionMedia"("collectionId", "mediaId");
|
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "languages_code_key" ON "languages"("code");
|
CREATE UNIQUE INDEX "languages_code_key" ON "languages"("code");
|
||||||
|
|
||||||
@ -694,12 +664,6 @@ CREATE UNIQUE INDEX "email_system_accounts_email_key" ON "email_system_accounts"
|
|||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "email_system_accounts_username_key" ON "email_system_accounts"("username");
|
CREATE UNIQUE INDEX "email_system_accounts_username_key" ON "email_system_accounts"("username");
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE UNIQUE INDEX "hero_banner_orderPriority_key" ON "hero_banner"("orderPriority");
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE UNIQUE INDEX "system_preferences_key_key" ON "system_preferences"("key");
|
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "_MediaStudios_B_index" ON "_MediaStudios"("B");
|
CREATE INDEX "_MediaStudios_B_index" ON "_MediaStudios"("B");
|
||||||
|
|
||||||
@ -712,21 +676,24 @@ CREATE INDEX "_UserFavoriteGenres_B_index" ON "_UserFavoriteGenres"("B");
|
|||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "_MediaCharacters_B_index" ON "_MediaCharacters"("B");
|
CREATE INDEX "_MediaCharacters_B_index" ON "_MediaCharacters"("B");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "_MediaCollections_B_index" ON "_MediaCollections"("B");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "_UserSelectedSharingCollention_B_index" ON "_UserSelectedSharingCollention"("B");
|
CREATE INDEX "_UserSelectedSharingCollention_B_index" ON "_UserSelectedSharingCollention"("B");
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "medias" ADD CONSTRAINT "medias_uploadedBy_fkey" FOREIGN KEY ("uploadedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "medias" ADD CONSTRAINT "medias_uploadedBy_fkey" FOREIGN KEY ("uploadedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "media_logs" ADD CONSTRAINT "media_logs_proposedBy_fkey" FOREIGN KEY ("proposedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "media_logs" ADD CONSTRAINT "media_logs_approvedBy_fkey" FOREIGN KEY ("approvedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "media_logs" ADD CONSTRAINT "media_logs_approvedBy_fkey" FOREIGN KEY ("approvedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "media_logs" ADD CONSTRAINT "media_logs_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "media_logs" ADD CONSTRAINT "media_logs_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "media_logs" ADD CONSTRAINT "media_logs_proposedBy_fkey" FOREIGN KEY ("proposedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "genres" ADD CONSTRAINT "genres_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "genres" ADD CONSTRAINT "genres_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
@ -739,15 +706,15 @@ ALTER TABLE "characters" ADD CONSTRAINT "characters_creatorId_fkey" FOREIGN KEY
|
|||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "voice_actors" ADD CONSTRAINT "voice_actors_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "voice_actors" ADD CONSTRAINT "voice_actors_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "lang_va_char" ADD CONSTRAINT "lang_va_char_vaId_fkey" FOREIGN KEY ("vaId") REFERENCES "voice_actors"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "lang_va_char" ADD CONSTRAINT "lang_va_char_charId_fkey" FOREIGN KEY ("charId") REFERENCES "characters"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "lang_va_char" ADD CONSTRAINT "lang_va_char_charId_fkey" FOREIGN KEY ("charId") REFERENCES "characters"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "lang_va_char" ADD CONSTRAINT "lang_va_char_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "lang_va_char" ADD CONSTRAINT "lang_va_char_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "lang_va_char" ADD CONSTRAINT "lang_va_char_vaId_fkey" FOREIGN KEY ("vaId") REFERENCES "voice_actors"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "episodes" ADD CONSTRAINT "episodes_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "episodes" ADD CONSTRAINT "episodes_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
@ -755,13 +722,13 @@ ALTER TABLE "episodes" ADD CONSTRAINT "episodes_mediaId_fkey" FOREIGN KEY ("medi
|
|||||||
ALTER TABLE "episodes" ADD CONSTRAINT "episodes_uploadedBy_fkey" FOREIGN KEY ("uploadedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "episodes" ADD CONSTRAINT "episodes_uploadedBy_fkey" FOREIGN KEY ("uploadedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "episode_likes" ADD CONSTRAINT "episode_likes_episodeId_fkey" FOREIGN KEY ("episodeId") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "episode_likes" ADD CONSTRAINT "episode_likes_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "episode_likes" ADD CONSTRAINT "episode_likes_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "user_sessions"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "episode_likes" ADD CONSTRAINT "episode_likes_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "user_sessions"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "episode_likes" ADD CONSTRAINT "episode_likes_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "episode_likes" ADD CONSTRAINT "episode_likes_episodeId_fkey" FOREIGN KEY ("episodeId") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "videos" ADD CONSTRAINT "videos_episodeId_fkey" FOREIGN KEY ("episodeId") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "videos" ADD CONSTRAINT "videos_episodeId_fkey" FOREIGN KEY ("episodeId") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@ -775,23 +742,23 @@ ALTER TABLE "videos" ADD CONSTRAINT "videos_uploadedBy_fkey" FOREIGN KEY ("uploa
|
|||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "video_services" ADD CONSTRAINT "video_services_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "video_services" ADD CONSTRAINT "video_services_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_langPreference_fkey" FOREIGN KEY ("langPreference") REFERENCES "languages"("code") ON DELETE SET NULL ON UPDATE CASCADE;
|
ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_langPreference_fkey" FOREIGN KEY ("langPreference") REFERENCES "languages"("code") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_serviceDefaultId_fkey" FOREIGN KEY ("serviceDefaultId") REFERENCES "video_services"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_serviceDefaultId_fkey" FOREIGN KEY ("serviceDefaultId") REFERENCES "video_services"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "user_role_assignments" ADD CONSTRAINT "user_role_assignments_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "user_roles"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "user_role_assignments" ADD CONSTRAINT "user_role_assignments_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "user_role_assignments" ADD CONSTRAINT "user_role_assignments_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "user_role_assignments" ADD CONSTRAINT "user_role_assignments_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "user_roles"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "user_notifications" ADD CONSTRAINT "user_notifications_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "user_notifications" ADD CONSTRAINT "user_notifications_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@ -800,35 +767,29 @@ ALTER TABLE "user_notifications" ADD CONSTRAINT "user_notifications_userId_fkey"
|
|||||||
ALTER TABLE "user_sessions" ADD CONSTRAINT "user_sessions_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "user_sessions" ADD CONSTRAINT "user_sessions_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "user_logs" ADD CONSTRAINT "user_logs_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "user_sessions"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "user_logs" ADD CONSTRAINT "user_logs_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "user_logs" ADD CONSTRAINT "user_logs_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "user_logs" ADD CONSTRAINT "user_logs_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "user_sessions"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "collections" ADD CONSTRAINT "collections_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "collections" ADD CONSTRAINT "collections_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "CollectionMedia" ADD CONSTRAINT "CollectionMedia_collectionId_fkey" FOREIGN KEY ("collectionId") REFERENCES "collections"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "CollectionMedia" ADD CONSTRAINT "CollectionMedia_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "watch_histories" ADD CONSTRAINT "watch_histories_id_fkey" FOREIGN KEY ("id") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "watch_histories" ADD CONSTRAINT "watch_histories_id_fkey" FOREIGN KEY ("id") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "watch_histories" ADD CONSTRAINT "watch_histories_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "user_sessions"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "watch_histories" ADD CONSTRAINT "watch_histories_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "watch_histories" ADD CONSTRAINT "watch_histories_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "movie_reviews" ADD CONSTRAINT "movie_reviews_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "watch_histories" ADD CONSTRAINT "watch_histories_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "user_sessions"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "movie_reviews" ADD CONSTRAINT "movie_reviews_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "movie_reviews" ADD CONSTRAINT "movie_reviews_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "movie_reviews" ADD CONSTRAINT "movie_reviews_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "comments" ADD CONSTRAINT "comments_episodeId_fkey" FOREIGN KEY ("episodeId") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "comments" ADD CONSTRAINT "comments_episodeId_fkey" FOREIGN KEY ("episodeId") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
@ -845,10 +806,10 @@ ALTER TABLE "comment_likes" ADD CONSTRAINT "comment_likes_commentId_fkey" FOREIG
|
|||||||
ALTER TABLE "comment_likes" ADD CONSTRAINT "comment_likes_userLiked_fkey" FOREIGN KEY ("userLiked") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "comment_likes" ADD CONSTRAINT "comment_likes_userLiked_fkey" FOREIGN KEY ("userLiked") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "comment_reports" ADD CONSTRAINT "comment_reports_approvedBy_fkey" FOREIGN KEY ("approvedBy") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
ALTER TABLE "comment_reports" ADD CONSTRAINT "comment_reports_userReporter_fkey" FOREIGN KEY ("userReporter") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "comment_reports" ADD CONSTRAINT "comment_reports_userReporter_fkey" FOREIGN KEY ("userReporter") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "comment_reports" ADD CONSTRAINT "comment_reports_approvedBy_fkey" FOREIGN KEY ("approvedBy") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "languages" ADD CONSTRAINT "languages_craetedBy_fkey" FOREIGN KEY ("craetedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "languages" ADD CONSTRAINT "languages_craetedBy_fkey" FOREIGN KEY ("craetedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@ -859,12 +820,6 @@ ALTER TABLE "email_system_accounts" ADD CONSTRAINT "email_system_accounts_create
|
|||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "email_system_histories" ADD CONSTRAINT "email_system_histories_userRelated_fkey" FOREIGN KEY ("userRelated") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "email_system_histories" ADD CONSTRAINT "email_system_histories_userRelated_fkey" FOREIGN KEY ("userRelated") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "hero_banner" ADD CONSTRAINT "hero_banner_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "hero_banner" ADD CONSTRAINT "hero_banner_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "system_notifications" ADD CONSTRAINT "system_notifications_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "system_notifications" ADD CONSTRAINT "system_notifications_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
@ -895,6 +850,12 @@ ALTER TABLE "_MediaCharacters" ADD CONSTRAINT "_MediaCharacters_A_fkey" FOREIGN
|
|||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "_MediaCharacters" ADD CONSTRAINT "_MediaCharacters_B_fkey" FOREIGN KEY ("B") REFERENCES "medias"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
ALTER TABLE "_MediaCharacters" ADD CONSTRAINT "_MediaCharacters_B_fkey" FOREIGN KEY ("B") REFERENCES "medias"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "_MediaCollections" ADD CONSTRAINT "_MediaCollections_A_fkey" FOREIGN KEY ("A") REFERENCES "collections"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "_MediaCollections" ADD CONSTRAINT "_MediaCollections_B_fkey" FOREIGN KEY ("B") REFERENCES "medias"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "_UserSelectedSharingCollention" ADD CONSTRAINT "_UserSelectedSharingCollention_A_fkey" FOREIGN KEY ("A") REFERENCES "collections"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
ALTER TABLE "_UserSelectedSharingCollention" ADD CONSTRAINT "_UserSelectedSharingCollention_A_fkey" FOREIGN KEY ("A") REFERENCES "collections"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `code` on the `videos` table. All the data in the column will be lost.
|
||||||
|
- A unique constraint covering the columns `[serviceId,videoCode]` on the table `videos` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
- Added the required column `videoCode` to the `videos` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- DropIndex
|
||||||
|
DROP INDEX "videos_serviceId_code_key";
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "videos" RENAME COLUMN "code" TO "videoCode";
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
DROP INDEX IF EXISTS "videos_serviceId_code_key";
|
||||||
|
CREATE UNIQUE INDEX "videos_serviceId_videoCode_key" ON "videos"("serviceId", "videoCode");
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "videos" ADD COLUMN "thumbnailCode" TEXT;
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "HeroBanner" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"isClickable" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"title" VARCHAR(225),
|
||||||
|
"description" TEXT,
|
||||||
|
"buttonContent" VARCHAR(100),
|
||||||
|
"buttonLink" TEXT,
|
||||||
|
"imageUrl" TEXT,
|
||||||
|
"startDate" TIMESTAMP(3) NOT NULL,
|
||||||
|
"endDate" TIMESTAMP(3) NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"creatorId" UUID NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "HeroBanner_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "HeroBanner" ADD CONSTRAINT "HeroBanner_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the `HeroBanner` table. If the table is not empty, all the data it contains will be lost.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "HeroBanner" DROP CONSTRAINT "HeroBanner_creatorId_fkey";
|
||||||
|
|
||||||
|
-- DropTable
|
||||||
|
DROP TABLE "HeroBanner";
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "hero_banner" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"isClickable" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"title" VARCHAR(225),
|
||||||
|
"description" TEXT,
|
||||||
|
"buttonContent" VARCHAR(100),
|
||||||
|
"buttonLink" TEXT,
|
||||||
|
"imageUrl" TEXT,
|
||||||
|
"startDate" TIMESTAMP(3) NOT NULL,
|
||||||
|
"endDate" TIMESTAMP(3) NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"creatorId" UUID NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "hero_banner_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "hero_banner" ADD CONSTRAINT "hero_banner_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- A unique constraint covering the columns `[order]` on the table `hero_banner` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "hero_banner" ADD COLUMN "order" INTEGER;
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "hero_banner_order_key" ON "hero_banner"("order");
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `order` on the `hero_banner` table. All the data in the column will be lost.
|
||||||
|
- A unique constraint covering the columns `[orderPriority]` on the table `hero_banner` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- DropIndex
|
||||||
|
DROP INDEX "hero_banner_order_key";
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "hero_banner" DROP COLUMN "order",
|
||||||
|
ADD COLUMN "orderPriority" INTEGER;
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "hero_banner_orderPriority_key" ON "hero_banner"("orderPriority");
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "hero_banner" ADD COLUMN "tags" TEXT[];
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- A unique constraint covering the columns `[key]` on the table `system_preferences` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "system_preferences_key_key" ON "system_preferences"("key");
|
||||||
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
Warnings:
|
|
||||||
|
|
||||||
- The values [Winter,Spring,Summer,Fall] on the enum `Season` will be removed. If these variants are still used in the database, this will fail.
|
|
||||||
|
|
||||||
*/
|
|
||||||
-- AlterEnum
|
|
||||||
BEGIN;
|
|
||||||
CREATE TYPE "Season_new" AS ENUM ('winter', 'spring', 'summer', 'fall');
|
|
||||||
ALTER TABLE "medias" ALTER COLUMN "season" TYPE "Season_new" USING ("season"::text::"Season_new");
|
|
||||||
ALTER TYPE "Season" RENAME TO "Season_old";
|
|
||||||
ALTER TYPE "Season_new" RENAME TO "Season";
|
|
||||||
DROP TYPE "public"."Season_old";
|
|
||||||
COMMIT;
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,4 @@
|
|||||||
|
import { Context } from "elysia";
|
||||||
import { UserHeaderInformation } from "./types";
|
import { UserHeaderInformation } from "./types";
|
||||||
|
|
||||||
export interface ClientInfoHeader {
|
export interface ClientInfoHeader {
|
||||||
@ -9,14 +10,25 @@ export interface ClientInfoHeader {
|
|||||||
ip: string;
|
ip: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getUserHeaderInformation = (clientInfo: string): UserHeaderInformation => {
|
export const getUserHeaderInformation = (
|
||||||
const clientInfoHeader = (JSON.parse(clientInfo) as ClientInfoHeader) ?? ("unknown" as string);
|
ctx: Context,
|
||||||
|
): UserHeaderInformation => {
|
||||||
|
const clientInfoHeader =
|
||||||
|
(JSON.parse(
|
||||||
|
ctx.request.headers.get("x-client-info") as string,
|
||||||
|
) as ClientInfoHeader) ?? ("unknown" as string);
|
||||||
|
|
||||||
const userHeaderInformation = {
|
const userHeaderInformation = {
|
||||||
ip: clientInfoHeader.ip ?? "unknown",
|
ip: clientInfoHeader.ip ?? "unknown",
|
||||||
deviceType: clientInfoHeader.deviceType ?? "unknown",
|
deviceType: clientInfoHeader.deviceType ?? "unknown",
|
||||||
deviceOS: (clientInfoHeader.os ?? "unknown") + " " + (clientInfoHeader.osVersion ?? "unknown"),
|
deviceOS:
|
||||||
browser: (clientInfoHeader.browser ?? "unknown") + " " + (clientInfoHeader.browserVersion ?? "unknown"),
|
(clientInfoHeader.os ?? "unknown") +
|
||||||
|
" " +
|
||||||
|
(clientInfoHeader.osVersion ?? "unknown"),
|
||||||
|
browser:
|
||||||
|
(clientInfoHeader.browser ?? "unknown") +
|
||||||
|
" " +
|
||||||
|
(clientInfoHeader.browserVersion ?? "unknown"),
|
||||||
};
|
};
|
||||||
|
|
||||||
return userHeaderInformation;
|
return userHeaderInformation;
|
||||||
|
|||||||
@ -1,17 +1,14 @@
|
|||||||
import { Context, Static } from "elysia";
|
import { Context } from "elysia";
|
||||||
import { returnWriteResponse } from "../../../helpers/callback/httpResponse";
|
import { returnWriteResponse } from "../../../helpers/callback/httpResponse";
|
||||||
import { githubCallbackService } from "../services/http/githubCallback.service";
|
import { githubCallbackService } from "../services/http/githubCallback.service";
|
||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||||
import { getUserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation";
|
import { getUserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation";
|
||||||
import { githubCallbackSchema } from "../schemas/githubCallback.schema";
|
|
||||||
|
|
||||||
export const githubCallbackController = async (ctx: {
|
export const githubCallbackController = async (
|
||||||
set: Context["set"];
|
ctx: Context & { query: { code: string; callbackURI: string } }
|
||||||
query: Static<typeof githubCallbackSchema.query>;
|
) => {
|
||||||
headers: Static<typeof githubCallbackSchema.headers>;
|
|
||||||
}) => {
|
|
||||||
try {
|
try {
|
||||||
const userHeaderInfo = getUserHeaderInformation(ctx.headers["x-client-info"]);
|
const userHeaderInfo = getUserHeaderInformation(ctx);
|
||||||
|
|
||||||
const authToken = await githubCallbackService(ctx.query, userHeaderInfo);
|
const authToken = await githubCallbackService(ctx.query, userHeaderInfo);
|
||||||
return returnWriteResponse(ctx.set, 200, "Authenticated successfully!", {
|
return returnWriteResponse(ctx.set, 200, "Authenticated successfully!", {
|
||||||
|
|||||||
@ -1,18 +1,21 @@
|
|||||||
import { Context, Static } from "elysia";
|
import { Context } from "elysia";
|
||||||
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
||||||
import { githubRequestService } from "../services/http/githubRequest.service";
|
import { githubRequestService } from "../services/http/githubRequest.service";
|
||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||||
import { githubRequestSchema } from "../schemas/githubRequest.schema";
|
|
||||||
|
|
||||||
export const githubRequestController = async (ctx: {
|
export const githubRequestController = async (
|
||||||
set: Context["set"];
|
ctx: Context & { query: { callback?: string } },
|
||||||
query: Static<typeof githubRequestSchema.query>;
|
) => {
|
||||||
}) => {
|
|
||||||
try {
|
try {
|
||||||
const loginUrl = await githubRequestService(ctx.query.callback);
|
const loginUrl = await githubRequestService(ctx.query.callback);
|
||||||
return returnReadResponse(ctx.set, 200, "GitHub login URL created successfully.", {
|
return returnReadResponse(
|
||||||
endpointUrl: loginUrl,
|
ctx.set,
|
||||||
});
|
200,
|
||||||
|
"Login URL generated successfully",
|
||||||
|
{
|
||||||
|
endpointUrl: loginUrl,
|
||||||
|
},
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return mainErrorHandler(ctx.set, error);
|
return mainErrorHandler(ctx.set, error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,17 @@
|
|||||||
import { Context, Static } from "elysia";
|
import { Context } from "elysia";
|
||||||
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||||
import { googleCallbackService } from "../services/http/googleCallback.service";
|
import { googleCallbackService } from "../services/http/googleCallback.service";
|
||||||
import { getUserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation";
|
import { getUserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation";
|
||||||
import { googleCallbackSchema } from "../schemas/googleCallback.schema";
|
|
||||||
|
|
||||||
export const googleCallbackController = async (ctx: {
|
export const googleCallbackController = async (
|
||||||
set: Context["set"];
|
ctx: Context & { query: { code: string; state: string; callbackURI: string } }
|
||||||
query: Static<typeof googleCallbackSchema.query>;
|
) => {
|
||||||
headers: Static<typeof googleCallbackSchema.headers>;
|
|
||||||
}) => {
|
|
||||||
try {
|
try {
|
||||||
const userHeaderInfo = getUserHeaderInformation(ctx.headers["x-client-info"]);
|
const userHeaderInfo = getUserHeaderInformation(ctx);
|
||||||
|
|
||||||
const authToken = await googleCallbackService(ctx.query, userHeaderInfo);
|
const authToken = await googleCallbackService(ctx.query, userHeaderInfo);
|
||||||
return returnReadResponse(ctx.set, 200, "Authentication successful!", {
|
return returnReadResponse(ctx.set, 200, "Authenticated successfully!", {
|
||||||
authToken,
|
authToken,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -1,16 +1,14 @@
|
|||||||
import { Context, Static } from "elysia";
|
import { Context } from "elysia";
|
||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||||
import { googleRequestService } from "../services/http/googleRequest.service";
|
import { googleRequestService } from "../services/http/googleRequest.service";
|
||||||
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
||||||
import { googleRequestSchema } from "../schemas/googleRequest.schema";
|
|
||||||
|
|
||||||
export const googleRequestController = async (ctx: {
|
export const googleRequestController = async (
|
||||||
set: Context["set"];
|
ctx: Context & { query: { callback?: string } }
|
||||||
query: Static<typeof googleRequestSchema.query>;
|
) => {
|
||||||
}) => {
|
|
||||||
try {
|
try {
|
||||||
const loginUrl = await googleRequestService(ctx.query.callback);
|
const loginUrl = await googleRequestService(ctx.query.callback);
|
||||||
return returnReadResponse(ctx.set, 200, "Google login URL created successfully.", {
|
return returnReadResponse(ctx.set, 200, "Google login url created!", {
|
||||||
endpointUrl: loginUrl,
|
endpointUrl: loginUrl,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -9,19 +9,13 @@ import { tokenValidationController } from "./controllers/tokenValidation.control
|
|||||||
import { logoutController } from "./controllers/logout.controller";
|
import { logoutController } from "./controllers/logout.controller";
|
||||||
import { tokenValidationSchema } from "./schemas/tokenValidation.schema";
|
import { tokenValidationSchema } from "./schemas/tokenValidation.schema";
|
||||||
import { getOauthProvidersSchema } from "./schemas/getOauthProviders.schema";
|
import { getOauthProvidersSchema } from "./schemas/getOauthProviders.schema";
|
||||||
import { getCallbackProviderUrlSchema } from "./schemas/getCallbackProviderUrl.schema";
|
|
||||||
import { googleRequestSchema } from "./schemas/googleRequest.schema";
|
|
||||||
import { googleCallbackSchema } from "./schemas/googleCallback.schema";
|
|
||||||
import { githubRequestSchema } from "./schemas/githubRequest.schema";
|
|
||||||
import { githubCallbackSchema } from "./schemas/githubCallback.schema";
|
|
||||||
import { logoutSchema } from "./schemas/logout.schema";
|
|
||||||
|
|
||||||
export const authModule = new Elysia({ prefix: "/auth", tags: ["Authentication"] })
|
export const authModule = new Elysia({ prefix: "/auth", tags: ["Authentication"] })
|
||||||
.post("/token/validate", tokenValidationController, tokenValidationSchema)
|
.post("/token/validate", tokenValidationController, tokenValidationSchema)
|
||||||
.get("/providers", getOauthProvidersController, getOauthProvidersSchema)
|
.get("/providers", getOauthProvidersController, getOauthProvidersSchema)
|
||||||
.get("/providers/:name/callback", getCallbackProviderUrlController, getCallbackProviderUrlSchema)
|
.get("/providers/:name/callback", getCallbackProviderUrlController)
|
||||||
.get("/google", googleRequestController, googleRequestSchema)
|
.get("/github", githubRequestController)
|
||||||
.get("/google/callback", googleCallbackController, googleCallbackSchema)
|
.get("/github/callback", githubCallbackController)
|
||||||
.get("/github", githubRequestController, githubRequestSchema)
|
.get("/google", googleRequestController)
|
||||||
.get("/github/callback", githubCallbackController, githubCallbackSchema)
|
.get("/google/callback", googleCallbackController)
|
||||||
.post("/logout", logoutController, logoutSchema);
|
.post("/logout", logoutController);
|
||||||
|
|||||||
@ -1,45 +0,0 @@
|
|||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const getCallbackProviderUrlSchema = {
|
|
||||||
detail: {
|
|
||||||
summary: "Get the callback URL of oauth provider",
|
|
||||||
description:
|
|
||||||
"After users have successfully completed the authentication process on the OAuth provider page, they will be redirected to the callback page on the frontend. This endpoint aims to obtain the actual endpoint for each OAuth response handler.",
|
|
||||||
responses: {
|
|
||||||
200: {
|
|
||||||
description: "The callback URL on the provider has been found.",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
success: {
|
|
||||||
type: "boolean",
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
type: "number",
|
|
||||||
default: 200,
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
type: "string",
|
|
||||||
default: "The callback URL on the provider has been found.",
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
callback_url: {
|
|
||||||
type: "string",
|
|
||||||
description: "The callback URL on the provider.",
|
|
||||||
example: "auth/google/callback",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { success } from "zod";
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
||||||
|
|
||||||
export const getOauthProvidersSchema = {
|
export const getOauthProvidersSchema = {
|
||||||
|
|||||||
@ -1,57 +0,0 @@
|
|||||||
import { t } from "elysia";
|
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const githubCallbackSchema = {
|
|
||||||
headers: t.Object({
|
|
||||||
"x-client-info": t.String({
|
|
||||||
examples: [
|
|
||||||
'{"os":"Windows","osVersion":"10","browser":"Chrome","browserVersion":"89.0.4389.82","deviceType":"Desktop","ip":"192.168.1.1"}',
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
query: t.Object({
|
|
||||||
code: t.String({ examples: ["4/0AY0e-xxxxxxxxx"] }),
|
|
||||||
callbackURI: t.String({ examples: ["https://example.com/auth/github/callback"] }),
|
|
||||||
}),
|
|
||||||
detail: {
|
|
||||||
summary: "GitHub OAuth callback endpoint",
|
|
||||||
description:
|
|
||||||
"Handles the callback from GitHub OAuth and processes the authentication response. This endpoint also processes the account provisioning if the user is logging in for the first time.",
|
|
||||||
responses: {
|
|
||||||
200: {
|
|
||||||
description: "Authentication successful",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
success: {
|
|
||||||
type: "boolean",
|
|
||||||
example: true,
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
type: "number",
|
|
||||||
example: 200,
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
type: "string",
|
|
||||||
example: "Authentication successful",
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
authToken: {
|
|
||||||
type: "string",
|
|
||||||
description: "JWT token for authenticated user",
|
|
||||||
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
import { t } from "elysia";
|
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const githubRequestSchema = {
|
|
||||||
query: t.Object({
|
|
||||||
callback: t.Optional(
|
|
||||||
t.String({
|
|
||||||
description: "The callback URL to redirect after GitHub authentication. It should be URL-encoded if provided.",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
detail: {
|
|
||||||
summary: "Initiate GitHub OAuth flow",
|
|
||||||
description:
|
|
||||||
"This endpoint initiates the GitHub OAuth flow by redirecting the user to GitHub's authentication page.",
|
|
||||||
responses: {
|
|
||||||
200: {
|
|
||||||
description: "GitHub login URL created successfully.",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
success: {
|
|
||||||
type: "boolean",
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
type: "number",
|
|
||||||
default: 200,
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
type: "string",
|
|
||||||
default: "GitHub login URL created successfully.",
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
endpointUrl: {
|
|
||||||
type: "string",
|
|
||||||
description: "The URL to redirect the user for GitHub authentication.",
|
|
||||||
example:
|
|
||||||
"https://github.com/login/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code&scope=user:email",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
import { t } from "elysia";
|
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const googleCallbackSchema = {
|
|
||||||
headers: t.Object({
|
|
||||||
"x-client-info": t.String({
|
|
||||||
examples: [
|
|
||||||
'{"os":"Windows","osVersion":"10","browser":"Chrome","browserVersion":"89.0.4389.82","deviceType":"Desktop","ip":"192.168.1.1"}',
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
query: t.Object({
|
|
||||||
code: t.String({ examples: ["4/0AY0e-xxxxxxxxx"] }),
|
|
||||||
state: t.String({ examples: ["random_state_string"] }),
|
|
||||||
callbackURI: t.String({ examples: ["https://example.com/auth/google/callback"] }),
|
|
||||||
}),
|
|
||||||
detail: {
|
|
||||||
summary: "Google OAuth callback endpoint",
|
|
||||||
description:
|
|
||||||
"Handles the callback from Google OAuth and processes the authentication response. This endpoint also processes the account provisioning if the user is logging in for the first time.",
|
|
||||||
responses: {
|
|
||||||
200: {
|
|
||||||
description: "Authentication successful",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
success: {
|
|
||||||
type: "boolean",
|
|
||||||
example: true,
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
type: "number",
|
|
||||||
example: 200,
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
type: "string",
|
|
||||||
example: "Authentication successful",
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
authToken: {
|
|
||||||
type: "string",
|
|
||||||
description: "JWT token for authenticated user",
|
|
||||||
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
import { t } from "elysia";
|
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const googleRequestSchema = {
|
|
||||||
query: t.Object({
|
|
||||||
callback: t.Optional(
|
|
||||||
t.String({
|
|
||||||
description: "The callback URL to redirect after Google authentication. It should be URL-encoded if provided.",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
detail: {
|
|
||||||
summary: "Initiate Google OAuth flow",
|
|
||||||
description:
|
|
||||||
"This endpoint initiates the Google OAuth flow by redirecting the user to Google's authentication page.",
|
|
||||||
responses: {
|
|
||||||
200: {
|
|
||||||
description: "Google login URL created successfully.",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
success: {
|
|
||||||
type: "boolean",
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
type: "number",
|
|
||||||
default: 200,
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
type: "string",
|
|
||||||
default: "Google login URL created successfully.",
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
endpointUrl: {
|
|
||||||
type: "string",
|
|
||||||
description: "The URL to redirect the user for Google authentication.",
|
|
||||||
example:
|
|
||||||
"https://accounts.google.com/o/oauth2/v2/auth?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code&scope=email%20profile",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -1,97 +0,0 @@
|
|||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const logoutSchema = {
|
|
||||||
detail: {
|
|
||||||
summary: "Logout endpoint",
|
|
||||||
description: "Logs out the authenticated user by invalidating their session or token.",
|
|
||||||
responses: {
|
|
||||||
200: {
|
|
||||||
description: "Logout successful",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
success: {
|
|
||||||
type: "boolean",
|
|
||||||
example: true,
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
type: "number",
|
|
||||||
example: 200,
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
type: "string",
|
|
||||||
example: "Logout successful",
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: "object",
|
|
||||||
description: "Details about the logout operation. This only returned in development environment.",
|
|
||||||
properties: {
|
|
||||||
id: {
|
|
||||||
type: "string",
|
|
||||||
example: "123e4567-e89b-12d3-a456-426614174000",
|
|
||||||
},
|
|
||||||
isAuthenticated: {
|
|
||||||
type: "boolean",
|
|
||||||
example: false,
|
|
||||||
},
|
|
||||||
validUntil: {
|
|
||||||
type: "string",
|
|
||||||
format: "date-time",
|
|
||||||
example: "2024-12-31T23:59:59Z",
|
|
||||||
},
|
|
||||||
userId: {
|
|
||||||
type: "string",
|
|
||||||
example: "user_12345",
|
|
||||||
},
|
|
||||||
deletedAt: {
|
|
||||||
type: "string",
|
|
||||||
format: "date-time",
|
|
||||||
example: "2024-01-02T12:00:00Z",
|
|
||||||
},
|
|
||||||
createdAt: {
|
|
||||||
type: "string",
|
|
||||||
format: "date-time",
|
|
||||||
example: "2024-01-01T12:00:00Z",
|
|
||||||
},
|
|
||||||
updatedAt: {
|
|
||||||
type: "string",
|
|
||||||
format: "date-time",
|
|
||||||
example: "2024-01-02T12:00:00Z",
|
|
||||||
},
|
|
||||||
deviceType: {
|
|
||||||
type: "string",
|
|
||||||
example: "Desktop",
|
|
||||||
},
|
|
||||||
deviceOs: {
|
|
||||||
type: "string",
|
|
||||||
example: "Windows 10",
|
|
||||||
},
|
|
||||||
deviceIp: {
|
|
||||||
type: "string",
|
|
||||||
example: "192.168.1.1",
|
|
||||||
},
|
|
||||||
browser: {
|
|
||||||
type: "string",
|
|
||||||
example: "Chrome 89.0.4389.82",
|
|
||||||
},
|
|
||||||
isOnline: {
|
|
||||||
type: "boolean",
|
|
||||||
example: false,
|
|
||||||
},
|
|
||||||
lastOnline: {
|
|
||||||
type: "string",
|
|
||||||
format: "date-time",
|
|
||||||
example: "2024-01-02T12:00:00Z",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import { Context, Static } from "elysia";
|
|
||||||
import { returnWriteResponse } from "../../../helpers/callback/httpResponse";
|
|
||||||
import { addItemToCollectionBySytemSchema } from "../schemas/addItemToCollectionBySytem.schema";
|
|
||||||
import { addItemToCollectionBySystemService } from "../services/addItemToCollectionBySystem.service";
|
|
||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
|
||||||
|
|
||||||
export const addItemToCollectionBySytemController = async (ctx: {
|
|
||||||
set: Context["set"];
|
|
||||||
headers: Static<typeof addItemToCollectionBySytemSchema.headers>;
|
|
||||||
body: Static<typeof addItemToCollectionBySytemSchema.body>;
|
|
||||||
}) => {
|
|
||||||
try {
|
|
||||||
const savedItem = await addItemToCollectionBySystemService({
|
|
||||||
cookie: ctx.headers.cookie,
|
|
||||||
collectionName: ctx.body.name,
|
|
||||||
mediaId: ctx.body.itemId,
|
|
||||||
});
|
|
||||||
return returnWriteResponse(ctx.set, 200, "Item added to collection successfully", savedItem);
|
|
||||||
} catch (error) {
|
|
||||||
return mainErrorHandler(ctx.set, error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import { Context, Static } from "elysia";
|
|
||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
|
||||||
import { returnWriteResponse } from "../../../helpers/callback/httpResponse";
|
|
||||||
import { removeItemFromCollectionBySystemService } from "../services/removeItemFromCollectionBySystem.service";
|
|
||||||
import { removeItemFromCollectionBySytemSchema } from "../schemas/removeItemFromCollectionBySytem.schema";
|
|
||||||
|
|
||||||
export const removeItemFromCollectionBySytemController = async (ctx: {
|
|
||||||
set: Context["set"];
|
|
||||||
headers: Static<typeof removeItemFromCollectionBySytemSchema.headers>;
|
|
||||||
body: Static<typeof removeItemFromCollectionBySytemSchema.body>;
|
|
||||||
}) => {
|
|
||||||
try {
|
|
||||||
const removedItem = await removeItemFromCollectionBySystemService({
|
|
||||||
cookie: ctx.headers.cookie,
|
|
||||||
collectionName: ctx.body.name,
|
|
||||||
mediaId: ctx.body.itemId,
|
|
||||||
});
|
|
||||||
return returnWriteResponse(ctx.set, 200, "Item removed from collection successfully", removedItem);
|
|
||||||
} catch (error) {
|
|
||||||
return mainErrorHandler(ctx.set, error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
import Elysia from "elysia";
|
|
||||||
import { addItemToCollectionBySytemController } from "./controllers/addItemToCollectionBySytem.controller";
|
|
||||||
import { addItemToCollectionBySytemSchema } from "./schemas/addItemToCollectionBySytem.schema";
|
|
||||||
import { removeItemFromCollectionBySytemController } from "./controllers/removeItemFromCollectionBySytem.controller";
|
|
||||||
import { removeItemFromCollectionBySytemSchema } from "./schemas/removeItemFromCollectionBySytem.schema";
|
|
||||||
|
|
||||||
export const collectionModule = new Elysia({ prefix: "/collections", tags: ["Collections"] })
|
|
||||||
.post("/sys", addItemToCollectionBySytemController, addItemToCollectionBySytemSchema)
|
|
||||||
.delete("/sys", removeItemFromCollectionBySytemController, removeItemFromCollectionBySytemSchema);
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
import slugify from "slugify";
|
|
||||||
import { AppError } from "../../../helpers/error/instances/app";
|
|
||||||
import { prisma } from "../../../utils/databases/prisma/connection";
|
|
||||||
|
|
||||||
export type DeleteUserCollectionBySystemPayload = {
|
|
||||||
userId: string;
|
|
||||||
collectionName: string;
|
|
||||||
itemId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteItemInUserCollectionBySystemRepository = async (payload: DeleteUserCollectionBySystemPayload) => {
|
|
||||||
try {
|
|
||||||
return await prisma.collection.update({
|
|
||||||
where: {
|
|
||||||
slug_ownerId: {
|
|
||||||
slug: slugify(payload.collectionName, { lower: true }),
|
|
||||||
ownerId: payload.userId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
media_saved: {
|
|
||||||
deleteMany: {
|
|
||||||
mediaId: payload.itemId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw new AppError(500, "Failed to remove item from collection", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
import slugify from "slugify";
|
|
||||||
import { AppError } from "../../../helpers/error/instances/app";
|
|
||||||
import { prisma } from "../../../utils/databases/prisma/connection";
|
|
||||||
import { generateUUIDv7 } from "../../../helpers/databases/uuidv7";
|
|
||||||
import { Prisma } from "@prisma/client";
|
|
||||||
|
|
||||||
export interface UpsertUserCollectionRepositoryPayload {
|
|
||||||
userId: string;
|
|
||||||
collectionName: string;
|
|
||||||
mediaConnectId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const upsertUserCollectionBySystemRepository = async (payload: UpsertUserCollectionRepositoryPayload) => {
|
|
||||||
try {
|
|
||||||
return await prisma.collection.upsert({
|
|
||||||
where: {
|
|
||||||
slug_ownerId: {
|
|
||||||
slug: slugify(payload.collectionName, { lower: true }),
|
|
||||||
ownerId: payload.userId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: {
|
|
||||||
media_saved: {
|
|
||||||
create: {
|
|
||||||
id: generateUUIDv7(),
|
|
||||||
media: {
|
|
||||||
connect: {
|
|
||||||
id: payload.mediaConnectId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
id: generateUUIDv7(),
|
|
||||||
name: payload.collectionName,
|
|
||||||
slug: slugify(payload.collectionName, { lower: true }),
|
|
||||||
owner: {
|
|
||||||
connect: {
|
|
||||||
id: payload.userId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
media_saved: {
|
|
||||||
create: {
|
|
||||||
id: generateUUIDv7(),
|
|
||||||
media: {
|
|
||||||
connect: {
|
|
||||||
id: payload.mediaConnectId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2002")
|
|
||||||
throw new AppError(400, "Media item is already in the collection");
|
|
||||||
throw new AppError(500, "Failed to upsert user collection");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
import { t } from "elysia";
|
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const addItemToCollectionBySytemSchema = {
|
|
||||||
headers: t.Object({
|
|
||||||
cookie: t.String({ description: "Authentication token in cookie format, e.g., auth_token=your_jwt_token;" }),
|
|
||||||
}),
|
|
||||||
body: t.Object({
|
|
||||||
name: t.String({ description: "Name of the collection to which the item will be added" }),
|
|
||||||
itemId: t.String({ description: "ID of the item to be added to the collection", examples: ["12345"] }),
|
|
||||||
}),
|
|
||||||
detail: {
|
|
||||||
summary: "Add an item to a collection",
|
|
||||||
description: "Adds a specified item to a collection identified by its name.",
|
|
||||||
responses: {
|
|
||||||
200: {
|
|
||||||
description: "The item was successfully added to the collection.",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
success: { type: "boolean", example: true },
|
|
||||||
status: { type: "number", example: 200 },
|
|
||||||
message: { type: "string", example: "Item added to collection successfully" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
import { t } from "elysia";
|
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const removeItemFromCollectionBySytemSchema = {
|
|
||||||
headers: t.Object({
|
|
||||||
cookie: t.String({ description: "Authentication token in cookie format, e.g., auth_token=your_jwt_token;" }),
|
|
||||||
}),
|
|
||||||
body: t.Object({
|
|
||||||
name: t.String({ description: "Name of the collection to which the item will be added" }),
|
|
||||||
itemId: t.String({ description: "ID of the item to be added to the collection", examples: ["12345"] }),
|
|
||||||
}),
|
|
||||||
detail: {
|
|
||||||
summary: "Remove an item from a collection",
|
|
||||||
description: "Removes a specified item from a collection identified by its name.",
|
|
||||||
responses: {
|
|
||||||
200: {
|
|
||||||
description: "The item was successfully removed from the collection.",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
success: { type: "boolean", example: true },
|
|
||||||
status: { type: "number", example: 200 },
|
|
||||||
message: { type: "string", example: "Item removed from collection successfully" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
import { parse } from "cookie";
|
|
||||||
import { tokenValidationService } from "../../auth/services/http/tokenValidation.service";
|
|
||||||
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
|
||||||
import { upsertUserCollectionBySystemRepository } from "../repositories/upsertUserCollectionBySystem.repository";
|
|
||||||
|
|
||||||
export type AddItemToCollectionPayload = {
|
|
||||||
cookie: string;
|
|
||||||
collectionName: string;
|
|
||||||
mediaId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addItemToCollectionBySystemService = async (payload: AddItemToCollectionPayload) => {
|
|
||||||
try {
|
|
||||||
const { auth_token } = parse(payload.cookie);
|
|
||||||
const userData = await tokenValidationService(auth_token as string);
|
|
||||||
return await upsertUserCollectionBySystemRepository({
|
|
||||||
userId: userData.user.id,
|
|
||||||
collectionName: payload.collectionName,
|
|
||||||
mediaConnectId: payload.mediaId,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
ErrorForwarder(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
import { parse } from "cookie";
|
|
||||||
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
|
||||||
import { tokenValidationService } from "../../auth/services/http/tokenValidation.service";
|
|
||||||
import { deleteItemInUserCollectionBySystemRepository } from "../repositories/deleteItemInUserCollectionBySystem.repository";
|
|
||||||
|
|
||||||
export type RemoveItemFromCollectionPayload = {
|
|
||||||
cookie: string;
|
|
||||||
collectionName: string;
|
|
||||||
mediaId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeItemFromCollectionBySystemService = async (payload: RemoveItemFromCollectionPayload) => {
|
|
||||||
try {
|
|
||||||
const { auth_token } = parse(payload.cookie);
|
|
||||||
const { user } = await tokenValidationService(auth_token as string);
|
|
||||||
return await deleteItemInUserCollectionBySystemRepository({
|
|
||||||
userId: user.id,
|
|
||||||
collectionName: payload.collectionName,
|
|
||||||
itemId: payload.mediaId,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
ErrorForwarder(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,14 +1,17 @@
|
|||||||
import { AppError } from "../../../../helpers/error/instances/app";
|
import { AppError } from "../../../../helpers/error/instances/app";
|
||||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||||
import { selectMediaIdFromSlugRepository } from "../../../media/repositories/SELECT/selectMediaIdFromSlug.repository";
|
import { getMediaIdFromSlugRepository } from "../../../media/repositories/GET/getMediaIdFromSlug.repository";
|
||||||
import { GetEpisodeDetailsParams } from "../../controllers/getEpisodeDetails.controller";
|
import { GetEpisodeDetailsParams } from "../../controllers/getEpisodeDetails.controller";
|
||||||
import { getEpisodeDetailsRepository } from "../../repositories/GET/getEpisodeDetails.repository";
|
import { getEpisodeDetailsRepository } from "../../repositories/GET/getEpisodeDetails.repository";
|
||||||
|
|
||||||
export const getEpisodeDetailsService = async (params: GetEpisodeDetailsParams) => {
|
export const getEpisodeDetailsService = async (
|
||||||
|
params: GetEpisodeDetailsParams,
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
if (!params.mediaSlug || !params.episode) throw new AppError(400, "Media slug and episode are required.");
|
if (!params.mediaSlug || !params.episode)
|
||||||
|
throw new AppError(400, "Media slug and episode are required.");
|
||||||
|
|
||||||
const mediaId = await selectMediaIdFromSlugRepository(params.mediaSlug);
|
const mediaId = await getMediaIdFromSlugRepository(params.mediaSlug);
|
||||||
if (!mediaId?.id) throw new AppError(404, "Media not found.");
|
if (!mediaId?.id) throw new AppError(404, "Media not found.");
|
||||||
|
|
||||||
const result = await getEpisodeDetailsRepository({
|
const result = await getEpisodeDetailsRepository({
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
import { Context } from "elysia";
|
|
||||||
import { returnWriteResponse } from "../../../helpers/callback/httpResponse";
|
|
||||||
import { clearHeroBannerService } from "../services/clearHeroBanner.service";
|
|
||||||
|
|
||||||
export const clearHeroBannerController = async (ctx: { set: Context["set"] }) => {
|
|
||||||
const cacheCleared = await clearHeroBannerService();
|
|
||||||
return returnWriteResponse(ctx.set, 200, "Hero banner cache flushed successfully", cacheCleared);
|
|
||||||
};
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
import Elysia from "elysia";
|
|
||||||
import { clearHeroBannerController } from "./controllers/clearHeroBanner.controller";
|
|
||||||
|
|
||||||
export const flushCacheModule = new Elysia({ prefix: "/flush-cache" }).put("/hero-banner", clearHeroBannerController);
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
import { redisKey } from "../../../config/redis/key";
|
|
||||||
import { AppError } from "../../../helpers/error/instances/app";
|
|
||||||
import { redis } from "../../../utils/databases/redis/connection";
|
|
||||||
|
|
||||||
export const clearHeroBannerService = async () => {
|
|
||||||
try {
|
|
||||||
const cache = await redis.del(redisKey.find((key) => key.name === "HERO_BANNER")?.key || "");
|
|
||||||
return cache > 0; // Returns true if cache was cleared, false if it was not found
|
|
||||||
} catch (error) {
|
|
||||||
throw new AppError(500, "Failed to clear hero banner cache", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,16 +1,17 @@
|
|||||||
import { Context, Static } from "elysia";
|
import { Context } from "elysia";
|
||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||||
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
||||||
import { getActiveHeroBannerService } from "../services/getActiveHeroBanner.service";
|
import { getActiveHeroBannerService } from "../services/getActiveHeroBanner.service";
|
||||||
import { getActiveHeroBannerSchema } from "../schemas/getActiveHeroBanner.schema";
|
|
||||||
|
|
||||||
export const getActiveHeroBannerController = async (ctx: {
|
export const getActiveHeroBannerController = async (ctx: Context) => {
|
||||||
set: Context["set"];
|
|
||||||
header: Static<typeof getActiveHeroBannerSchema.headers>;
|
|
||||||
}) => {
|
|
||||||
try {
|
try {
|
||||||
const response = await getActiveHeroBannerService({ cookie: ctx.header?.cookie });
|
const response = await getActiveHeroBannerService();
|
||||||
return returnReadResponse(ctx.set, 200, "Active hero banners fetched successfully", response);
|
return returnReadResponse(
|
||||||
|
ctx.set,
|
||||||
|
200,
|
||||||
|
"Active hero banners fetched successfully",
|
||||||
|
response,
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return mainErrorHandler(ctx.set, error);
|
return mainErrorHandler(ctx.set, error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { AppError } from "../../../../helpers/error/instances/app";
|
import { AppError } from "../../../../helpers/error/instances/app";
|
||||||
import { prisma } from "../../../../utils/databases/prisma/connection";
|
import { prisma } from "../../../../utils/databases/prisma/connection";
|
||||||
|
|
||||||
export const findAllActiveHeroBannerRepository = async (userId?: string) => {
|
export const findAllActiveHeroBannerRepository = async () => {
|
||||||
try {
|
try {
|
||||||
return await prisma.heroBanner.findMany({
|
return await prisma.heroBanner.findMany({
|
||||||
where: {
|
where: {
|
||||||
@ -20,36 +20,6 @@ export const findAllActiveHeroBannerRepository = async (userId?: string) => {
|
|||||||
startDate: "asc",
|
startDate: "asc",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
select: {
|
|
||||||
orderPriority: true,
|
|
||||||
imageUrl: true,
|
|
||||||
media: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
title: true,
|
|
||||||
slug: true,
|
|
||||||
pictureLarge: true,
|
|
||||||
synopsis: true,
|
|
||||||
genres: {
|
|
||||||
select: {
|
|
||||||
slug: true,
|
|
||||||
name: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_count: {
|
|
||||||
select: {
|
|
||||||
inCollections: {
|
|
||||||
where: {
|
|
||||||
collection: {
|
|
||||||
ownerId: userId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new AppError(500, "Failed to fetch active hero banners", error);
|
throw new AppError(500, "Failed to fetch active hero banners", error);
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
import { t } from "elysia";
|
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const getActiveHeroBannerSchema = {
|
|
||||||
headers: t.Object({
|
|
||||||
cookie: t.Optional(t.String()),
|
|
||||||
}),
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -1,44 +1,33 @@
|
|||||||
|
import { redisKey } from "../../../config/redis/key";
|
||||||
import { AppError } from "../../../helpers/error/instances/app";
|
import { AppError } from "../../../helpers/error/instances/app";
|
||||||
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
|
||||||
import { tokenValidationService } from "../../auth/services/http/tokenValidation.service";
|
import { redis } from "../../../utils/databases/redis/connection";
|
||||||
import { findSystemPreferenceService } from "../../systemPreference/services/internal/findSystemPreference.service";
|
import { findSystemPreferenceService } from "../../systemPreference/services/internal/findSystemPreference.service";
|
||||||
import { findAllActiveHeroBannerRepository } from "../repositories/GET/findAllActiveHeroBanner.repository";
|
import { findAllActiveHeroBannerRepository } from "../repositories/GET/findAllActiveHeroBanner.repository";
|
||||||
|
|
||||||
export const getActiveHeroBannerService = async ({ cookie }: { cookie?: string }) => {
|
export const getActiveHeroBannerService = async () => {
|
||||||
try {
|
try {
|
||||||
const userId = cookie ? (await tokenValidationService(cookie)).user.id : undefined;
|
|
||||||
|
|
||||||
// Check if Hero Banner is enabled in system preferences
|
// Check if Hero Banner is enabled in system preferences
|
||||||
const isHeroBannerEnabled = await findSystemPreferenceService("HERO_BANNER_ENABLED", "boolean");
|
const isHeroBannerEnabled = await findSystemPreferenceService(
|
||||||
if (!isHeroBannerEnabled) throw new AppError(403, "Hero Banner is disabled");
|
"HERO_BANNER_ENABLED",
|
||||||
|
"boolean",
|
||||||
|
);
|
||||||
|
if (!isHeroBannerEnabled)
|
||||||
|
throw new AppError(403, "Hero Banner is disabled");
|
||||||
|
|
||||||
// Don’t implement caching just yet; implement collection caching first, then implement banner caching.
|
// Try to get active banners from Redis cache
|
||||||
// Please note that currently, a database query is still required to check the collections.
|
const cachedBanners = await redis.get(
|
||||||
// // Try to get active banners from Redis cache
|
`${redisKey.filter((key) => key.name === "HERO_BANNER")[0].key}`,
|
||||||
// const cachedBanners = await redis.get(`${redisKey.filter((key) => key.name === "HERO_BANNER")[0].key}`);
|
);
|
||||||
// if (cachedBanners) return JSON.parse(cachedBanners);
|
if (cachedBanners) return JSON.parse(cachedBanners);
|
||||||
|
|
||||||
// If not in cache, fetch from database and cache the result
|
// If not in cache, fetch from database and cache the result
|
||||||
const activeBanners = await findAllActiveHeroBannerRepository(userId);
|
const activeBanners = await findAllActiveHeroBannerRepository();
|
||||||
const constructedBanners = activeBanners.map((banner) => ({
|
await redis.set(
|
||||||
id: banner.media.id,
|
`${redisKey.filter((key) => key.name === "HERO_BANNER")[0].key}`,
|
||||||
title: banner.media.title,
|
JSON.stringify(activeBanners),
|
||||||
slug: banner.media.slug,
|
);
|
||||||
imageUrl: banner.imageUrl || banner.media.pictureLarge,
|
return activeBanners;
|
||||||
synopsis: banner.media.synopsis,
|
|
||||||
genres: banner.media.genres.map((genre) => ({
|
|
||||||
slug: genre.slug,
|
|
||||||
name: genre.name,
|
|
||||||
})),
|
|
||||||
isInCollection: banner.media._count.inCollections > 0,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// await redis.set(
|
|
||||||
// `${redisKey.filter((key) => key.name === "HERO_BANNER")[0].key}`,
|
|
||||||
// JSON.stringify(constructedBanners),
|
|
||||||
// );
|
|
||||||
|
|
||||||
return constructedBanners;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ErrorForwarder(error);
|
ErrorForwarder(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
|
import { Prisma } from "@prisma/client";
|
||||||
import { AppError } from "../../../helpers/error/instances/app";
|
import { AppError } from "../../../helpers/error/instances/app";
|
||||||
import { prisma } from "../../../utils/databases/prisma/connection";
|
import { prisma } from "../../../utils/databases/prisma/connection";
|
||||||
import { generateUUIDv7 } from "../../../helpers/databases/uuidv7";
|
import { generateUUIDv7 } from "../../../helpers/databases/uuidv7";
|
||||||
import { SystemAccountId } from "../../../config/account/system";
|
import { SystemAccountId } from "../../../config/account/system";
|
||||||
import { Static } from "elysia";
|
|
||||||
import { createHeroBannerSchema } from "../schemas/createHeroBanner.schema";
|
|
||||||
import { Prisma } from "@prisma/client";
|
|
||||||
|
|
||||||
export const insertHeroBannerRepository = async (payload: Static<typeof createHeroBannerSchema.body>) => {
|
export const insertHeroBannerRepository = async (
|
||||||
|
payload: Omit<Prisma.HeroBannerCreateInput, "id" | "createdBy">,
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
return await prisma.heroBanner.create({
|
return await prisma.heroBanner.create({
|
||||||
data: {
|
data: {
|
||||||
@ -16,9 +16,6 @@ export const insertHeroBannerRepository = async (payload: Static<typeof createHe
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2002") {
|
|
||||||
throw new AppError(400, "A hero banner with the order priority already exists", error);
|
|
||||||
}
|
|
||||||
throw new AppError(500, "Failed to insert hero banner", error);
|
throw new AppError(500, "Failed to insert hero banner", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,18 +3,45 @@ import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|||||||
|
|
||||||
export const createHeroBannerSchema = {
|
export const createHeroBannerSchema = {
|
||||||
body: t.Object({
|
body: t.Object({
|
||||||
orderPriority: t.Optional(
|
isClickable: t.Optional(
|
||||||
t.Number({ description: "The priority order of the hero banner. Lower numbers indicate higher priority." }),
|
t.Boolean({
|
||||||
),
|
description: "Indicates whether the hero banner is clickable",
|
||||||
mediaId: t.String({ description: "The ID of the media associated with the hero banner" }),
|
|
||||||
imageUrl: t.Optional(
|
|
||||||
t.String({
|
|
||||||
description:
|
|
||||||
"The URL of the image used in the hero banner. If not provided, a thumbnail image of the media will be used.",
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
startDate: t.Date({ description: "The start date for the hero banner in ISO 8601 format" }),
|
title: t.Optional(
|
||||||
endDate: t.Date({ description: "The end date for the hero banner in ISO 8601 format" }),
|
t.String({
|
||||||
|
description: "The title of the hero banner",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
tags: t.Array(t.String(), {
|
||||||
|
description: "An array of tags associated with the hero banner",
|
||||||
|
}),
|
||||||
|
description: t.Optional(
|
||||||
|
t.String({
|
||||||
|
description: "A brief description of the hero banner",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
buttonContent: t.Optional(
|
||||||
|
t.String({
|
||||||
|
description: "The text content of the button on the hero banner",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
buttonLink: t.Optional(
|
||||||
|
t.String({
|
||||||
|
description: "The URL that the button on the hero banner links to",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
imageUrl: t.Optional(
|
||||||
|
t.String({
|
||||||
|
description: "The URL of the image used in the hero banner",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
startDate: t.String({
|
||||||
|
description: "The start date for the hero banner in ISO 8601 format",
|
||||||
|
}),
|
||||||
|
endDate: t.String({
|
||||||
|
description: "The end date for the hero banner in ISO 8601 format",
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
detail: {
|
detail: {
|
||||||
summary: "Create a new hero banner",
|
summary: "Create a new hero banner",
|
||||||
@ -37,16 +64,17 @@ export const createHeroBannerSchema = {
|
|||||||
"The created hero banner object. This field is returned only if the environment is running in development mode.",
|
"The created hero banner object. This field is returned only if the environment is running in development mode.",
|
||||||
properties: {
|
properties: {
|
||||||
id: { type: "string", description: "The ID of the created hero banner" },
|
id: { type: "string", description: "The ID of the created hero banner" },
|
||||||
orderPriority: {
|
isClickable: { type: "boolean", description: "Indicates whether the hero banner is clickable" },
|
||||||
type: "number",
|
title: { type: "string", description: "The title of the hero banner" },
|
||||||
description: "The priority order of the hero banner. Lower numbers indicate higher priority.",
|
tags: {
|
||||||
},
|
type: "array",
|
||||||
mediaId: { type: "string", description: "The ID of the media associated with the hero banner" },
|
items: { type: "string" },
|
||||||
imageUrl: {
|
description: "An array of tags associated with the hero banner",
|
||||||
type: "string",
|
|
||||||
description:
|
|
||||||
"The URL of the image used in the hero banner. If not provided, a thumbnail image of the media will be used.",
|
|
||||||
},
|
},
|
||||||
|
description: { type: "string", description: "A brief description of the hero banner" },
|
||||||
|
buttonContent: { type: "string", description: "The text content of the button on the hero banner" },
|
||||||
|
buttonLink: { type: "string", description: "The URL that the button on the hero banner links to" },
|
||||||
|
imageUrl: { type: "string", description: "The URL of the image used in the hero banner" },
|
||||||
startDate: {
|
startDate: {
|
||||||
type: "string",
|
type: "string",
|
||||||
format: "date-time",
|
format: "date-time",
|
||||||
|
|||||||
@ -1,20 +1,27 @@
|
|||||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||||
import { MediaEpisodeInfoResponse } from "../../types/mediaEpisodeInfo.type";
|
import { MediaEpisodeInfoResponse } from "../../types/mediaEpisodeInfo.type";
|
||||||
|
import { getMediaByMalIdRepository } from "../../../media/repositories/GET/getMediaByMalId.repository";
|
||||||
import { AppError } from "../../../../helpers/error/instances/app";
|
import { AppError } from "../../../../helpers/error/instances/app";
|
||||||
import { SystemAccountId } from "../../../../config/account/system";
|
import { SystemAccountId } from "../../../../config/account/system";
|
||||||
import { bulkInsertEpisodesRepository } from "../../repositories/bulkInsertEpisodes.repository";
|
import { bulkInsertEpisodesRepository } from "../../repositories/bulkInsertEpisodes.repository";
|
||||||
import { getEpisodeReferenceAPI } from "../../../../config/apis/jikan/episode.reference";
|
import { getEpisodeReferenceAPI } from "../../../../config/apis/jikan/episode.reference";
|
||||||
import { selectMediaByMalIdRepository } from "../../../media/repositories/SELECT/selectMediaByMalId.repository";
|
|
||||||
|
|
||||||
export const bulkInsertEpisodeService = async (mal_id: number, page: number = 1) => {
|
export const bulkInsertEpisodeService = async (
|
||||||
|
mal_id: number,
|
||||||
|
page: number = 1,
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const episodeAPI = getEpisodeReferenceAPI(mal_id);
|
const episodeAPI = getEpisodeReferenceAPI(mal_id);
|
||||||
const episodeData: MediaEpisodeInfoResponse = await fetch(
|
const episodeData: MediaEpisodeInfoResponse = await fetch(
|
||||||
`${episodeAPI.baseURL}${episodeAPI.getEpisodeList}?page=${page}`,
|
`${episodeAPI.baseURL}${episodeAPI.getEpisodeList}?page=${page}`,
|
||||||
).then((res) => res.json());
|
).then((res) => res.json());
|
||||||
|
|
||||||
const mediaData = await selectMediaByMalIdRepository(mal_id);
|
const mediaData = await getMediaByMalIdRepository(mal_id);
|
||||||
if (!mediaData) throw new AppError(404, `Media with Mal ID ${mal_id} not found in database`);
|
if (!mediaData)
|
||||||
|
throw new AppError(
|
||||||
|
404,
|
||||||
|
`Media with Mal ID ${mal_id} not found in database`,
|
||||||
|
);
|
||||||
|
|
||||||
const insertedEpisodeData = [];
|
const insertedEpisodeData = [];
|
||||||
episodeData.data.forEach(async (episode) => {
|
episodeData.data.forEach(async (episode) => {
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { Static } from "elysia";
|
|
||||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||||
|
import { CreateHeroBannerRequestBody } from "../../controllers/createHeroBanner.controller";
|
||||||
import { insertHeroBannerRepository } from "../../repositories/insertHeroBanner.repository";
|
import { insertHeroBannerRepository } from "../../repositories/insertHeroBanner.repository";
|
||||||
import { createHeroBannerSchema } from "../../schemas/createHeroBanner.schema";
|
|
||||||
|
|
||||||
export const createHeroBannerService = async (payload: Static<typeof createHeroBannerSchema.body>) => {
|
export const createHeroBannerService = async (
|
||||||
|
payload: CreateHeroBannerRequestBody,
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
return await insertHeroBannerRepository(payload);
|
return await insertHeroBannerRepository(payload);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
import { Context, Static } from "elysia";
|
import { Context } from "elysia";
|
||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||||
import { getAllMediaService } from "../services/http/getAllMedia.service";
|
import { getAllMediaService } from "../services/http/getAllMedia.service";
|
||||||
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
||||||
import { getAllMediaSchema } from "../schemas/getAllMedia.schema";
|
|
||||||
|
|
||||||
export const getAllMediaController = async (ctx: {
|
export const getAllMediaController = async (
|
||||||
set: Context["set"];
|
ctx: Context & { query: { page: string } },
|
||||||
query: Static<typeof getAllMediaSchema.query>;
|
) => {
|
||||||
}) => {
|
|
||||||
try {
|
try {
|
||||||
const mediaData = await getAllMediaService(ctx.query.page);
|
const mediaData = await getAllMediaService(ctx.query.page);
|
||||||
return returnReadResponse(ctx.set, 200, "Media fetched successfully", mediaData);
|
return returnReadResponse(
|
||||||
|
ctx.set,
|
||||||
|
200,
|
||||||
|
"Media fetched successfully",
|
||||||
|
mediaData,
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return mainErrorHandler(ctx.set, error);
|
return mainErrorHandler(ctx.set, error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
import { Context, Static } from "elysia";
|
|
||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
|
||||||
import { getMediaBySlugSchema } from "../schemas/getMediaBySlug.schema";
|
|
||||||
import { getMediaBySlugService } from "../services/http/getMediaBySlug.service";
|
|
||||||
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
|
||||||
|
|
||||||
export const getMediaBySlugController = async (ctx: {
|
|
||||||
set: Context["set"];
|
|
||||||
params: Static<typeof getMediaBySlugSchema.params>;
|
|
||||||
}) => {
|
|
||||||
try {
|
|
||||||
const mediaData = await getMediaBySlugService(ctx.params.slug);
|
|
||||||
return returnReadResponse(ctx.set, 200, "Media fetched successfully", mediaData);
|
|
||||||
} catch (error) {
|
|
||||||
return mainErrorHandler(ctx.set, error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,9 +1,7 @@
|
|||||||
import Elysia from "elysia";
|
import Elysia from "elysia";
|
||||||
import { getAllMediaController } from "./controllers/getAllMedia.controller";
|
import { getAllMediaController } from "./controllers/getAllMedia.controller";
|
||||||
import { getMediaBySlugController } from "./controllers/getMediaBySlug.controller";
|
|
||||||
import { getMediaBySlugSchema } from "./schemas/getMediaBySlug.schema";
|
|
||||||
import { getAllMediaSchema } from "./schemas/getAllMedia.schema";
|
|
||||||
|
|
||||||
export const mediaModule = new Elysia({ prefix: "/media", tags: ["Media"] })
|
export const mediaModule = new Elysia({ prefix: "/media" }).get(
|
||||||
.get("/", getAllMediaController, getAllMediaSchema)
|
"/",
|
||||||
.get("/:slug", getMediaBySlugController, getMediaBySlugSchema);
|
getAllMediaController,
|
||||||
|
);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { AppError } from "../../../../helpers/error/instances/app";
|
import { AppError } from "../../../../helpers/error/instances/app";
|
||||||
import { mediaModel } from "../../model";
|
import { mediaModel } from "../../model";
|
||||||
|
|
||||||
export const selectAllMediaRepository = async (page: number) => {
|
export const getAllMediaRepository = async (page: number) => {
|
||||||
try {
|
try {
|
||||||
const limit = 10;
|
const limit = 10;
|
||||||
return await mediaModel.findMany({
|
return await mediaModel.findMany({
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { AppError } from "../../../../helpers/error/instances/app";
|
import { AppError } from "../../../../helpers/error/instances/app";
|
||||||
import { mediaModel } from "../../model";
|
import { mediaModel } from "../../model";
|
||||||
|
|
||||||
export const selectMediaByMalIdRepository = async (mal_id: number) => {
|
export const getMediaByMalIdRepository = async (mal_id: number) => {
|
||||||
try {
|
try {
|
||||||
return await mediaModel.findUnique({
|
return await mediaModel.findUnique({
|
||||||
where: { malId: mal_id },
|
where: { malId: mal_id },
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { AppError } from "../../../../helpers/error/instances/app";
|
import { AppError } from "../../../../helpers/error/instances/app";
|
||||||
import { mediaModel } from "../../model";
|
import { mediaModel } from "../../model";
|
||||||
|
|
||||||
export const selectMediaIdFromSlugRepository = async (slug: string) => {
|
export const getMediaIdFromSlugRepository = async (slug: string) => {
|
||||||
try {
|
try {
|
||||||
return await mediaModel.findUnique({
|
return await mediaModel.findUnique({
|
||||||
where: { slug },
|
where: { slug },
|
||||||
@ -1,12 +0,0 @@
|
|||||||
import { AppError } from "../../../../helpers/error/instances/app";
|
|
||||||
import { prisma } from "../../../../utils/databases/prisma/connection";
|
|
||||||
|
|
||||||
export const selectMediaBySlugRepository = async (slug: string) => {
|
|
||||||
try {
|
|
||||||
return await prisma.media.findUnique({
|
|
||||||
where: { slug },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw new AppError(500, "Failed to fetch media by slug", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
import { t } from "elysia";
|
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const getAllMediaSchema = {
|
|
||||||
query: t.Object({
|
|
||||||
page: t.String({ description: "The page number for pagination", default: "1" }),
|
|
||||||
}),
|
|
||||||
detail: {
|
|
||||||
summary: "Fetch all media items with pagination",
|
|
||||||
description:
|
|
||||||
"Fetch a paginated list of all media items. The 'page' query parameter can be used to specify the page number for pagination.",
|
|
||||||
responses: {
|
|
||||||
200: {
|
|
||||||
description: "Media items fetched successfully",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
success: { type: "boolean", example: true },
|
|
||||||
status: { type: "number", example: 200 },
|
|
||||||
message: { type: "string", example: "Media fetched successfully" },
|
|
||||||
data: {
|
|
||||||
type: "array",
|
|
||||||
items: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
status: { type: "string", example: "Finished Airing" },
|
|
||||||
id: { type: "string", example: "12345" },
|
|
||||||
title: { type: "string", example: "Example Media Title" },
|
|
||||||
slug: { type: "string", example: "example-media-title" },
|
|
||||||
malId: { type: "number", example: 67890 },
|
|
||||||
pictureMedium: { type: "string", example: "https://example.com/medium.jpg" },
|
|
||||||
pictureLarge: { type: "string", example: "https://example.com/large.jpg" },
|
|
||||||
country: { type: "string", example: "JP" },
|
|
||||||
score: { type: "number", example: 8.5 },
|
|
||||||
startAiring: { type: "string", format: "date-time", example: "2023-01-01T00:00:00Z" },
|
|
||||||
endAiring: { type: "string", format: "date-time", example: "2023-12-31T23:59:59Z" },
|
|
||||||
synopsis: { type: "string", example: "This is an example synopsis of the media item." },
|
|
||||||
ageRating: { type: "string", example: "PG-13" },
|
|
||||||
mediaType: { type: "string", example: "Anime" },
|
|
||||||
source: { type: "string", example: "Manga" },
|
|
||||||
onDraft: { type: "boolean", example: false },
|
|
||||||
uploadedBy: { type: "string", example: "admin" },
|
|
||||||
deletedAt: { type: "string", format: "date-time", nullable: true, example: null },
|
|
||||||
createdAt: { type: "string", format: "date-time", example: "2023-01-01T00:00:00Z" },
|
|
||||||
updatedAt: { type: "string", format: "date-time", example: "2023-01-02T00:00:00Z" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
import { t } from "elysia";
|
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|
||||||
|
|
||||||
export const getMediaBySlugSchema = {
|
|
||||||
params: t.Object({
|
|
||||||
slug: t.String({ description: "The slug of the media to fetch" }),
|
|
||||||
}),
|
|
||||||
detail: {
|
|
||||||
summary: "Fetch a media item by its slug",
|
|
||||||
description: "Fetch the specified media item using its slug. This endpoint returns the media details if found.",
|
|
||||||
responses: {
|
|
||||||
200: {
|
|
||||||
description: "Media item fetched successfully",
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
success: { type: "boolean", example: true },
|
|
||||||
status: { type: "number", example: 200 },
|
|
||||||
message: { type: "string", example: "Media fetched successfully" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies AppRouteSchema;
|
|
||||||
@ -1,11 +1,14 @@
|
|||||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||||
import { selectAllMediaRepository } from "../../repositories/SELECT/selectAllMedia.repository";
|
import { getAllMediaRepository } from "../../repositories/GET/getAllMedia.repository";
|
||||||
|
|
||||||
export const getAllMediaService = async (pagination: string) => {
|
export const getAllMediaService = async (pagination: string) => {
|
||||||
try {
|
try {
|
||||||
const page = /^\d+$/.test(pagination) && Number(pagination) > 0 ? Number(pagination) : 1;
|
const page =
|
||||||
|
/^\d+$/.test(pagination) && Number(pagination) > 0
|
||||||
|
? Number(pagination)
|
||||||
|
: 1;
|
||||||
|
|
||||||
return selectAllMediaRepository(page);
|
return getAllMediaRepository(page);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ErrorForwarder(error);
|
ErrorForwarder(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +0,0 @@
|
|||||||
import { AppError } from "../../../../helpers/error/instances/app";
|
|
||||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
|
||||||
import { selectMediaBySlugRepository } from "../../repositories/SELECT/selectMediaBySlug.repository";
|
|
||||||
|
|
||||||
export const getMediaBySlugService = async (slug: string) => {
|
|
||||||
try {
|
|
||||||
const mediaData = await selectMediaBySlugRepository(slug);
|
|
||||||
if (!mediaData) throw new AppError(404, "Media not found with the provided slug.");
|
|
||||||
|
|
||||||
return mediaData;
|
|
||||||
} catch (error) {
|
|
||||||
ErrorForwarder(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user