Compare commits

..

9 Commits

Author SHA1 Message Date
6556ac8354 Merge pull request 'fix-media' (#32) from fix-media into main
All checks were successful
Sync to GitHub / sync (push) Successful in 10s
Reviewed-on: #32
2026-04-24 10:31:42 +07:00
16d8c00d75 🗃️ db: fix schema drift and correct season enum
All checks were successful
Integration Tests / integration-tests (pull_request) Successful in 1m14s
2026-04-22 12:18:56 +07:00
e61686956b Merge pull request 'media-detail' (#31) from media-detail into main
All checks were successful
Sync to GitHub / sync (push) Successful in 9s
Reviewed-on: #31
2026-04-21 20:44:51 +07:00
baf7ba20b1 🗃️ db: enforce season field constraint 2026-04-07 12:00:00 +07:00
697f28de60 🗃️ db: add season field to media model 2026-04-03 12:00:00 +07:00
72f8e9e4eb 👔 feat: implement database repository for get media by slug
All checks were successful
Integration Tests / integration-tests (pull_request) Successful in 1m51s
2026-04-02 09:48:31 +07:00
59228f7d1e feat: add service for getBySlug 2026-04-02 09:34:03 +07:00
b27479cd3e 🐛 fix: resolve schema type error in getAllMedia module 2026-04-01 23:38:32 +07:00
17eb272b1d feat: add endpoint to fetch media by slug 2026-04-01 23:28:22 +07:00
19 changed files with 965 additions and 901 deletions

View File

@ -7,6 +7,9 @@ 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');
@ -72,6 +75,8 @@ 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")
); );
@ -367,7 +372,7 @@ CREATE TABLE "user_logs" (
-- CreateTable -- CreateTable
CREATE TABLE "collections" ( CREATE TABLE "collections" (
"id" UUID NOT NULL, "id" UUID NOT NULL,
"name" VARCHAR(255) NOT NULL, "name" VARCHAR(115) 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),
@ -375,10 +380,21 @@ 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,
@ -502,18 +518,13 @@ CREATE TABLE "email_system_histories" (
CREATE TABLE "hero_banner" ( CREATE TABLE "hero_banner" (
"id" UUID NOT NULL, "id" UUID NOT NULL,
"orderPriority" INTEGER, "orderPriority" INTEGER,
"isClickable" BOOLEAN NOT NULL DEFAULT false,
"title" VARCHAR(225),
"tags" TEXT[],
"description" TEXT,
"buttonContent" VARCHAR(100),
"buttonLink" TEXT,
"imageUrl" TEXT, "imageUrl" TEXT,
"startDate" TIMESTAMP(3) NOT NULL, "startDate" TIMESTAMP(3) NOT NULL,
"endDate" TIMESTAMP(3) NOT NULL, "endDate" TIMESTAMP(3) NOT NULL,
"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,
"creatorId" UUID NOT NULL, "creatorId" UUID NOT NULL,
"mediaId" UUID NOT NULL,
CONSTRAINT "hero_banner_pkey" PRIMARY KEY ("id") CONSTRAINT "hero_banner_pkey" PRIMARY KEY ("id")
); );
@ -591,14 +602,6 @@ 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,
@ -673,6 +676,12 @@ 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");
@ -703,24 +712,21 @@ 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;
@ -733,15 +739,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;
@ -749,13 +755,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_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 "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_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 "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;
@ -769,23 +775,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_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_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_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;
@ -794,29 +800,35 @@ 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_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 "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 "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 -- 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 "CollectionMedia" ADD CONSTRAINT "CollectionMedia_collectionId_fkey" FOREIGN KEY ("collectionId") REFERENCES "collections"("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 "CollectionMedia" ADD CONSTRAINT "CollectionMedia_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "watch_histories" ADD CONSTRAINT "watch_histories_id_fkey" FOREIGN KEY ("id") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE "watch_histories" ADD CONSTRAINT "watch_histories_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "user_sessions"("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 "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 "movie_reviews" ADD CONSTRAINT "movie_reviews_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "movie_reviews" ADD CONSTRAINT "movie_reviews_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("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;
@ -833,10 +845,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_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 "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 "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;
@ -850,6 +862,9 @@ ALTER TABLE "email_system_histories" ADD CONSTRAINT "email_system_histories_user
-- AddForeignKey -- AddForeignKey
ALTER TABLE "hero_banner" ADD CONSTRAINT "hero_banner_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; 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;
@ -880,12 +895,6 @@ 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;

View File

@ -1,23 +0,0 @@
/*
Warnings:
- You are about to drop the column `buttonContent` on the `hero_banner` table. All the data in the column will be lost.
- You are about to drop the column `buttonLink` on the `hero_banner` table. All the data in the column will be lost.
- You are about to drop the column `description` on the `hero_banner` table. All the data in the column will be lost.
- You are about to drop the column `isClickable` on the `hero_banner` table. All the data in the column will be lost.
- You are about to drop the column `tags` on the `hero_banner` table. All the data in the column will be lost.
- You are about to drop the column `title` on the `hero_banner` table. All the data in the column will be lost.
- Added the required column `mediaId` to the `hero_banner` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "hero_banner" DROP COLUMN "buttonContent",
DROP COLUMN "buttonLink",
DROP COLUMN "description",
DROP COLUMN "isClickable",
DROP COLUMN "tags",
DROP COLUMN "title",
ADD COLUMN "mediaId" UUID NOT NULL;
-- AddForeignKey
ALTER TABLE "hero_banner" ADD CONSTRAINT "hero_banner_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -1,14 +0,0 @@
/*
Warnings:
- You are about to alter the column `name` on the `collections` table. The data in that column could be lost. The data in that column will be cast from `VarChar(255)` to `VarChar(115)`.
- A unique constraint covering the columns `[slug,ownerId]` on the table `collections` will be added. If there are existing duplicate values, this will fail.
- Added the required column `slug` to the `collections` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "collections" ADD COLUMN "slug" VARCHAR(115) NOT NULL,
ALTER COLUMN "name" SET DATA TYPE VARCHAR(115);
-- CreateIndex
CREATE UNIQUE INDEX "collections_slug_ownerId_key" ON "collections"("slug", "ownerId");

View File

@ -1,33 +0,0 @@
/*
Warnings:
- You are about to drop the `_MediaCollections` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE "_MediaCollections" DROP CONSTRAINT "_MediaCollections_A_fkey";
-- DropForeignKey
ALTER TABLE "_MediaCollections" DROP CONSTRAINT "_MediaCollections_B_fkey";
-- DropTable
DROP TABLE "_MediaCollections";
-- 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")
);
-- CreateIndex
CREATE UNIQUE INDEX "CollectionMedia_collectionId_mediaId_key" ON "CollectionMedia"("collectionId", "mediaId");
-- 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;

View File

@ -0,0 +1,14 @@
/*
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

View File

@ -1,17 +1,14 @@
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 { getMediaIdFromSlugRepository } from "../../../media/repositories/GET/getMediaIdFromSlug.repository"; import { selectMediaIdFromSlugRepository } from "../../../media/repositories/SELECT/selectMediaIdFromSlug.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 ( export const getEpisodeDetailsService = async (params: GetEpisodeDetailsParams) => {
params: GetEpisodeDetailsParams,
) => {
try { try {
if (!params.mediaSlug || !params.episode) if (!params.mediaSlug || !params.episode) throw new AppError(400, "Media slug and episode are required.");
throw new AppError(400, "Media slug and episode are required.");
const mediaId = await getMediaIdFromSlugRepository(params.mediaSlug); const mediaId = await selectMediaIdFromSlugRepository(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({

View File

@ -1,27 +1,20 @@
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 ( export const bulkInsertEpisodeService = async (mal_id: number, page: number = 1) => {
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 getMediaByMalIdRepository(mal_id); const mediaData = await selectMediaByMalIdRepository(mal_id);
if (!mediaData) if (!mediaData) throw new AppError(404, `Media with Mal ID ${mal_id} not found in database`);
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) => {

View File

@ -1,19 +1,16 @@
import { Context } from "elysia"; import { Context, Static } 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 ( export const getAllMediaController = async (ctx: {
ctx: Context & { query: { page: string } }, set: Context["set"];
) => { query: Static<typeof getAllMediaSchema.query>;
}) => {
try { try {
const mediaData = await getAllMediaService(ctx.query.page); const mediaData = await getAllMediaService(ctx.query.page);
return returnReadResponse( return returnReadResponse(ctx.set, 200, "Media fetched successfully", mediaData);
ctx.set,
200,
"Media fetched successfully",
mediaData,
);
} catch (error) { } catch (error) {
return mainErrorHandler(ctx.set, error); return mainErrorHandler(ctx.set, error);
} }

View File

@ -0,0 +1,17 @@
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);
}
};

View File

@ -1,7 +1,9 @@
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" }).get( export const mediaModule = new Elysia({ prefix: "/media", tags: ["Media"] })
"/", .get("/", getAllMediaController, getAllMediaSchema)
getAllMediaController, .get("/:slug", getMediaBySlugController, getMediaBySlugSchema);
);

View File

@ -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 getAllMediaRepository = async (page: number) => { export const selectAllMediaRepository = async (page: number) => {
try { try {
const limit = 10; const limit = 10;
return await mediaModel.findMany({ return await mediaModel.findMany({

View File

@ -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 getMediaByMalIdRepository = async (mal_id: number) => { export const selectMediaByMalIdRepository = async (mal_id: number) => {
try { try {
return await mediaModel.findUnique({ return await mediaModel.findUnique({
where: { malId: mal_id }, where: { malId: mal_id },

View File

@ -0,0 +1,12 @@
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);
}
};

View File

@ -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 getMediaIdFromSlugRepository = async (slug: string) => { export const selectMediaIdFromSlugRepository = async (slug: string) => {
try { try {
return await mediaModel.findUnique({ return await mediaModel.findUnique({
where: { slug }, where: { slug },

View File

@ -0,0 +1,58 @@
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;

View File

@ -0,0 +1,29 @@
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;

View File

@ -1,14 +1,11 @@
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder"; import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
import { getAllMediaRepository } from "../../repositories/GET/getAllMedia.repository"; import { selectAllMediaRepository } from "../../repositories/SELECT/selectAllMedia.repository";
export const getAllMediaService = async (pagination: string) => { export const getAllMediaService = async (pagination: string) => {
try { try {
const page = const page = /^\d+$/.test(pagination) && Number(pagination) > 0 ? Number(pagination) : 1;
/^\d+$/.test(pagination) && Number(pagination) > 0
? Number(pagination)
: 1;
return getAllMediaRepository(page); return selectAllMediaRepository(page);
} catch (error) { } catch (error) {
ErrorForwarder(error); ErrorForwarder(error);
} }

View File

@ -0,0 +1,14 @@
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);
}
};