diff --git a/prisma/migrations/20220831121710_update_hosted_image_table/migration.sql b/prisma/migrations/20220831121710_update_hosted_image_table/migration.sql new file mode 100644 index 0000000..e25ab98 --- /dev/null +++ b/prisma/migrations/20220831121710_update_hosted_image_table/migration.sql @@ -0,0 +1,29 @@ +/* + Warnings: + + - The primary key for the `HostedImage` table will be changed. If it partially fails, the table could be left without primary key constraint. + - The `id` column on the `HostedImage` table would be dropped and recreated. This will lead to data loss if there is data in the column. + - Added the required column `provider` to the `HostedImage` table without a default value. This is not possible if the table is not empty. + - Added the required column `provider_image_id` to the `HostedImage` table without a default value. This is not possible if the table is not empty. + - Added the required column `url` to the `HostedImage` table without a default value. This is not possible if the table is not empty. + +*/ + +-- START Custom SQL +-- Because of the breaking changes, we have to apply some custom SQL. +-- By chance, the previous HostedImage migration is not used it production, so we can remove all data from this table +DELETE FROM "HostedImage"; +-- END Custom SQL + + +-- AlterTable +ALTER TABLE "HostedImage" DROP CONSTRAINT "HostedImage_pkey", +ADD COLUMN "provider" TEXT NOT NULL, +ADD COLUMN "provider_image_id" TEXT NOT NULL, +ADD COLUMN "url" TEXT NOT NULL, +DROP COLUMN "id", +ADD COLUMN "id" SERIAL NOT NULL, +ADD CONSTRAINT "HostedImage_pkey" PRIMARY KEY ("id"); + +-- AlterTable +ALTER TABLE "UserKey" ALTER COLUMN "name" SET DEFAULT E'My new wallet key'; diff --git a/prisma/migrations/20220912140653_update_hosted_image_rel_table/migration.sql b/prisma/migrations/20220912140653_update_hosted_image_rel_table/migration.sql new file mode 100644 index 0000000..4e5eb9a --- /dev/null +++ b/prisma/migrations/20220912140653_update_hosted_image_rel_table/migration.sql @@ -0,0 +1,74 @@ +/* + Warnings: + + - A unique constraint covering the columns `[image_id]` on the table `Award` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[cover_image_id]` on the table `Category` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[cover_image_id]` on the table `Hackathon` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[thumbnail_image_id]` on the table `Project` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[cover_image_id]` on the table `Project` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[cover_image_id]` on the table `Story` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[avatar_id]` on the table `User` will be added. If there are existing duplicate values, this will fail. + +*/ +-- AlterTable +ALTER TABLE "Award" ADD COLUMN "image_id" INTEGER; + +-- AlterTable +ALTER TABLE "Category" ADD COLUMN "cover_image_id" INTEGER; + +-- AlterTable +ALTER TABLE "Hackathon" ADD COLUMN "cover_image_id" INTEGER; + +-- AlterTable +ALTER TABLE "Project" ADD COLUMN "cover_image_id" INTEGER, +ADD COLUMN "screenshots_ids" INTEGER[], +ADD COLUMN "thumbnail_image_id" INTEGER; + +-- AlterTable +ALTER TABLE "Story" ADD COLUMN "body_image_ids" INTEGER[], +ADD COLUMN "cover_image_id" INTEGER; + +-- AlterTable +ALTER TABLE "User" ADD COLUMN "avatar_id" INTEGER; + +-- CreateIndex +CREATE UNIQUE INDEX "Award_image_id_key" ON "Award"("image_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Category_cover_image_id_key" ON "Category"("cover_image_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Hackathon_cover_image_id_key" ON "Hackathon"("cover_image_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Project_thumbnail_image_id_key" ON "Project"("thumbnail_image_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Project_cover_image_id_key" ON "Project"("cover_image_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "Story_cover_image_id_key" ON "Story"("cover_image_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_avatar_id_key" ON "User"("avatar_id"); + +-- AddForeignKey +ALTER TABLE "User" ADD CONSTRAINT "User_avatar_id_fkey" FOREIGN KEY ("avatar_id") REFERENCES "HostedImage"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Category" ADD CONSTRAINT "Category_cover_image_id_fkey" FOREIGN KEY ("cover_image_id") REFERENCES "HostedImage"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Project" ADD CONSTRAINT "Project_thumbnail_image_id_fkey" FOREIGN KEY ("thumbnail_image_id") REFERENCES "HostedImage"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Project" ADD CONSTRAINT "Project_cover_image_id_fkey" FOREIGN KEY ("cover_image_id") REFERENCES "HostedImage"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Award" ADD CONSTRAINT "Award_image_id_fkey" FOREIGN KEY ("image_id") REFERENCES "HostedImage"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Story" ADD CONSTRAINT "Story_cover_image_id_fkey" FOREIGN KEY ("cover_image_id") REFERENCES "HostedImage"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Hackathon" ADD CONSTRAINT "Hackathon_cover_image_id_fkey" FOREIGN KEY ("cover_image_id") REFERENCES "HostedImage"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 783d13f..cad516d 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -40,11 +40,13 @@ model Vote { // ----------------- model User { - id Int @id @default(autoincrement()) - pubKey String? @unique - name String? - avatar String? - role String @default("user") + id Int @id @default(autoincrement()) + pubKey String? @unique + name String? + avatar String? + avatar_id Int? @unique + avatar_rel HostedImage? @relation("User_Avatar", fields: [avatar_id], references: [id]) + role String @default("user") email String? jobTitle String? @@ -112,24 +114,31 @@ model Skill { // ----------------- model Category { - id Int @id @default(autoincrement()) - title String - cover_image String? - icon String? + id Int @id @default(autoincrement()) + title String + cover_image String? + cover_image_id Int? @unique + cover_image_rel HostedImage? @relation("Category_CoverImage", fields: [cover_image_id], references: [id]) + icon String? project Project[] } model Project { - id Int @id @default(autoincrement()) - title String - description String - screenshots String[] - website String - thumbnail_image String? - cover_image String? - lightning_address String? - lnurl_callback_url String? + id Int @id @default(autoincrement()) + title String + description String + screenshots String[] + screenshots_ids Int[] + website String + thumbnail_image String? + thumbnail_image_id Int? @unique + thumbnail_image_rel HostedImage? @relation("Project_Thumbnail", fields: [thumbnail_image_id], references: [id]) + cover_image String? + cover_image_id Int? @unique + cover_image_rel HostedImage? @relation("Project_CoverImage", fields: [cover_image_id], references: [id]) + lightning_address String? + lnurl_callback_url String? category Category @relation(fields: [category_id], references: [id]) category_id Int @@ -155,10 +164,12 @@ model ProjectRecruitRoles { } model Award { - id Int @id @default(autoincrement()) - title String - image String - url String + id Int @id @default(autoincrement()) + title String + image String + image_id Int? @unique + image_rel HostedImage? @relation("Award_Image", fields: [image_id], references: [id]) + url String project Project @relation(fields: [project_id], references: [id]) project_id Int @@ -169,15 +180,18 @@ model Award { // ----------------- model Story { - id Int @id @default(autoincrement()) - title String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - body String - excerpt String - cover_image String? - votes_count Int @default(0) - is_published Boolean @default(true) + id Int @id @default(autoincrement()) + title String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + body String + body_image_ids Int[] + excerpt String + cover_image String? + cover_image_id Int? @unique + cover_image_rel HostedImage? @relation("Story_CoverImage", fields: [cover_image_id], references: [id]) + votes_count Int @default(0) + is_published Boolean @default(true) tags Tag[] @@ -230,15 +244,17 @@ model PostComment { // Hackathons // ----------------- model Hackathon { - id Int @id @default(autoincrement()) - title String - start_date DateTime @db.Date - end_date DateTime @db.Date - cover_image String - description String - location String - website String - votes_count Int @default(0) + id Int @id @default(autoincrement()) + title String + start_date DateTime @db.Date + end_date DateTime @db.Date + cover_image String + cover_image_id Int? @unique + cover_image_rel HostedImage? @relation("Hackathon_CoverImage", fields: [cover_image_id], references: [id]) + description String + location String + website String + votes_count Int @default(0) tags Tag[] } @@ -272,10 +288,21 @@ model GeneratedK1 { // Hosted Image // ----------------- model HostedImage { - id String @id - filename String - createdAt DateTime @default(now()) - is_used Boolean @default(false) + id Int @id @default(autoincrement()) + filename String + provider_image_id String + provider String + url String + createdAt DateTime @default(now()) + is_used Boolean @default(false) + + ProjectThumbnail Project? @relation("Project_Thumbnail") + ProjectCoverImage Project? @relation("Project_CoverImage") + CategoryCoverImage Category? @relation("Category_CoverImage") + AwardImage Award? @relation("Award_Image") + HackathonCoverImage Hackathon? @relation("Hackathon_CoverImage") + StoryCoverImage Story? @relation("Story_CoverImage") + User User? @relation("User_Avatar") } // ----------------- diff --git a/prisma/seed/index.js b/prisma/seed/index.js index b455e10..f7c2af2 100644 --- a/prisma/seed/index.js +++ b/prisma/seed/index.js @@ -65,8 +65,192 @@ async function main() { // await createSkills(); - await createTournament(); + // await createTournament(); + await migrateOldImages(); +} + +async function migrateOldImages() { + console.log('Migrating old images data to HostedImage'); + + // Can't use prisma method createMany() for columns like Project.screenshots, because this method doesn't return created IDs. + + /** + * Project + **/ + const projects = await prisma.project.findMany({ + select: { + id: true, + screenshots: true, + cover_image: true, + thumbnail_image: true + } + }) + for (const project of projects) { + /** + * Project.screenshots to Project.screenshots_ids + **/ + let projectScreenshotIds = []; + for (const screenshot of project.screenshots) { + let hostedImageId = await _insertInHostedImage(screenshot) + projectScreenshotIds.push(hostedImageId); + } + if (projectScreenshotIds.length > 0) { + await _updateObjectWithHostedImageId(prisma.project, project.id, { + screenshots_ids: projectScreenshotIds, + }) + } + + /** + * Project.cover_image to Project.cover_image_id + **/ + if (project.cover_image) { + let hostedImageId = await _insertInHostedImage(project.cover_image) + await _updateObjectWithHostedImageId(prisma.project, project.id, { + cover_image_id: hostedImageId, + }) + } + + /** + * Project.thumbnail_image to Project.thumbnail_image_id + **/ + if (project.cover_image) { + let hostedImageId = await _insertInHostedImage(project.thumbnail_image) + await _updateObjectWithHostedImageId(prisma.project, project.id, { + thumbnail_image_id: hostedImageId, + }) + } + } + + /** + * Category + **/ + const categories = await prisma.category.findMany({ + select: { + id: true, + cover_image: true, + } + }) + for (const category of categories) { + if (category.cover_image) { + let hostedImageId = await _insertInHostedImage(category.cover_image) + await _updateObjectWithHostedImageId(prisma.category, category.id, { + cover_image_id: hostedImageId, + }) + } + } + + /** + * Award + **/ + const awards = await prisma.award.findMany({ + select: { + id: true, + image: true, + } + }) + for (const award of awards) { + if (award.image) { + let hostedImageId = await _insertInHostedImage(award.image) + await _updateObjectWithHostedImageId(prisma.award, award.id, { + image_id: hostedImageId, + }) + } + } + + /** + * Hackaton + **/ + const hackatons = await prisma.hackathon.findMany({ + select: { + id: true, + cover_image: true, + } + }) + for (const hackaton of hackatons) { + if (hackaton.cover_image) { + let hostedImageId = await _insertInHostedImage(hackaton.cover_image) + await _updateObjectWithHostedImageId(prisma.hackathon, hackaton.id, { + cover_image_id: hostedImageId, + }) + } + } + + /** + * Story + **/ + const stories = await prisma.story.findMany({ + select: { + id: true, + cover_image: true, + body: true, + } + }) + for (const story of stories) { + /** + * Story.body to Story.body_image_ids + **/ + let bodyImageIds = []; + const regex = /(?:!\[(.*?)\]\((.*?)\))/g + let match; + while ((match = regex.exec(story.body))) { + const [, , value] = match + let hostedImageId = await _insertInHostedImage(value) + bodyImageIds.push(hostedImageId) + } + if (bodyImageIds.length > 0) { + await _updateObjectWithHostedImageId(prisma.story, story.id, { + body_image_ids: bodyImageIds, + }) + } + + /** + * Story.cover_image to Story.cover_image_id + **/ + if (story.cover_image) { + let hostedImageId = await _insertInHostedImage(story.cover_image) + await _updateObjectWithHostedImageId(prisma.story, story.id, { + cover_image_id: hostedImageId, + }) + } + } + + /** + * User + **/ + const users = await prisma.user.findMany({ + select: { + id: true, + avatar: true, + } + }) + for (const user of users) { + if (user.avatar) { + let hostedImageId = await _insertInHostedImage(user.avatar) + await _updateObjectWithHostedImageId(prisma.user, user.id, { + avatar_id: hostedImageId, + }) + } + } +} + +async function _insertInHostedImage(url) { + const newHostedImage = await prisma.hostedImage.create({ + data: { + filename: "default.png", + provider: "external", + provider_image_id: "", + url, + is_used: true + } + }); + return newHostedImage.id; +} +async function _updateObjectWithHostedImageId(prismaObject, objectId, data) { + await prismaObject.update({ + where: { id: objectId }, + data, + }); } async function createCategories() {