Compare commits
20 Commits
864a919680
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| cef6da16cb | |||
| 412b501c80 | |||
| 68d834ae6b | |||
| 86fe39f5b5 | |||
| 73b22d7f2c | |||
| f1e79945b0 | |||
| 3768ae4c26 | |||
| 56c921e800 | |||
| e798338107 | |||
| dade012888 | |||
| 4001aec6ef | |||
| dd70f9f9d4 | |||
| 26909154ab | |||
| 7f6b1373f4 | |||
| 794a130562 | |||
| 6599fa8f79 | |||
| 27b66e6d34 | |||
| 1c097aac69 | |||
| b5a0c2eda6 | |||
| d767a0434c |
@ -28,10 +28,11 @@ 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 {
|
||||||
@ -368,7 +369,7 @@ Table user_logs {
|
|||||||
Table collections {
|
Table collections {
|
||||||
id String [pk]
|
id String [pk]
|
||||||
name String [not null]
|
name String [not null]
|
||||||
medias medias [not null]
|
slug String [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']
|
||||||
@ -378,6 +379,24 @@ 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 {
|
||||||
@ -496,12 +515,8 @@ Table email_system_histories {
|
|||||||
Table hero_banner {
|
Table hero_banner {
|
||||||
id String [pk]
|
id String [pk]
|
||||||
orderPriority Int [unique]
|
orderPriority Int [unique]
|
||||||
isClickable Boolean [not null, default: false]
|
mediaId String [not null]
|
||||||
title String
|
media medias [not null]
|
||||||
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]
|
||||||
@ -560,9 +575,9 @@ Table MediaCharacters {
|
|||||||
mediasId String [ref: > medias.id]
|
mediasId String [ref: > medias.id]
|
||||||
}
|
}
|
||||||
|
|
||||||
Table MediaCollections {
|
Table CollectionMedia {
|
||||||
collectionsId String [ref: > collections.id]
|
incollectionsId String [ref: > CollectionMedia.id]
|
||||||
mediasId String [ref: > medias.id]
|
media_savedId String [ref: > CollectionMedia.id]
|
||||||
}
|
}
|
||||||
|
|
||||||
Table UserFavoriteGenres {
|
Table UserFavoriteGenres {
|
||||||
@ -750,6 +765,10 @@ 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
|
||||||
@ -780,6 +799,8 @@ 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
|
||||||
|
|||||||
@ -206,7 +206,8 @@ 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,
|
||||||
"code" VARCHAR(255) NOT NULL,
|
"videoCode" 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),
|
||||||
@ -497,6 +498,26 @@ 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,
|
||||||
|
"isClickable" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"title" VARCHAR(225),
|
||||||
|
"tags" TEXT[],
|
||||||
|
"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")
|
||||||
|
);
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "system_preferences" (
|
CREATE TABLE "system_preferences" (
|
||||||
"id" UUID NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
@ -629,7 +650,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_code_key" ON "videos"("serviceId", "code");
|
CREATE UNIQUE INDEX "videos_serviceId_videoCode_key" ON "videos"("serviceId", "videoCode");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "video_services_name_key" ON "video_services"("name");
|
CREATE UNIQUE INDEX "video_services_name_key" ON "video_services"("name");
|
||||||
@ -664,6 +685,12 @@ 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");
|
||||||
|
|
||||||
@ -820,6 +847,9 @@ 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
|
-- 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;
|
||||||
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
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");
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
-- AlterTable
|
|
||||||
ALTER TABLE "videos" ADD COLUMN "thumbnailCode" TEXT;
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
-- 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;
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
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;
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
/*
|
|
||||||
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");
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
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");
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
-- AlterTable
|
|
||||||
ALTER TABLE "hero_banner" ADD COLUMN "tags" TEXT[];
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
/*
|
|
||||||
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");
|
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
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;
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
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");
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
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;
|
||||||
@ -49,10 +49,11 @@ model Media {
|
|||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
|
||||||
logs MediaLog[] @relation("MediaLogs")
|
bannerPromotion HeroBanner[] @relation("MediaBannerPromotion")
|
||||||
episodes Episode[] @relation("MediaEpisodes")
|
logs MediaLog[] @relation("MediaLogs")
|
||||||
collections Collection[] @relation("MediaCollections")
|
episodes Episode[] @relation("MediaEpisodes")
|
||||||
reviews MediaReview[] @relation("MediaReviews")
|
reviews MediaReview[] @relation("MediaReviews")
|
||||||
|
inCollections CollectionMedia[] @relation("CollectionMedia")
|
||||||
|
|
||||||
@@index([status, onDraft, deletedAt])
|
@@index([status, onDraft, deletedAt])
|
||||||
@@index([mediaType])
|
@@index([mediaType])
|
||||||
@ -417,8 +418,8 @@ model UserLog {
|
|||||||
|
|
||||||
model Collection {
|
model Collection {
|
||||||
id String @id @db.Uuid
|
id String @id @db.Uuid
|
||||||
name String @db.VarChar(255)
|
name String @db.VarChar(115)
|
||||||
medias Media[] @relation("MediaCollections")
|
slug String @db.VarChar(115)
|
||||||
owner User @relation("UserCollections", fields: [ownerId], references: [id])
|
owner User @relation("UserCollections", fields: [ownerId], references: [id])
|
||||||
ownerId String @db.Uuid
|
ownerId String @db.Uuid
|
||||||
accessStatus AccessStatus @default(private)
|
accessStatus AccessStatus @default(private)
|
||||||
@ -428,9 +429,22 @@ model Collection {
|
|||||||
deletedAt DateTime?
|
deletedAt DateTime?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
|
||||||
|
media_saved CollectionMedia[] @relation("CollectionMedia")
|
||||||
|
@@unique([slug, ownerId])
|
||||||
@@map("collections")
|
@@map("collections")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model CollectionMedia {
|
||||||
|
id String @id @db.Uuid
|
||||||
|
collection Collection @relation("CollectionMedia", fields: [collectionId], references: [id])
|
||||||
|
collectionId String @db.Uuid
|
||||||
|
media Media @relation("CollectionMedia", fields: [mediaId], references: [id])
|
||||||
|
mediaId String @db.Uuid
|
||||||
|
savedAt DateTime @default(now())
|
||||||
|
@@unique([collectionId, mediaId])
|
||||||
|
}
|
||||||
|
|
||||||
model WatchHistory {
|
model WatchHistory {
|
||||||
id String @id @db.Uuid
|
id String @id @db.Uuid
|
||||||
episode Episode @relation("EpisodeWatchHistories", fields: [id], references: [id])
|
episode Episode @relation("EpisodeWatchHistories", fields: [id], references: [id])
|
||||||
@ -557,12 +571,8 @@ model EmailSystemHistory {
|
|||||||
model HeroBanner {
|
model HeroBanner {
|
||||||
id String @id @db.Uuid
|
id String @id @db.Uuid
|
||||||
orderPriority Int? @unique
|
orderPriority Int? @unique
|
||||||
isClickable Boolean @default(false)
|
mediaId String @db.Uuid
|
||||||
title String? @db.VarChar(225)
|
media Media @relation("MediaBannerPromotion", fields: [mediaId], references: [id])
|
||||||
tags String[]
|
|
||||||
description String? @db.Text
|
|
||||||
buttonContent String? @db.VarChar(100)
|
|
||||||
buttonLink String? @db.Text
|
|
||||||
imageUrl String? @db.Text
|
imageUrl String? @db.Text
|
||||||
startDate DateTime
|
startDate DateTime
|
||||||
endDate DateTime
|
endDate DateTime
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { Context } from "elysia";
|
|
||||||
import { UserHeaderInformation } from "./types";
|
import { UserHeaderInformation } from "./types";
|
||||||
|
|
||||||
export interface ClientInfoHeader {
|
export interface ClientInfoHeader {
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { success } from "zod";
|
|
||||||
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
||||||
|
|
||||||
export const getOauthProvidersSchema = {
|
export const getOauthProvidersSchema = {
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
9
src/modules/collection/index.ts
Normal file
9
src/modules/collection/index.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
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);
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
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;
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
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;
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
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);
|
||||||
|
};
|
||||||
4
src/modules/flushCache/index.ts
Normal file
4
src/modules/flushCache/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import Elysia from "elysia";
|
||||||
|
import { clearHeroBannerController } from "./controllers/clearHeroBanner.controller";
|
||||||
|
|
||||||
|
export const flushCacheModule = new Elysia({ prefix: "/flush-cache" }).put("/hero-banner", clearHeroBannerController);
|
||||||
12
src/modules/flushCache/services/clearHeroBanner.service.ts
Normal file
12
src/modules/flushCache/services/clearHeroBanner.service.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -20,6 +20,25 @@ export const findAllActiveHeroBannerRepository = async () => {
|
|||||||
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} 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);
|
||||||
|
|||||||
@ -8,26 +8,31 @@ import { findAllActiveHeroBannerRepository } from "../repositories/GET/findAllAc
|
|||||||
export const getActiveHeroBannerService = async () => {
|
export const getActiveHeroBannerService = async () => {
|
||||||
try {
|
try {
|
||||||
// Check if Hero Banner is enabled in system preferences
|
// Check if Hero Banner is enabled in system preferences
|
||||||
const isHeroBannerEnabled = await findSystemPreferenceService(
|
const isHeroBannerEnabled = await findSystemPreferenceService("HERO_BANNER_ENABLED", "boolean");
|
||||||
"HERO_BANNER_ENABLED",
|
if (!isHeroBannerEnabled) throw new AppError(403, "Hero Banner is disabled");
|
||||||
"boolean",
|
|
||||||
);
|
|
||||||
if (!isHeroBannerEnabled)
|
|
||||||
throw new AppError(403, "Hero Banner is disabled");
|
|
||||||
|
|
||||||
// Try to get active banners from Redis cache
|
// Try to get active banners from Redis cache
|
||||||
const cachedBanners = await redis.get(
|
const cachedBanners = await redis.get(`${redisKey.filter((key) => key.name === "HERO_BANNER")[0].key}`);
|
||||||
`${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();
|
const activeBanners = await findAllActiveHeroBannerRepository();
|
||||||
|
const constructedBanners = activeBanners.map((banner) => ({
|
||||||
|
id: banner.media.id,
|
||||||
|
title: banner.media.title,
|
||||||
|
slug: banner.media.slug,
|
||||||
|
imageUrl: banner.imageUrl || banner.media.pictureLarge,
|
||||||
|
synopsis: banner.media.synopsis,
|
||||||
|
genres: banner.media.genres.map((genre) => ({
|
||||||
|
slug: genre.slug,
|
||||||
|
name: genre.name,
|
||||||
|
})),
|
||||||
|
}));
|
||||||
await redis.set(
|
await redis.set(
|
||||||
`${redisKey.filter((key) => key.name === "HERO_BANNER")[0].key}`,
|
`${redisKey.filter((key) => key.name === "HERO_BANNER")[0].key}`,
|
||||||
JSON.stringify(activeBanners),
|
JSON.stringify(constructedBanners),
|
||||||
);
|
);
|
||||||
return activeBanners;
|
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 (
|
export const insertHeroBannerRepository = async (payload: Static<typeof createHeroBannerSchema.body>) => {
|
||||||
payload: Omit<Prisma.HeroBannerCreateInput, "id" | "createdBy">,
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
return await prisma.heroBanner.create({
|
return await prisma.heroBanner.create({
|
||||||
data: {
|
data: {
|
||||||
@ -16,6 +16,9 @@ export const insertHeroBannerRepository = async (
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} 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,45 +3,18 @@ import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
|||||||
|
|
||||||
export const createHeroBannerSchema = {
|
export const createHeroBannerSchema = {
|
||||||
body: t.Object({
|
body: t.Object({
|
||||||
isClickable: t.Optional(
|
orderPriority: t.Optional(
|
||||||
t.Boolean({
|
t.Number({ description: "The priority order of the hero banner. Lower numbers indicate higher priority." }),
|
||||||
description: "Indicates whether the hero banner is clickable",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
title: t.Optional(
|
|
||||||
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",
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
|
mediaId: t.String({ description: "The ID of the media associated with the hero banner" }),
|
||||||
imageUrl: t.Optional(
|
imageUrl: t.Optional(
|
||||||
t.String({
|
t.String({
|
||||||
description: "The URL of the image used in the hero banner",
|
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.String({
|
startDate: t.Date({ description: "The start date for the hero banner in ISO 8601 format" }),
|
||||||
description: "The start date for the hero banner in ISO 8601 format",
|
endDate: t.Date({ description: "The end 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",
|
||||||
@ -64,17 +37,16 @@ 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" },
|
||||||
isClickable: { type: "boolean", description: "Indicates whether the hero banner is clickable" },
|
orderPriority: {
|
||||||
title: { type: "string", description: "The title of the hero banner" },
|
type: "number",
|
||||||
tags: {
|
description: "The priority order of the hero banner. Lower numbers indicate higher priority.",
|
||||||
type: "array",
|
},
|
||||||
items: { type: "string" },
|
mediaId: { type: "string", description: "The ID of the media associated with the hero banner" },
|
||||||
description: "An array of tags associated with the hero banner",
|
imageUrl: {
|
||||||
|
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,10 +1,9 @@
|
|||||||
|
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 (
|
export const createHeroBannerService = async (payload: Static<typeof createHeroBannerSchema.body>) => {
|
||||||
payload: CreateHeroBannerRequestBody,
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
return await insertHeroBannerRepository(payload);
|
return await insertHeroBannerRepository(payload);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user