Compare commits
9 Commits
main
...
502e7b10c6
| Author | SHA1 | Date | |
|---|---|---|---|
| 502e7b10c6 | |||
| 73f1f87695 | |||
| 28b3de29d8 | |||
| a04d1ffdf1 | |||
| dcfa4350d6 | |||
| 9de535f541 | |||
| 00ca1ba8fb | |||
| 0057f0c63b | |||
| 1694035dc4 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -62,4 +62,7 @@ server.exe
|
||||
# uploaded files
|
||||
/uploads
|
||||
|
||||
/scripts/git-multipush.ts
|
||||
/scripts/git-multipush.ts
|
||||
|
||||
# IDE configuration
|
||||
/.idea
|
||||
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
12
.idea/backend.iml
generated
12
.idea/backend.iml
generated
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/backend.iml" filepath="$PROJECT_DIR$/.idea/backend.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@ -252,8 +252,6 @@ Table medias {
|
||||
age_rating_id String
|
||||
country_id String
|
||||
related_media media_relations [not null]
|
||||
approver_id String
|
||||
created_by_id String
|
||||
updated_by_id String
|
||||
deleted_by_id String
|
||||
home_media_banners home_media_banners [not null]
|
||||
@ -296,7 +294,7 @@ Table media_collections {
|
||||
Table media_trailers {
|
||||
media_id String [pk]
|
||||
url String
|
||||
embed_url String
|
||||
embed_url String [unique]
|
||||
small_image_url String
|
||||
large_image_url String
|
||||
maximum_image_url String
|
||||
@ -661,7 +659,7 @@ Table countries {
|
||||
id String [pk]
|
||||
name String [not null]
|
||||
slug String [not null]
|
||||
code String [not null]
|
||||
code String [unique, not null]
|
||||
flag String
|
||||
banner String
|
||||
UserCountry users [not null]
|
||||
|
||||
@ -1,911 +0,0 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "user_role" AS ENUM ('user', 'contributor', 'curator', 'admin');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "user_sex" AS ENUM ('male', 'female');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "auth_provider" AS ENUM ('google', 'github');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "device_type" AS ENUM ('mobile', 'tablet', 'desktop', 'unknown');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "user_preference_state" AS ENUM ('exclude', 'include');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "media_season" AS ENUM ('winter', 'spring', 'summer', 'fall');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "character_role" AS ENUM ('main', 'supporting', 'background');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "status_submission" AS ENUM ('pending', 'approved', 'rejected');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "like_type" AS ENUM ('like', 'dislike');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "audit_action" AS ENUM ('delete', 'restore', 'edit', 'flag');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "privacy_level" AS ENUM ('public', 'unlisted', 'private');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "collection_access_level" AS ENUM ('owner', 'moderator', 'contributor', 'viewer');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "users" (
|
||||
"id" UUID NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"password" VARCHAR(255),
|
||||
"username" VARCHAR(28) NOT NULL,
|
||||
"fullname" VARCHAR(32) NOT NULL,
|
||||
"avatar" VARCHAR(255),
|
||||
"bio" TEXT,
|
||||
"datebirth" DATE,
|
||||
"role" "user_role" NOT NULL DEFAULT 'user',
|
||||
"sex" "user_sex",
|
||||
"phone_number" VARCHAR(20),
|
||||
"auth_provider" VARCHAR(64),
|
||||
"provider_token" VARCHAR(255),
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
"deleted_at" TIMESTAMPTZ,
|
||||
"countryId" UUID,
|
||||
|
||||
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_addresses" (
|
||||
"user_id" UUID NOT NULL,
|
||||
"address" VARCHAR(255) NOT NULL,
|
||||
"district" VARCHAR(100) NOT NULL,
|
||||
"city" VARCHAR(100) NOT NULL,
|
||||
"province" VARCHAR(100) NOT NULL,
|
||||
"postal_code" VARCHAR(20) NOT NULL,
|
||||
"coordinate" VARCHAR(50),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
|
||||
CONSTRAINT "user_addresses_pkey" PRIMARY KEY ("user_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_oauth_accounts" (
|
||||
"id" UUID NOT NULL,
|
||||
"provider_name" "auth_provider" NOT NULL,
|
||||
"provider_sub" VARCHAR(255),
|
||||
"provider_email" VARCHAR(255),
|
||||
"provider_token" VARCHAR(255),
|
||||
"refresh_token" VARCHAR(255),
|
||||
"expires_at" TIMESTAMPTZ,
|
||||
"last_login" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
"user_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "user_oauth_accounts_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_sessions" (
|
||||
"id" UUID NOT NULL,
|
||||
"device_type" "device_type" NOT NULL,
|
||||
"os_type" VARCHAR(50),
|
||||
"os_version" VARCHAR(50),
|
||||
"browser_name" VARCHAR(50),
|
||||
"browser_version" VARCHAR(50),
|
||||
"ip_login" INET,
|
||||
"login_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"logout_at" TIMESTAMPTZ,
|
||||
"user_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "user_sessions_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_preferences" (
|
||||
"comment_picture" VARCHAR(255),
|
||||
"enable_watch_history" BOOLEAN NOT NULL DEFAULT true,
|
||||
"enable_search_history" BOOLEAN NOT NULL DEFAULT false,
|
||||
"is_private_account" BOOLEAN NOT NULL DEFAULT false,
|
||||
"can_message_me" BOOLEAN NOT NULL DEFAULT true,
|
||||
"publish_birthday" BOOLEAN NOT NULL DEFAULT false,
|
||||
"publish_email" BOOLEAN NOT NULL DEFAULT false,
|
||||
"publish_phone_number" BOOLEAN NOT NULL DEFAULT false,
|
||||
"publish_country" BOOLEAN NOT NULL DEFAULT false,
|
||||
"publish_partner" BOOLEAN NOT NULL DEFAULT true,
|
||||
"subscribe_to_newsletter" BOOLEAN NOT NULL DEFAULT true,
|
||||
"enable_security_alerts" BOOLEAN NOT NULL DEFAULT true,
|
||||
"user_id" UUID NOT NULL,
|
||||
"char_as_partner_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "user_preferences_pkey" PRIMARY KEY ("user_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_genre_preferences" (
|
||||
"state" "user_preference_state" NOT NULL,
|
||||
"user_id" UUID NOT NULL,
|
||||
"genre_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "user_genre_preferences_pkey" PRIMARY KEY ("user_id","genre_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_rating_preferences" (
|
||||
"state" "user_preference_state" NOT NULL,
|
||||
"user_id" UUID NOT NULL,
|
||||
"rating_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "user_rating_preferences_pkey" PRIMARY KEY ("user_id","rating_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_country_preferences" (
|
||||
"state" "user_preference_state" NOT NULL,
|
||||
"user_id" UUID NOT NULL,
|
||||
"country_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "user_country_preferences_pkey" PRIMARY KEY ("user_id","country_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_follows" (
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"follower_id" UUID NOT NULL,
|
||||
"following_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "user_follows_pkey" PRIMARY KEY ("follower_id","following_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_watch_histories" (
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
"user_id" UUID NOT NULL,
|
||||
"episode_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "user_watch_histories_pkey" PRIMARY KEY ("user_id","episode_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "collections" (
|
||||
"id" UUID NOT NULL,
|
||||
"name" VARCHAR(64) NOT NULL,
|
||||
"code" VARCHAR(12),
|
||||
"cover_url" VARCHAR(255),
|
||||
"privacy" "privacy_level" NOT NULL DEFAULT 'private',
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
|
||||
CONSTRAINT "collections_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "collection_members" (
|
||||
"access_level" "collection_access_level" NOT NULL,
|
||||
"invited_at" TIMESTAMPTZ,
|
||||
"collection_id" UUID NOT NULL,
|
||||
"user_id" UUID NOT NULL,
|
||||
"invited_by_id" UUID,
|
||||
|
||||
CONSTRAINT "collection_members_pkey" PRIMARY KEY ("collection_id","user_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "medias" (
|
||||
"id" UUID NOT NULL,
|
||||
"mal_id" INTEGER NOT NULL,
|
||||
"title" VARCHAR(255) NOT NULL,
|
||||
"title_secondary" VARCHAR(255),
|
||||
"title_original" VARCHAR(255),
|
||||
"title_synonyms" VARCHAR(255)[],
|
||||
"synopsis" TEXT,
|
||||
"small_image_url" VARCHAR(255),
|
||||
"medium_image_url" VARCHAR(255) NOT NULL,
|
||||
"large_image_url" VARCHAR(255),
|
||||
"airing" BOOLEAN NOT NULL,
|
||||
"start_airing" DATE,
|
||||
"end_airing" DATE,
|
||||
"score" DECIMAL(2,2),
|
||||
"score_total" INTEGER NOT NULL DEFAULT 0,
|
||||
"score_count" INTEGER NOT NULL DEFAULT 0,
|
||||
"background" TEXT,
|
||||
"season" "media_season" NOT NULL,
|
||||
"year" SMALLINT,
|
||||
"broadcast_day" VARCHAR(20),
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
"deleted_at" TIMESTAMPTZ,
|
||||
"type_id" UUID NOT NULL,
|
||||
"source_id" UUID NOT NULL,
|
||||
"status_id" UUID NOT NULL,
|
||||
"age_rating_id" UUID,
|
||||
"country_id" UUID,
|
||||
"approver_id" UUID,
|
||||
"created_by_id" UUID,
|
||||
"updated_by_id" UUID,
|
||||
"deleted_by_id" UUID,
|
||||
|
||||
CONSTRAINT "medias_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_submissions" (
|
||||
"id" UUID NOT NULL,
|
||||
"status" "status_submission" NOT NULL DEFAULT 'pending',
|
||||
"reviewed_at" TIMESTAMPTZ,
|
||||
"reason" TEXT,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"media_id" UUID NOT NULL,
|
||||
"submitter_id" UUID NOT NULL,
|
||||
"reviewer_id" UUID,
|
||||
|
||||
CONSTRAINT "media_submissions_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_collections" (
|
||||
"added_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"media_id" UUID NOT NULL,
|
||||
"collection_id" UUID NOT NULL,
|
||||
"added_by_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "media_collections_pkey" PRIMARY KEY ("media_id","collection_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_trailers" (
|
||||
"media_id" UUID NOT NULL,
|
||||
"url" VARCHAR(255),
|
||||
"embed_url" VARCHAR(255),
|
||||
"small_image_url" VARCHAR(255),
|
||||
"large_image_url" VARCHAR(255),
|
||||
"maximum_image_url" VARCHAR(255),
|
||||
|
||||
CONSTRAINT "media_trailers_pkey" PRIMARY KEY ("media_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_types" (
|
||||
"id" UUID NOT NULL,
|
||||
"name" VARCHAR(100) NOT NULL,
|
||||
|
||||
CONSTRAINT "media_types_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_sources" (
|
||||
"id" UUID NOT NULL,
|
||||
"name" VARCHAR(100) NOT NULL,
|
||||
|
||||
CONSTRAINT "media_sources_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_statuses" (
|
||||
"id" UUID NOT NULL,
|
||||
"name" VARCHAR(100) NOT NULL,
|
||||
|
||||
CONSTRAINT "media_statuses_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_age_ratings" (
|
||||
"id" UUID NOT NULL,
|
||||
"name" VARCHAR(100) NOT NULL,
|
||||
"min_age" SMALLINT NOT NULL,
|
||||
|
||||
CONSTRAINT "media_age_ratings_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_producers" (
|
||||
"media_id" UUID NOT NULL,
|
||||
"producer_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "media_producers_pkey" PRIMARY KEY ("media_id","producer_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_licensors" (
|
||||
"media_id" UUID NOT NULL,
|
||||
"licensor_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "media_licensors_pkey" PRIMARY KEY ("media_id","licensor_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_studios" (
|
||||
"media_id" UUID NOT NULL,
|
||||
"studio_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "media_studios_pkey" PRIMARY KEY ("media_id","studio_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "producers" (
|
||||
"id" UUID NOT NULL,
|
||||
"mal_id" INTEGER NOT NULL,
|
||||
"type" VARCHAR(24) NOT NULL,
|
||||
"name" VARCHAR(255) NOT NULL,
|
||||
"url" VARCHAR(255),
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
"deleted_at" TIMESTAMPTZ,
|
||||
"created_by_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "producers_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_genres" (
|
||||
"media_id" UUID NOT NULL,
|
||||
"genre_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "media_genres_pkey" PRIMARY KEY ("media_id","genre_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_explicit_genres" (
|
||||
"media_id" UUID NOT NULL,
|
||||
"genre_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "media_explicit_genres_pkey" PRIMARY KEY ("media_id","genre_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_themes" (
|
||||
"media_id" UUID NOT NULL,
|
||||
"genre_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "media_themes_pkey" PRIMARY KEY ("media_id","genre_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_demographics" (
|
||||
"media_id" UUID NOT NULL,
|
||||
"demographic_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "media_demographics_pkey" PRIMARY KEY ("media_id","demographic_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "genres" (
|
||||
"id" UUID NOT NULL,
|
||||
"mal_id" SMALLINT NOT NULL,
|
||||
"name" VARCHAR(100) NOT NULL,
|
||||
"slug" VARCHAR(115) NOT NULL,
|
||||
"thumbnail_url" VARCHAR(255),
|
||||
|
||||
CONSTRAINT "genres_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_relations" (
|
||||
"relation_type" VARCHAR(50) NOT NULL,
|
||||
"media_id" UUID NOT NULL,
|
||||
"related_media_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "media_relations_pkey" PRIMARY KEY ("media_id","related_media_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_external_links" (
|
||||
"id" UUID NOT NULL,
|
||||
"url" VARCHAR(255) NOT NULL,
|
||||
"site_name" VARCHAR(100),
|
||||
"media_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "media_external_links_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "media_characters" (
|
||||
"id" UUID NOT NULL,
|
||||
"role" "character_role" NOT NULL,
|
||||
"media_id" UUID NOT NULL,
|
||||
"character_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "media_characters_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "characters" (
|
||||
"id" UUID NOT NULL,
|
||||
"name" VARCHAR(255) NOT NULL,
|
||||
"image" VARCHAR(255),
|
||||
"small_image" VARCHAR(255),
|
||||
"mal_id" INTEGER,
|
||||
"fanpage_url" VARCHAR(255),
|
||||
"liked" INTEGER NOT NULL DEFAULT 0,
|
||||
"deleted_at" TIMESTAMPTZ,
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "characters_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "voice_actors" (
|
||||
"id" UUID NOT NULL,
|
||||
"media_character_id" UUID NOT NULL,
|
||||
"language" VARCHAR(115) NOT NULL,
|
||||
"staff_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "voice_actors_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "staff" (
|
||||
"id" UUID NOT NULL,
|
||||
"name" VARCHAR(255) NOT NULL,
|
||||
"image" VARCHAR(255),
|
||||
"mal_id" INTEGER,
|
||||
"deleted_at" TIMESTAMPTZ,
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "staff_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "episodes" (
|
||||
"id" UUID NOT NULL,
|
||||
"media_id" UUID NOT NULL,
|
||||
"episode" SMALLINT NOT NULL,
|
||||
"mal_url" VARCHAR(255),
|
||||
"forum_url" VARCHAR(255),
|
||||
"title" VARCHAR(155) NOT NULL,
|
||||
"title_origin" VARCHAR(155),
|
||||
"title_romanji" VARCHAR(155),
|
||||
"aired_at" DATE,
|
||||
"filler" BOOLEAN NOT NULL,
|
||||
"recap" BOOLEAN NOT NULL,
|
||||
"total_score" INTEGER NOT NULL DEFAULT 0,
|
||||
"score_count" INTEGER NOT NULL DEFAULT 0,
|
||||
"deleted_at" TIMESTAMPTZ,
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"created_by_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "episodes_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "videos" (
|
||||
"id" UUID NOT NULL,
|
||||
"video_code" VARCHAR(255) NOT NULL,
|
||||
"short_code" VARCHAR(255),
|
||||
"thumbnail_code" VARCHAR(255),
|
||||
"download_code" VARCHAR(255),
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted_at" TIMESTAMPTZ,
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
"episode_id" UUID NOT NULL,
|
||||
"created_by_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "videos_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "video_submissions" (
|
||||
"video_id" UUID NOT NULL,
|
||||
"status" "status_submission" NOT NULL DEFAULT 'pending',
|
||||
"reviewed_at" TIMESTAMPTZ,
|
||||
"reason" TEXT,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"created_by_id" UUID NOT NULL,
|
||||
"reviewer_id" UUID,
|
||||
|
||||
CONSTRAINT "video_submissions_pkey" PRIMARY KEY ("video_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "video_services" (
|
||||
"id" UUID NOT NULL,
|
||||
"name" VARCHAR(155) NOT NULL,
|
||||
"resolution" SMALLINT NOT NULL,
|
||||
"domain" VARCHAR(255) NOT NULL,
|
||||
"image_url" VARCHAR(255),
|
||||
"hex_color" VARCHAR(10),
|
||||
"endpoint_video" VARCHAR(255) NOT NULL,
|
||||
"endpoint_short" VARCHAR(255),
|
||||
"endpoint_image" VARCHAR(255),
|
||||
"endpoint_download" VARCHAR(255),
|
||||
"deleted_at" TIMESTAMPTZ,
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "video_services_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "video_service_submissions" (
|
||||
"video_service_id" UUID NOT NULL,
|
||||
"status" "status_submission" NOT NULL DEFAULT 'pending',
|
||||
"reviewed_at" TIMESTAMPTZ,
|
||||
"reason" TEXT,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"created_by_id" UUID NOT NULL,
|
||||
"reviewer_id" UUID,
|
||||
|
||||
CONSTRAINT "video_service_submissions_pkey" PRIMARY KEY ("video_service_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "comments" (
|
||||
"id" UUID NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||
"deleted_at" TIMESTAMPTZ,
|
||||
"user_id" UUID NOT NULL,
|
||||
"episode_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "comments_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "comment_likes" (
|
||||
"user_id" UUID NOT NULL,
|
||||
"comment_id" UUID NOT NULL,
|
||||
"type" "like_type" NOT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "comment_likes_pkey" PRIMARY KEY ("user_id","comment_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "comment_audit_logs" (
|
||||
"id" UUID NOT NULL,
|
||||
"action" "audit_action" NOT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"comment_id" UUID NOT NULL,
|
||||
"performed_by_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "comment_audit_logs_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "comment_reports" (
|
||||
"id" UUID NOT NULL,
|
||||
"title" VARCHAR(115) NOT NULL,
|
||||
"status" "status_submission" NOT NULL,
|
||||
"description" TEXT,
|
||||
"reported_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"closed_at" TIMESTAMPTZ,
|
||||
"reporter_id" UUID NOT NULL,
|
||||
"comment_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "comment_reports_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "provisioned_users" (
|
||||
"provisioned_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"reason" VARCHAR(255),
|
||||
"admin_id" UUID NOT NULL,
|
||||
"user_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "provisioned_users_pkey" PRIMARY KEY ("admin_id","user_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "countries" (
|
||||
"id" UUID NOT NULL,
|
||||
"name" VARCHAR(155) NOT NULL,
|
||||
"slug" VARCHAR(165) NOT NULL,
|
||||
"code" VARCHAR(3) NOT NULL,
|
||||
"flag" VARCHAR(255),
|
||||
"banner" VARCHAR(255),
|
||||
|
||||
CONSTRAINT "countries_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "home_media_banners" (
|
||||
"id" UUID NOT NULL,
|
||||
"priority" SMALLINT NOT NULL,
|
||||
"start_show" DATE NOT NULL,
|
||||
"end_show" DATE NOT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"media_id" UUID NOT NULL,
|
||||
"created_by_id" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "home_media_banners_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_VideoToVideoService" (
|
||||
"A" UUID NOT NULL,
|
||||
"B" UUID NOT NULL,
|
||||
|
||||
CONSTRAINT "_VideoToVideoService_AB_pkey" PRIMARY KEY ("A","B")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "users_username_key" ON "users"("username");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "users_email_idx" ON "users"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "users_username_idx" ON "users"("username");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "medias_mal_id_key" ON "medias"("mal_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "media_submissions_media_id_key" ON "media_submissions"("media_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "media_types_name_key" ON "media_types"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "media_sources_name_key" ON "media_sources"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "media_statuses_name_key" ON "media_statuses"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "media_age_ratings_name_key" ON "media_age_ratings"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "producers_mal_id_key" ON "producers"("mal_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "genres_mal_id_key" ON "genres"("mal_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "characters_mal_id_key" ON "characters"("mal_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "staff_mal_id_key" ON "staff"("mal_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "episodes_media_id_episode_idx" ON "episodes"("media_id", "episode");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "video_services_name_resolution_key" ON "video_services"("name", "resolution");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "home_media_banners_priority_key" ON "home_media_banners"("priority");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_VideoToVideoService_B_index" ON "_VideoToVideoService"("B");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "users" ADD CONSTRAINT "users_countryId_fkey" FOREIGN KEY ("countryId") REFERENCES "countries"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_addresses" ADD CONSTRAINT "user_addresses_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_oauth_accounts" ADD CONSTRAINT "user_oauth_accounts_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_sessions" ADD CONSTRAINT "user_sessions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_char_as_partner_id_fkey" FOREIGN KEY ("char_as_partner_id") REFERENCES "characters"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_genre_preferences" ADD CONSTRAINT "user_genre_preferences_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user_preferences"("user_id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_genre_preferences" ADD CONSTRAINT "user_genre_preferences_genre_id_fkey" FOREIGN KEY ("genre_id") REFERENCES "genres"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_rating_preferences" ADD CONSTRAINT "user_rating_preferences_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user_preferences"("user_id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_rating_preferences" ADD CONSTRAINT "user_rating_preferences_rating_id_fkey" FOREIGN KEY ("rating_id") REFERENCES "media_age_ratings"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_country_preferences" ADD CONSTRAINT "user_country_preferences_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user_preferences"("user_id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_country_preferences" ADD CONSTRAINT "user_country_preferences_country_id_fkey" FOREIGN KEY ("country_id") REFERENCES "countries"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_follows" ADD CONSTRAINT "user_follows_follower_id_fkey" FOREIGN KEY ("follower_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_follows" ADD CONSTRAINT "user_follows_following_id_fkey" FOREIGN KEY ("following_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_watch_histories" ADD CONSTRAINT "user_watch_histories_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_watch_histories" ADD CONSTRAINT "user_watch_histories_episode_id_fkey" FOREIGN KEY ("episode_id") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "collection_members" ADD CONSTRAINT "collection_members_collection_id_fkey" FOREIGN KEY ("collection_id") REFERENCES "collections"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "collection_members" ADD CONSTRAINT "collection_members_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "collection_members" ADD CONSTRAINT "collection_members_invited_by_id_fkey" FOREIGN KEY ("invited_by_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "medias" ADD CONSTRAINT "medias_type_id_fkey" FOREIGN KEY ("type_id") REFERENCES "media_types"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "medias" ADD CONSTRAINT "medias_source_id_fkey" FOREIGN KEY ("source_id") REFERENCES "media_sources"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "medias" ADD CONSTRAINT "medias_status_id_fkey" FOREIGN KEY ("status_id") REFERENCES "media_statuses"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "medias" ADD CONSTRAINT "medias_age_rating_id_fkey" FOREIGN KEY ("age_rating_id") REFERENCES "media_age_ratings"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "medias" ADD CONSTRAINT "medias_country_id_fkey" FOREIGN KEY ("country_id") REFERENCES "countries"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "medias" ADD CONSTRAINT "medias_updated_by_id_fkey" FOREIGN KEY ("updated_by_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "medias" ADD CONSTRAINT "medias_deleted_by_id_fkey" FOREIGN KEY ("deleted_by_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_submissions" ADD CONSTRAINT "media_submissions_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_submissions" ADD CONSTRAINT "media_submissions_submitter_id_fkey" FOREIGN KEY ("submitter_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_submissions" ADD CONSTRAINT "media_submissions_reviewer_id_fkey" FOREIGN KEY ("reviewer_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_collections" ADD CONSTRAINT "media_collections_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_collections" ADD CONSTRAINT "media_collections_collection_id_fkey" FOREIGN KEY ("collection_id") REFERENCES "collections"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_collections" ADD CONSTRAINT "media_collections_added_by_id_fkey" FOREIGN KEY ("added_by_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_trailers" ADD CONSTRAINT "media_trailers_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_producers" ADD CONSTRAINT "media_producers_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_producers" ADD CONSTRAINT "media_producers_producer_id_fkey" FOREIGN KEY ("producer_id") REFERENCES "producers"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_licensors" ADD CONSTRAINT "media_licensors_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_licensors" ADD CONSTRAINT "media_licensors_licensor_id_fkey" FOREIGN KEY ("licensor_id") REFERENCES "producers"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_studios" ADD CONSTRAINT "media_studios_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_studios" ADD CONSTRAINT "media_studios_studio_id_fkey" FOREIGN KEY ("studio_id") REFERENCES "producers"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "producers" ADD CONSTRAINT "producers_created_by_id_fkey" FOREIGN KEY ("created_by_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_genres" ADD CONSTRAINT "media_genres_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_genres" ADD CONSTRAINT "media_genres_genre_id_fkey" FOREIGN KEY ("genre_id") REFERENCES "genres"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_explicit_genres" ADD CONSTRAINT "media_explicit_genres_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_explicit_genres" ADD CONSTRAINT "media_explicit_genres_genre_id_fkey" FOREIGN KEY ("genre_id") REFERENCES "genres"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_themes" ADD CONSTRAINT "media_themes_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_themes" ADD CONSTRAINT "media_themes_genre_id_fkey" FOREIGN KEY ("genre_id") REFERENCES "genres"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_demographics" ADD CONSTRAINT "media_demographics_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_demographics" ADD CONSTRAINT "media_demographics_demographic_id_fkey" FOREIGN KEY ("demographic_id") REFERENCES "genres"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_relations" ADD CONSTRAINT "media_relations_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_relations" ADD CONSTRAINT "media_relations_related_media_id_fkey" FOREIGN KEY ("related_media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_external_links" ADD CONSTRAINT "media_external_links_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_characters" ADD CONSTRAINT "media_characters_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "media_characters" ADD CONSTRAINT "media_characters_character_id_fkey" FOREIGN KEY ("character_id") REFERENCES "characters"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "voice_actors" ADD CONSTRAINT "voice_actors_staff_id_fkey" FOREIGN KEY ("staff_id") REFERENCES "staff"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "voice_actors" ADD CONSTRAINT "voice_actors_media_character_id_fkey" FOREIGN KEY ("media_character_id") REFERENCES "media_characters"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "episodes" ADD CONSTRAINT "episodes_created_by_id_fkey" FOREIGN KEY ("created_by_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "videos" ADD CONSTRAINT "videos_episode_id_fkey" FOREIGN KEY ("episode_id") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "video_submissions" ADD CONSTRAINT "video_submissions_created_by_id_fkey" FOREIGN KEY ("created_by_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "video_submissions" ADD CONSTRAINT "video_submissions_reviewer_id_fkey" FOREIGN KEY ("reviewer_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "video_submissions" ADD CONSTRAINT "video_submissions_video_id_fkey" FOREIGN KEY ("video_id") REFERENCES "videos"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "video_service_submissions" ADD CONSTRAINT "video_service_submissions_created_by_id_fkey" FOREIGN KEY ("created_by_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "video_service_submissions" ADD CONSTRAINT "video_service_submissions_reviewer_id_fkey" FOREIGN KEY ("reviewer_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "video_service_submissions" ADD CONSTRAINT "video_service_submissions_video_service_id_fkey" FOREIGN KEY ("video_service_id") REFERENCES "video_services"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "comments" ADD CONSTRAINT "comments_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "comments" ADD CONSTRAINT "comments_episode_id_fkey" FOREIGN KEY ("episode_id") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "comment_likes" ADD CONSTRAINT "comment_likes_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "comment_likes" ADD CONSTRAINT "comment_likes_comment_id_fkey" FOREIGN KEY ("comment_id") REFERENCES "comments"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "comment_audit_logs" ADD CONSTRAINT "comment_audit_logs_comment_id_fkey" FOREIGN KEY ("comment_id") REFERENCES "comments"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "comment_audit_logs" ADD CONSTRAINT "comment_audit_logs_performed_by_id_fkey" FOREIGN KEY ("performed_by_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "comment_reports" ADD CONSTRAINT "comment_reports_reporter_id_fkey" FOREIGN KEY ("reporter_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "comment_reports" ADD CONSTRAINT "comment_reports_comment_id_fkey" FOREIGN KEY ("comment_id") REFERENCES "comments"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "provisioned_users" ADD CONSTRAINT "provisioned_users_admin_id_fkey" FOREIGN KEY ("admin_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "provisioned_users" ADD CONSTRAINT "provisioned_users_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "home_media_banners" ADD CONSTRAINT "home_media_banners_media_id_fkey" FOREIGN KEY ("media_id") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "home_media_banners" ADD CONSTRAINT "home_media_banners_created_by_id_fkey" FOREIGN KEY ("created_by_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_VideoToVideoService" ADD CONSTRAINT "_VideoToVideoService_A_fkey" FOREIGN KEY ("A") REFERENCES "videos"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_VideoToVideoService" ADD CONSTRAINT "_VideoToVideoService_B_fkey" FOREIGN KEY ("B") REFERENCES "video_services"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -1,10 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `auth_provider` on the `users` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `provider_token` on the `users` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "users" DROP COLUMN "auth_provider",
|
||||
DROP COLUMN "provider_token";
|
||||
@ -1,8 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `last_login` on the `user_oauth_accounts` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "user_oauth_accounts" DROP COLUMN "last_login";
|
||||
@ -1,12 +0,0 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "user_preferences" DROP CONSTRAINT "user_preferences_char_as_partner_id_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "user_oauth_accounts" ALTER COLUMN "provider_token" SET DATA TYPE TEXT,
|
||||
ALTER COLUMN "refresh_token" SET DATA TYPE TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "user_preferences" ALTER COLUMN "char_as_partner_id" DROP NOT NULL;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_char_as_partner_id_fkey" FOREIGN KEY ("char_as_partner_id") REFERENCES "characters"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@ -1,8 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `valid_until` to the `user_sessions` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "user_sessions" ADD COLUMN "valid_until" TIMESTAMPTZ NOT NULL;
|
||||
@ -1,3 +0,0 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "postgresql"
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,11 @@
|
||||
import { prisma } from "../../src/utils/databases/prisma/connection";
|
||||
import { systemPreferenceSeed } from "./systemPreference.seed";
|
||||
import { userRoleSeed } from "./userRole.seed";
|
||||
import { userSystemSeed } from "./userSystem.seed";
|
||||
|
||||
async function main() {
|
||||
console.log("🌱 Running all seeds...");
|
||||
console.log("🔌 Connecting to database...");
|
||||
|
||||
const userSystemSeedResult = await userSystemSeed();
|
||||
await userRoleSeed(userSystemSeedResult.id);
|
||||
await systemPreferenceSeed();
|
||||
await userSystemSeed();
|
||||
|
||||
console.log("🌳 All seeds completed");
|
||||
}
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { generateUUIDv7 } from "../../src/helpers/databases/uuidv7";
|
||||
import { prisma } from "../../src/utils/databases/prisma/connection";
|
||||
|
||||
export const systemPreferenceSeed = async () => {
|
||||
const preferences: Prisma.SystemPreferenceUpsertArgs["create"][] = [
|
||||
{
|
||||
id: generateUUIDv7(),
|
||||
key: "REGISTRATION_ENABLED",
|
||||
value: process.env.ENABLE_REGISTRATION === "true" ? "true" : "false",
|
||||
description: "Enable or disable user registration",
|
||||
},
|
||||
{
|
||||
id: generateUUIDv7(),
|
||||
key: "HERO_BANNER_ENABLED",
|
||||
value: process.env.ENABLE_HERO_BANNER === "true" ? "true" : "false",
|
||||
description: "Enable or disable hero banner feature",
|
||||
},
|
||||
];
|
||||
|
||||
await prisma.$transaction(async (tx) => {
|
||||
return await Promise.all(
|
||||
preferences.map(
|
||||
async (pref) =>
|
||||
await tx.systemPreference.upsert({
|
||||
where: {
|
||||
key: pref.key,
|
||||
},
|
||||
update: pref,
|
||||
create: pref,
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
};
|
||||
@ -1,73 +0,0 @@
|
||||
import { generateUUIDv7 } from "../../src/helpers/databases/uuidv7";
|
||||
import { prisma } from "../../src/utils/databases/prisma/connection";
|
||||
|
||||
export const userRoleSeed = async (SystemAccountId: string) => {
|
||||
console.log("🔃 Seeding user roles...");
|
||||
const roles = [
|
||||
{
|
||||
name: "ADMIN",
|
||||
description: "Administrator with full access",
|
||||
isSuperadmin: true,
|
||||
canEditMedia: true,
|
||||
canManageMedia: true,
|
||||
canEditEpisodes: true,
|
||||
canManageEpisodes: true,
|
||||
canEditComment: true,
|
||||
canManageComment: true,
|
||||
canEditUser: true,
|
||||
canManageUser: true,
|
||||
canEditSystem: true,
|
||||
canManageSystem: true,
|
||||
createdBy: SystemAccountId,
|
||||
},
|
||||
{
|
||||
name: "USER",
|
||||
description: "Regular user with limited access",
|
||||
isSuperadmin: false,
|
||||
canEditMedia: false,
|
||||
canManageMedia: false,
|
||||
canEditEpisodes: false,
|
||||
canManageEpisodes: false,
|
||||
canEditComment: false,
|
||||
canManageComment: false,
|
||||
canEditUser: false,
|
||||
canManageUser: false,
|
||||
canEditSystem: false,
|
||||
canManageSystem: false,
|
||||
createdBy: SystemAccountId,
|
||||
},
|
||||
];
|
||||
|
||||
await prisma.$transaction(async (tx) => {
|
||||
const createdRoles = await Promise.all(
|
||||
roles.map(
|
||||
async (role) =>
|
||||
await tx.userRole.upsert({
|
||||
where: { name: role.name },
|
||||
update: role,
|
||||
create: {
|
||||
id: generateUUIDv7(),
|
||||
...role,
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
await tx.userRoleAssignment.upsert({
|
||||
where: {
|
||||
userId_roleId: {
|
||||
userId: SystemAccountId,
|
||||
roleId: createdRoles.find((r) => r.name === "ADMIN")!.id,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
userId: SystemAccountId,
|
||||
roleId: createdRoles.find((r) => r.name === "ADMIN")!.id,
|
||||
},
|
||||
update: {
|
||||
userId: SystemAccountId,
|
||||
roleId: createdRoles.find((r) => r.name === "ADMIN")!.id,
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -1,21 +1,21 @@
|
||||
import { generateUUIDv7 } from "../../src/helpers/databases/uuidv7";
|
||||
import { createFile } from "../../src/helpers/files/createFile";
|
||||
import { hashPassword } from "../../src/helpers/security/password/hash";
|
||||
import { prisma } from "../../src/utils/databases/prisma/connection";
|
||||
import {Prisma} from "@prisma/client";
|
||||
|
||||
export const userSystemSeed = async () => {
|
||||
const payload = {
|
||||
name: "SYSTEM",
|
||||
username: process.env.DEFAULT_ADMIN_USERNAME!,
|
||||
fullname: "SYSTEM",
|
||||
email: process.env.DEFAULT_ADMIN_EMAIL!,
|
||||
password: await hashPassword(process.env.DEFAULT_ADMIN_PASSWORD!),
|
||||
};
|
||||
role: "admin"
|
||||
} as Prisma.UserCreateInput;
|
||||
|
||||
const insertedUserSystem = await prisma.user.upsert({
|
||||
where: { username: payload.username },
|
||||
update: payload,
|
||||
create: {
|
||||
id: generateUUIDv7(),
|
||||
...payload,
|
||||
},
|
||||
select: { id: true },
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { baseURL } from "./baseUrl";
|
||||
import {baseURL} from "./baseUrl";
|
||||
|
||||
export const getContentReferenceAPI = (malId: number) => {
|
||||
return {
|
||||
baseURL,
|
||||
getMediaFullInfo: `/anime/${malId}/full`,
|
||||
getMediaCharactersWithVA: `/anime/${malId}/characters`,
|
||||
};
|
||||
return {
|
||||
baseURL,
|
||||
getMediaFullInfo: `/anime/${malId}/full`,
|
||||
getMediaCharacters: `/anime/${malId}/characters`,
|
||||
};
|
||||
};
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
import {AppError} from "../../../helpers/error/instances/app";
|
||||
import {MediaChar} from "../types/mediaCharacters";
|
||||
|
||||
export const bulkInsertMediaCharacterRepository = async (animeMalId: number, characters: MediaChar[]) => {
|
||||
try {
|
||||
return characters[0].character.name;
|
||||
} catch (error) {
|
||||
throw new AppError(500, "Failed to bulk insert media characters", error);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { GenreOrProducer } from "../types/mediaFullInfo.type";
|
||||
import { SystemAccountId } from "../../../config/account/system";
|
||||
|
||||
|
||||
/**
|
||||
* Bulk Insert Producer, Studio, Licensor
|
||||
*
|
||||
* This function handles the bulk insertion of producers, studios, and licensors.
|
||||
* It takes a transaction client, the ID of the media, and an array of producer, studio, and licensor objects.
|
||||
* */
|
||||
export const bulkInsertMediaProducerStudioLicensorRepository = async (
|
||||
tx: Prisma.TransactionClient,
|
||||
media_id: string,
|
||||
payload: (GenreOrProducer & { status: "producer" | "licensor" | "studio" })[],
|
||||
) => {
|
||||
await tx.producer.createMany({
|
||||
data: payload.map((p) => ({
|
||||
mal_id: p.mal_id,
|
||||
type: p.type,
|
||||
name: p.name,
|
||||
url: p.url,
|
||||
created_by_id: SystemAccountId,
|
||||
})),
|
||||
skipDuplicates: true,
|
||||
});
|
||||
|
||||
const insertedProducers = (
|
||||
await tx.producer.findMany({
|
||||
where: {
|
||||
mal_id: {
|
||||
in: payload.map((p) => p.mal_id),
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
mal_id: true,
|
||||
},
|
||||
})
|
||||
).map((producer) => {
|
||||
const statusProducer = payload.find((p) => p.mal_id === producer.mal_id)?.status;
|
||||
return {
|
||||
id: producer.id,
|
||||
mal_id: producer.mal_id,
|
||||
status: statusProducer,
|
||||
};
|
||||
});
|
||||
|
||||
await tx.mediaProducer.createMany({
|
||||
data: insertedProducers
|
||||
.filter((p) => p.status === "producer")
|
||||
.map((producer) => ({
|
||||
media_id,
|
||||
producer_id: producer.id,
|
||||
})),
|
||||
skipDuplicates: true,
|
||||
});
|
||||
|
||||
await tx.mediaLicensor.createMany({
|
||||
data: insertedProducers
|
||||
.filter((p) => p.status === "licensor")
|
||||
.map((producer) => ({
|
||||
media_id,
|
||||
licensor_id: producer.id,
|
||||
})),
|
||||
skipDuplicates: true,
|
||||
});
|
||||
|
||||
await tx.mediaStudio.createMany({
|
||||
data: insertedProducers
|
||||
.filter((p) => p.status === "studio")
|
||||
.map((producer) => ({
|
||||
media_id,
|
||||
studio_id: producer.id,
|
||||
})),
|
||||
skipDuplicates: true,
|
||||
});
|
||||
|
||||
return insertedProducers;
|
||||
};
|
||||
@ -1,69 +0,0 @@
|
||||
import { SystemAccountId } from "../../../config/account/system";
|
||||
import { generateSlug } from "../../../helpers/characters/generateSlug";
|
||||
import { generateUUIDv7 } from "../../../helpers/databases/uuidv7";
|
||||
import { AppError } from "../../../helpers/error/instances/app";
|
||||
import { prisma } from "../../../utils/databases/prisma/connection";
|
||||
import { MediaFullInfoResponse } from "../types/mediaFullInfo.type";
|
||||
|
||||
/**
|
||||
* Studios Insertion
|
||||
*
|
||||
* This section manages the insertion of studios associated with the media.
|
||||
* It processes each studio listed in the media data, generating a slug for
|
||||
* each and performing an upsert operation to either create or update the
|
||||
* studio record in the database. The IDs of the inserted or updated studios
|
||||
* are collected for later association with the media.
|
||||
*
|
||||
* @param data - The full media data containing studios information.
|
||||
* @returns An array of IDs of the inserted or updated studios.
|
||||
*/
|
||||
export const bulkInsertStudiosRepository = async (
|
||||
data: MediaFullInfoResponse,
|
||||
) => {
|
||||
try {
|
||||
const studioIds: string[] = [];
|
||||
for (const studio of data.data.studios) {
|
||||
const slug = (await generateSlug(studio.name)) as string;
|
||||
const studioPayload = {
|
||||
name: studio.name,
|
||||
malId: studio.mal_id,
|
||||
linkAbout: studio.url,
|
||||
createdBy: SystemAccountId,
|
||||
slug,
|
||||
};
|
||||
const insertedStudio = await prisma.studio.upsert({
|
||||
where: { slug },
|
||||
create: {
|
||||
id: generateUUIDv7(),
|
||||
...studioPayload,
|
||||
},
|
||||
update: studioPayload,
|
||||
select: { id: true },
|
||||
});
|
||||
studioIds.push(insertedStudio.id);
|
||||
}
|
||||
for (const studio of data.data.producers) {
|
||||
const slug = (await generateSlug(studio.name)) as string;
|
||||
const studioPayload = {
|
||||
name: studio.name,
|
||||
malId: studio.mal_id,
|
||||
linkAbout: studio.url,
|
||||
createdBy: SystemAccountId,
|
||||
slug,
|
||||
};
|
||||
const insertedStudio = await prisma.studio.upsert({
|
||||
where: { slug },
|
||||
create: {
|
||||
id: generateUUIDv7(),
|
||||
...studioPayload,
|
||||
},
|
||||
update: studioPayload,
|
||||
select: { id: true },
|
||||
});
|
||||
studioIds.push(insertedStudio.id);
|
||||
}
|
||||
return studioIds;
|
||||
} catch (error) {
|
||||
throw new AppError(500, "Failed to insert studios", error);
|
||||
}
|
||||
};
|
||||
@ -1,7 +1,8 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { AppError } from "../../../helpers/error/instances/app";
|
||||
import { MediaFullInfoResponse } from "../types/mediaFullInfo.type";
|
||||
import { prisma } from "../../../utils/databases/prisma/connection";
|
||||
import { generateUUIDv7 } from "../../../helpers/databases/uuidv7";
|
||||
import { bulkInsertMediaProducerStudioLicensorRepository } from "./bulkInsertMediaProducerStudioLicensor.repository";
|
||||
|
||||
/**
|
||||
* Media Payload Construction and Upsert
|
||||
@ -17,22 +18,138 @@ import { generateUUIDv7 } from "../../../helpers/databases/uuidv7";
|
||||
* @param data - The full media data for constructing the media payload.
|
||||
* @returns The inserted or updated media record.
|
||||
*/
|
||||
export const InsertMediaRepository = async ({
|
||||
malId,
|
||||
payload,
|
||||
}: {
|
||||
malId: number;
|
||||
payload: Omit<Prisma.MediaUncheckedCreateInput, "id">;
|
||||
}) => {
|
||||
export const InsertMediaRepository = async ({ payload }: { payload: MediaFullInfoResponse["data"] }) => {
|
||||
try {
|
||||
return await prisma.media.upsert({
|
||||
where: { malId },
|
||||
update: payload,
|
||||
create: {
|
||||
id: generateUUIDv7(),
|
||||
...payload,
|
||||
const constructMediaPayload: Prisma.MediaUpsertArgs["create"] = {
|
||||
mal_id: payload.mal_id,
|
||||
title: payload.title,
|
||||
title_secondary: payload.title_english,
|
||||
title_original: payload.title_japanese,
|
||||
title_synonyms: payload.title_synonyms,
|
||||
trailer: {
|
||||
connectOrCreate: {
|
||||
where: {
|
||||
embed_url: payload.trailer.embed_url,
|
||||
},
|
||||
create: {
|
||||
embed_url: payload.trailer.embed_url,
|
||||
url: payload.trailer.url,
|
||||
small_image_url: payload.trailer.images.small_image_url,
|
||||
large_image_url: payload.trailer.images.large_image_url,
|
||||
maximum_image_url: payload.trailer.images.maximum_image_url,
|
||||
},
|
||||
},
|
||||
},
|
||||
synopsis: payload.synopsis,
|
||||
small_image_url: payload.images.jpg.small_image_url,
|
||||
medium_image_url: payload.images.jpg.image_url,
|
||||
large_image_url: payload.images.jpg.large_image_url,
|
||||
type: {
|
||||
connectOrCreate: {
|
||||
where: {
|
||||
name: payload.type.toLowerCase(),
|
||||
},
|
||||
create: {
|
||||
name: payload.type.toLowerCase(),
|
||||
},
|
||||
},
|
||||
},
|
||||
source: {
|
||||
connectOrCreate: {
|
||||
where: {
|
||||
name: payload.source.toLowerCase(),
|
||||
},
|
||||
create: {
|
||||
name: payload.source.toLowerCase(),
|
||||
},
|
||||
},
|
||||
},
|
||||
status: {
|
||||
connectOrCreate: {
|
||||
where: {
|
||||
name: payload.status.toLowerCase(),
|
||||
},
|
||||
create: {
|
||||
name: payload.status.toLowerCase(),
|
||||
},
|
||||
},
|
||||
},
|
||||
airing: payload.airing,
|
||||
start_airing: payload.aired.from,
|
||||
end_airing: payload.aired.to,
|
||||
age_rating: {
|
||||
connectOrCreate: {
|
||||
where: {
|
||||
name: payload.rating.toLowerCase(),
|
||||
},
|
||||
create: {
|
||||
name: payload.rating.toLowerCase(),
|
||||
min_age: 0, // Placeholder, as the actual age rating details may require additional mapping
|
||||
},
|
||||
},
|
||||
},
|
||||
score_total: 0,
|
||||
score_count: 0,
|
||||
background: payload.background,
|
||||
season: payload.season,
|
||||
year: payload.year,
|
||||
country: {
|
||||
connectOrCreate: {
|
||||
where: {
|
||||
code: "jpn",
|
||||
},
|
||||
create: {
|
||||
name: "japan",
|
||||
slug: "japan",
|
||||
code: "jpn",
|
||||
},
|
||||
},
|
||||
},
|
||||
broadcast_day: payload.broadcast.day,
|
||||
};
|
||||
|
||||
const producerPayload = [
|
||||
...payload.producers.map((producer) => ({
|
||||
mal_id: producer.mal_id,
|
||||
type: producer.type,
|
||||
name: producer.name,
|
||||
url: producer.url,
|
||||
status: "producer" as const,
|
||||
})),
|
||||
...payload.licensors.map((licensor) => ({
|
||||
mal_id: licensor.mal_id,
|
||||
type: licensor.type,
|
||||
name: licensor.name,
|
||||
url: licensor.url,
|
||||
status: "licensor" as const,
|
||||
})),
|
||||
...payload.studios.map((studio) => ({
|
||||
mal_id: studio.mal_id,
|
||||
type: studio.type,
|
||||
name: studio.name,
|
||||
url: studio.url,
|
||||
status: "studio" as const,
|
||||
})),
|
||||
];
|
||||
|
||||
return await prisma.$transaction(async (tx) => {
|
||||
const media = await tx.media.upsert({
|
||||
where: { mal_id: payload.mal_id },
|
||||
create: constructMediaPayload,
|
||||
update: constructMediaPayload,
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
await bulkInsertMediaProducerStudioLicensorRepository(tx, media.id, producerPayload);
|
||||
return {
|
||||
id: media.id,
|
||||
mal_id: payload.mal_id,
|
||||
name: payload.title,
|
||||
};
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
throw new AppError(500, "Failed to insert media", error);
|
||||
}
|
||||
|
||||
@ -1,65 +1,26 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||
import { bulkInsertGenresRepository } from "../../repositories/bulkInsertGenres.repository";
|
||||
import { InsertMediaRepository } from "../../repositories/bulkinsertMedia.repository";
|
||||
import { bulkInsertStudiosRepository } from "../../repositories/bulkInsertStudios.repository";
|
||||
import { MediaFullInfoResponse } from "../../types/mediaFullInfo.type";
|
||||
import { generateSlug } from "../../../../helpers/characters/generateSlug";
|
||||
import { bulkInsertCharWithVAService } from "../internal/bulkInsertCharWithVA.service";
|
||||
import { generateUUIDv7 } from "../../../../helpers/databases/uuidv7";
|
||||
import { SystemAccountId } from "../../../../config/account/system";
|
||||
import { getContentReferenceAPI } from "../../../../config/apis/jikan/media.reference";
|
||||
import {ErrorForwarder} from "../../../../helpers/error/instances/forwarder";
|
||||
import {InsertMediaRepository} from "../../repositories/bulkinsertMedia.repository";
|
||||
import {getContentReferenceAPI} from "../../../../config/apis/jikan/media.reference";
|
||||
import {bulkInsertMediaCharacterRepository} from "../../repositories/bulkInsertMediaCharacter.repository";
|
||||
import {MediaFullInfoResponse} from "../../types/mediaFullInfo.type";
|
||||
import {MediaCharacters} from "../../types/mediaCharacters";
|
||||
|
||||
export const bulkInsertAnimeService = async (malId: number) => {
|
||||
try {
|
||||
const { baseURL, getMediaFullInfo } = getContentReferenceAPI(malId);
|
||||
const mediaFullInfo = (await fetch(baseURL + getMediaFullInfo).then((res) =>
|
||||
res.json(),
|
||||
)) as MediaFullInfoResponse;
|
||||
try {
|
||||
const {baseURL, getMediaFullInfo, getMediaCharacters} = getContentReferenceAPI(malId);
|
||||
const mediaFullInfo = (await fetch(baseURL + getMediaFullInfo).then((res) => res.json())) as MediaFullInfoResponse;
|
||||
|
||||
const insertedGenres = await bulkInsertGenresRepository(mediaFullInfo);
|
||||
const insertedStudios = await bulkInsertStudiosRepository(mediaFullInfo);
|
||||
const insertedCharacters = await bulkInsertCharWithVAService(malId);
|
||||
const insertedMedia = await InsertMediaRepository({
|
||||
payload: mediaFullInfo.data,
|
||||
});
|
||||
|
||||
const constructMediaPayload: Prisma.MediaUpsertArgs["create"] = {
|
||||
id: generateUUIDv7(),
|
||||
title: mediaFullInfo.data.title,
|
||||
titleAlternative: mediaFullInfo.data
|
||||
.titles as unknown as Prisma.InputJsonValue,
|
||||
slug: await generateSlug(mediaFullInfo.data.title, {
|
||||
model: "media",
|
||||
target: "slug",
|
||||
}),
|
||||
malId: mediaFullInfo.data.mal_id,
|
||||
genres: {
|
||||
connect: insertedGenres.map((id) => ({ id })),
|
||||
},
|
||||
studios: {
|
||||
connect: insertedStudios.map((id) => ({ id })),
|
||||
},
|
||||
characters: {
|
||||
connect: insertedCharacters.map(({ id }) => ({ id })),
|
||||
},
|
||||
score: mediaFullInfo.data.score,
|
||||
pictureMedium: mediaFullInfo.data.images.webp.image_url,
|
||||
pictureLarge: mediaFullInfo.data.images.webp.large_image_url,
|
||||
status: mediaFullInfo.data.status,
|
||||
startAiring: mediaFullInfo.data.aired.from,
|
||||
endAiring: mediaFullInfo.data.aired.to,
|
||||
synopsis: mediaFullInfo.data.synopsis,
|
||||
ageRating: mediaFullInfo.data.rating,
|
||||
mediaType: mediaFullInfo.data.type,
|
||||
source: mediaFullInfo.data.source,
|
||||
onDraft: false,
|
||||
uploadedBy: SystemAccountId,
|
||||
};
|
||||
const insertedMedia = await InsertMediaRepository({
|
||||
malId: mediaFullInfo.data.mal_id,
|
||||
payload: constructMediaPayload,
|
||||
});
|
||||
|
||||
return insertedMedia;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
// await bulkInsertMediaCharacterRepository(insertedMedia.mal_id)
|
||||
const mediaChar = await fetch(baseURL + getMediaCharacters).then((res) => res.json()) as MediaCharacters;
|
||||
await bulkInsertMediaCharacterRepository(insertedMedia.mal_id, mediaChar.data);
|
||||
|
||||
return insertedMedia.id;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
};
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { MediaFullInfoResponse } from "../../types/mediaFullInfo.type";
|
||||
import { prisma } from "../../../../utils/databases/prisma/connection";
|
||||
|
||||
interface InsertedProducer {
|
||||
producer: string[];
|
||||
licensor: string[];
|
||||
studio: string[];
|
||||
}
|
||||
|
||||
export const bulkInsertProducerService = async (payload: MediaFullInfoResponse, systemAccountId: string) => {
|
||||
const insertedPayload: InsertedProducer = {
|
||||
producer: [],
|
||||
licensor: [],
|
||||
studio: [],
|
||||
};
|
||||
|
||||
const insertingMainProducer = await prisma.producer.createMany({
|
||||
data: payload.data.producers.map((producer) => ({
|
||||
mal_id: producer.mal_id,
|
||||
type: producer.type,
|
||||
name: producer.name,
|
||||
url: producer.url,
|
||||
created_by_id: systemAccountId,
|
||||
})),
|
||||
skipDuplicates: true,
|
||||
});
|
||||
};
|
||||
@ -1,58 +1,58 @@
|
||||
import { SystemAccountId } from "../../../../config/account/system";
|
||||
import { getContentReferenceAPI } from "../../../../config/apis/jikan/media.reference";
|
||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||
import { bulkInsertCharactersRepository } from "../../repositories/bulkInsertCharacters.repository";
|
||||
import { bulkInsertLangVARepository } from "../../repositories/bulkInsertLangVA.repository";
|
||||
import { MediaCharWithVAInfo } from "../../types/mediaCharWithVAInfo";
|
||||
import { bulkInsertStaffOrPeopleService } from "./bulkInsertStaffOrPeople.service";
|
||||
import {SystemAccountId} from "../../../../config/account/system";
|
||||
import {getContentReferenceAPI} from "../../../../config/apis/jikan/media.reference";
|
||||
import {ErrorForwarder} from "../../../../helpers/error/instances/forwarder";
|
||||
import {bulkInsertCharactersRepository} from "../../repositories/bulkInsertCharacters.repository";
|
||||
import {bulkInsertLangVARepository} from "../../repositories/bulkInsertLangVA.repository";
|
||||
import {MediaCharWithVAInfo} from "../../types/mediaCharacters";
|
||||
import {bulkInsertStaffOrPeopleService} from "./bulkInsertStaffOrPeople.service";
|
||||
|
||||
export const bulkInsertCharWithVAService = async (malId: number) => {
|
||||
try {
|
||||
const { baseURL, getMediaCharactersWithVA } = getContentReferenceAPI(malId);
|
||||
const charactersWithVAData = (await fetch(
|
||||
`${baseURL}${getMediaCharactersWithVA}`,
|
||||
).then((res) => res.json())) as MediaCharWithVAInfo;
|
||||
try {
|
||||
const {baseURL, getMediaCharactersWithVA} = getContentReferenceAPI(malId);
|
||||
const charactersWithVAData = (await fetch(
|
||||
`${baseURL}${getMediaCharactersWithVA}`,
|
||||
).then((res) => res.json())) as MediaCharWithVAInfo;
|
||||
|
||||
const insertedCharacters = [];
|
||||
for (const charEntry of charactersWithVAData.data) {
|
||||
// Insert character if not exists
|
||||
const characterInsertedId = await bulkInsertCharactersRepository({
|
||||
malId: charEntry.character.mal_id,
|
||||
name: charEntry.character.name,
|
||||
role: charEntry.role,
|
||||
favorites: charEntry.favorites,
|
||||
imageUrl: charEntry.character.images.webp.image_url,
|
||||
smallImageUrl: charEntry.character.images.webp.small_image_url,
|
||||
creatorId: SystemAccountId,
|
||||
});
|
||||
const insertedCharacters = [];
|
||||
for (const charEntry of charactersWithVAData.data) {
|
||||
// Insert character if not exists
|
||||
const characterInsertedId = await bulkInsertCharactersRepository({
|
||||
malId: charEntry.character.mal_id,
|
||||
name: charEntry.character.name,
|
||||
role: charEntry.role,
|
||||
favorites: charEntry.favorites,
|
||||
imageUrl: charEntry.character.images.webp.image_url,
|
||||
smallImageUrl: charEntry.character.images.webp.small_image_url,
|
||||
creatorId: SystemAccountId,
|
||||
});
|
||||
|
||||
// Insert character voice actors if not exists
|
||||
const insertedVAs: { staffId: string; lang: string }[] = [];
|
||||
for (const VAEntries of charEntry.voice_actors) {
|
||||
const insertedVAId = await bulkInsertStaffOrPeopleService(
|
||||
VAEntries.person,
|
||||
);
|
||||
insertedVAs.push({
|
||||
staffId: insertedVAId.id,
|
||||
lang: VAEntries.language,
|
||||
});
|
||||
}
|
||||
// Insert character voice actors if not exists
|
||||
const insertedVAs: { staffId: string; lang: string }[] = [];
|
||||
for (const VAEntries of charEntry.voice_actors) {
|
||||
const insertedVAId = await bulkInsertStaffOrPeopleService(
|
||||
VAEntries.person,
|
||||
);
|
||||
insertedVAs.push({
|
||||
staffId: insertedVAId.id,
|
||||
lang: VAEntries.language,
|
||||
});
|
||||
}
|
||||
|
||||
// Link character with inserted VAs
|
||||
for (const langVA of insertedVAs) {
|
||||
await bulkInsertLangVARepository({
|
||||
language: langVA.lang,
|
||||
vaId: langVA.staffId,
|
||||
charId: characterInsertedId.id,
|
||||
creatorId: SystemAccountId,
|
||||
});
|
||||
}
|
||||
// Link character with inserted VAs
|
||||
for (const langVA of insertedVAs) {
|
||||
await bulkInsertLangVARepository({
|
||||
language: langVA.lang,
|
||||
vaId: langVA.staffId,
|
||||
charId: characterInsertedId.id,
|
||||
creatorId: SystemAccountId,
|
||||
});
|
||||
}
|
||||
|
||||
insertedCharacters.push(characterInsertedId);
|
||||
insertedCharacters.push(characterInsertedId);
|
||||
}
|
||||
|
||||
return insertedCharacters;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
|
||||
return insertedCharacters;
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import { SystemAccountId } from "../../../../config/account/system";
|
||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||
import { bulkInsertVoiceActorRepository } from "../../repositories/bulkInsertVoiceActor.repository";
|
||||
import { Person } from "../../types/mediaCharWithVAInfo";
|
||||
import {SystemAccountId} from "../../../../config/account/system";
|
||||
import {ErrorForwarder} from "../../../../helpers/error/instances/forwarder";
|
||||
import {bulkInsertVoiceActorRepository} from "../../repositories/bulkInsertVoiceActor.repository";
|
||||
import {Person} from "../../types/mediaCharacters";
|
||||
|
||||
export const bulkInsertStaffOrPeopleService = async (peopleData: Person) => {
|
||||
try {
|
||||
return await bulkInsertVoiceActorRepository({
|
||||
malId: peopleData.mal_id,
|
||||
name: peopleData.name,
|
||||
imageUrl: peopleData.images.jpg.image_url,
|
||||
creatorId: SystemAccountId,
|
||||
});
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
try {
|
||||
return await bulkInsertVoiceActorRepository({
|
||||
malId: peopleData.mal_id,
|
||||
name: peopleData.name,
|
||||
imageUrl: peopleData.images.jpg.image_url,
|
||||
creatorId: SystemAccountId,
|
||||
});
|
||||
} catch (error) {
|
||||
ErrorForwarder(error);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,59 +0,0 @@
|
||||
export interface MediaCharWithVAInfo {
|
||||
data: Datum[];
|
||||
}
|
||||
|
||||
interface Datum {
|
||||
character: Character;
|
||||
role: Role;
|
||||
favorites: number;
|
||||
voice_actors: VoiceActor[];
|
||||
}
|
||||
|
||||
interface Character {
|
||||
mal_id: number;
|
||||
url: string;
|
||||
images: CharacterImages;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface CharacterImages {
|
||||
jpg: Jpg;
|
||||
webp: Webp;
|
||||
}
|
||||
|
||||
interface Jpg {
|
||||
image_url: string;
|
||||
}
|
||||
|
||||
interface Webp {
|
||||
image_url: string;
|
||||
small_image_url: string;
|
||||
}
|
||||
|
||||
enum Role {
|
||||
Main = "Main",
|
||||
Supporting = "Supporting",
|
||||
}
|
||||
|
||||
export interface VoiceActor {
|
||||
person: Person;
|
||||
language: Language;
|
||||
}
|
||||
|
||||
enum Language {
|
||||
English = "English",
|
||||
Japanese = "Japanese",
|
||||
PortugueseBR = "Portuguese (BR)",
|
||||
Spanish = "Spanish",
|
||||
}
|
||||
|
||||
export interface Person {
|
||||
mal_id: number;
|
||||
url: string;
|
||||
images: PersonImages;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface PersonImages {
|
||||
jpg: Jpg;
|
||||
}
|
||||
50
src/modules/internal/types/mediaCharacters.ts
Normal file
50
src/modules/internal/types/mediaCharacters.ts
Normal file
@ -0,0 +1,50 @@
|
||||
interface StaffVA {
|
||||
mal_id: number;
|
||||
url: string;
|
||||
images: {
|
||||
jpg: {
|
||||
image_url: string;
|
||||
},
|
||||
webp: {
|
||||
image_url: string;
|
||||
small_image_url: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface voiceActor {
|
||||
person: StaffVA;
|
||||
language: string;
|
||||
}
|
||||
|
||||
interface Character {
|
||||
mal_id: number;
|
||||
name: string;
|
||||
url: string;
|
||||
images: {
|
||||
jpg: {
|
||||
image_url: string;
|
||||
},
|
||||
webp: {
|
||||
image_url: string;
|
||||
small_image_url: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Role {
|
||||
Main = "Main",
|
||||
Supporting = "Supporting",
|
||||
Background = "Background",
|
||||
}
|
||||
|
||||
export interface MediaChar {
|
||||
character: Character;
|
||||
role: Role;
|
||||
favorites: number;
|
||||
voice_actors: voiceActor[];
|
||||
}
|
||||
|
||||
export type MediaCharacters = {
|
||||
data: MediaChar[];
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
import { MediaType } from "@prisma/client";
|
||||
import { media_season } from "@prisma/client";
|
||||
export interface MediaFullInfoResponse {
|
||||
data: Data;
|
||||
}
|
||||
@ -14,7 +14,7 @@ interface Data {
|
||||
title_english: string;
|
||||
title_japanese: string;
|
||||
title_synonyms: string[];
|
||||
type: MediaType;
|
||||
type: string;
|
||||
source: string;
|
||||
episodes: number;
|
||||
status: string;
|
||||
@ -30,16 +30,16 @@ interface Data {
|
||||
favorites: number;
|
||||
synopsis: string;
|
||||
background: string;
|
||||
season: string;
|
||||
season: media_season;
|
||||
year: number;
|
||||
broadcast: Broadcast;
|
||||
producers: Genre[];
|
||||
licensors: unknown[];
|
||||
studios: Genre[];
|
||||
genres: Genre[];
|
||||
explicit_genres: unknown[];
|
||||
themes: Genre[];
|
||||
demographics: unknown[];
|
||||
producers: GenreOrProducer[];
|
||||
licensors: GenreOrProducer[];
|
||||
studios: GenreOrProducer[];
|
||||
genres: GenreOrProducer[];
|
||||
explicit_genres: GenreOrProducer[];
|
||||
themes: GenreOrProducer[];
|
||||
demographics: GenreOrProducer[];
|
||||
relations: Relation[];
|
||||
theme: Theme;
|
||||
external: External[];
|
||||
@ -76,18 +76,13 @@ interface External {
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface Genre {
|
||||
export interface GenreOrProducer {
|
||||
mal_id: number;
|
||||
type: Type;
|
||||
type: string;
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
enum Type {
|
||||
Anime = "anime",
|
||||
Manga = "manga",
|
||||
}
|
||||
|
||||
interface Image {
|
||||
image_url: string;
|
||||
small_image_url: string;
|
||||
@ -96,7 +91,7 @@ interface Image {
|
||||
|
||||
interface Relation {
|
||||
relation: string;
|
||||
entry: Genre[];
|
||||
entry: GenreOrProducer[];
|
||||
}
|
||||
|
||||
interface Theme {
|
||||
|
||||
Reference in New Issue
Block a user