From 8d1b0d33dc8a998fcf8338b00a58d27c6ca3a53a Mon Sep 17 00:00:00 2001 From: Goostaf Date: Mon, 24 Jun 2024 00:00:46 +0200 Subject: [PATCH 1/2] Add missing SQL migration --- .../migration.sql | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 prisma/migrations/20240623212002_division_documents/migration.sql diff --git a/prisma/migrations/20240623212002_division_documents/migration.sql b/prisma/migrations/20240623212002_division_documents/migration.sql new file mode 100644 index 00000000..9d1d3751 --- /dev/null +++ b/prisma/migrations/20240623212002_division_documents/migration.sql @@ -0,0 +1,24 @@ +-- CreateEnum +CREATE TYPE "DocumentType" AS ENUM ('PROTOCOL', 'BUDGET', 'BUSINESS_PLAN', 'FINANCIAL_REPORT', 'BUSINESS_REPORT', 'MISC'); + +-- CreateTable +CREATE TABLE "DivisionDocument" ( + "id" SERIAL NOT NULL, + "divisionGroupId" INTEGER NOT NULL, + "mediaSha256" TEXT NOT NULL, + "titleSv" TEXT NOT NULL, + "titleEn" TEXT NOT NULL, + "descriptionSv" TEXT NOT NULL, + "descriptionEn" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "type" "DocumentType" NOT NULL DEFAULT 'MISC', + + CONSTRAINT "DivisionDocument_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "DivisionDocument" ADD CONSTRAINT "DivisionDocument_divisionGroupId_fkey" FOREIGN KEY ("divisionGroupId") REFERENCES "DivisionGroup"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DivisionDocument" ADD CONSTRAINT "DivisionDocument_mediaSha256_fkey" FOREIGN KEY ("mediaSha256") REFERENCES "Media"("sha256") ON DELETE RESTRICT ON UPDATE CASCADE; From bde1035b035144664b3da67f46932382cab15a0b Mon Sep 17 00:00:00 2001 From: Goostaf Date: Mon, 24 Jun 2024 00:05:13 +0200 Subject: [PATCH 2/2] Remove migrations from old site --- .gitignore | 2 - Dockerfile | 4 - prisma-old-site/schema.prisma | 265 ------------------ src/actions/migration.ts | 11 - src/app/[locale]/post/search/page.tsx | 1 - src/app/[locale]/settings/page.tsx | 4 - .../MigrationButton/MigrateButton.tsx | 18 -- src/services/migrationService.ts | 265 ------------------ 8 files changed, 570 deletions(-) delete mode 100644 prisma-old-site/schema.prisma delete mode 100644 src/actions/migration.ts delete mode 100644 src/components/MigrationButton/MigrateButton.tsx delete mode 100644 src/services/migrationService.ts diff --git a/.gitignore b/.gitignore index ea915b47..bd0e5668 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,4 @@ package-lock.json /media .idea/ -/prisma-old-site/client/ /db -/db-old diff --git a/Dockerfile b/Dockerfile index 0cdbb6e5..c8fc4eec 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,8 +15,6 @@ WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . RUN yarn prisma generate -#TODO: Remove this line when the old site is removed -RUN yarn prisma generate --schema ./prisma-old-site/schema.prisma RUN yarn build ########################## @@ -37,8 +35,6 @@ RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static -#TODO: Remove this line when the old site is removed -COPY --from=builder --chown=nextjs:nodejs /app/prisma-old-site/client/old-db ./prisma-old-site/client/old-db # Copy logger configs COPY --chown=nextjs:nodejs next-logger.config.js /app/ diff --git a/prisma-old-site/schema.prisma b/prisma-old-site/schema.prisma deleted file mode 100644 index 886f5207..00000000 --- a/prisma-old-site/schema.prisma +++ /dev/null @@ -1,265 +0,0 @@ -generator client { - provider = "prisma-client-js" - output = "client/old-db" -} - -datasource db { - provider = "mysql" - url = env("OLD_DATABASE_URL") -} - -model ar_internal_metadata { - key String @id @db.VarChar(255) - value String? @db.VarChar(255) - created_at DateTime @db.DateTime(0) - updated_at DateTime @db.DateTime(0) -} - -model banners { - id Int @id @default(autoincrement()) - image String? @db.VarChar(255) - group_id String? @db.VarChar(20) - created_at DateTime @db.DateTime(0) - updated_at DateTime @db.DateTime(0) -} - -model comments { - id Int @id @default(autoincrement()) - post_id Int? - body String? @db.Text - user_id String? @db.VarChar(255) - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) - - @@index([post_id], map: "index_comments_on_post_id") -} - -model committee_translations { - id Int @id @default(autoincrement()) - committee_id Int - locale String @db.VarChar(255) - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) - title String? @db.VarChar(255) - description String? @db.Text - - @@index([committee_id], map: "index_committee_translations_on_committee_id") - @@index([locale], map: "index_committee_translations_on_locale") -} - -model committees { - id Int @id @default(autoincrement()) - name String? @db.VarChar(255) - title String? @db.VarChar(255) - description String? @db.Text - url String? @db.VarChar(255) - email String? @db.VarChar(255) - slug String? @db.VarChar(255) - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) - - @@index([slug], map: "index_committees_on_slug") -} - -model configurables { - id Int @id @default(autoincrement()) - name String? @db.VarChar(255) - value String? @db.VarChar(255) - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) - - @@index([name], map: "index_configurables_on_name") -} - -model contacts { - id Int @id @default(autoincrement()) - title String? @db.Text - body String? @db.Text - email String? @db.VarChar(255) - to_whom String? @db.Text - created_at DateTime @db.DateTime(0) - updated_at DateTime @db.DateTime(0) - value String? @db.Text -} - -model course_translations { - id Int @id @default(autoincrement()) - course_id Int - locale String @db.VarChar(255) - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) - name String? @db.VarChar(255) - description String? @db.Text - - @@index([course_id], map: "index_course_translations_on_course_id") - @@index([locale], map: "index_course_translations_on_locale") -} - -model events { - id Int @id @default(autoincrement()) - event_date DateTime? @db.Date - full_day Boolean? - start_time DateTime? @db.Time(0) - end_time DateTime? @db.Time(0) - location String? @db.VarChar(255) - organizer String? @db.VarChar(255) - post_id Int? - facebook_link String? @db.VarChar(255) - - @@index([post_id], map: "index_events_on_post_id") -} - -model frontpages { - id Int @id @default(autoincrement()) - page_id Int? - created_at DateTime @db.DateTime(0) - updated_at DateTime @db.DateTime(0) - - @@index([page_id], map: "index_frontpages_on_page_id") -} - -model menu_links { - id Int @id @default(autoincrement()) - menu_id Int? - controller String? @db.VarChar(255) - action String? @db.VarChar(255) - params String? @db.Text - title String? @db.VarChar(255) - preferred_order Int? - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) - - @@index([menu_id], map: "index_menu_links_on_menu_id") -} - -model menus { - id Int @id @default(autoincrement()) - name String? @db.VarChar(255) - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) -} - -model page_translations { - id Int @id @default(autoincrement()) - page_id Int - locale String @db.VarChar(255) - created_at DateTime @db.DateTime(0) - updated_at DateTime @db.DateTime(0) - title String? @db.VarChar(255) - body String? @db.Text - - @@index([locale], map: "index_page_translations_on_locale") - @@index([page_id], map: "index_page_translations_on_page_id") -} - -model pages { - id Int @id @default(autoincrement()) - title String? @db.VarChar(255) - body String? @db.Text - slug String? @db.VarChar(255) - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) - parent_id Int? - - @@index([parent_id], map: "index_pages_on_parent_id") - @@index([slug], map: "index_pages_on_slug") - @@index([title], map: "index_pages_on_title") -} - -model post_translations { - id Int @id @default(autoincrement()) - post_id Int - locale String @db.VarChar(255) - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) - title String? @db.VarChar(255) - body String? @db.Text - slug String? @db.VarChar(255) - - @@index([locale], map: "index_post_translations_on_locale") - @@index([post_id], map: "index_post_translations_on_post_id") -} - -model posts { - id Int @id @default(autoincrement()) - user_id String @db.VarChar(20) - group_id String? @db.VarChar(20) - title String? @db.VarChar(255) - body String? @db.Text - sticky Boolean @default(false) - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) - slug String? @db.VarChar(255) - comments_count Int? @default(0) - show_public Boolean? - - @@index([group_id], map: "index_posts_on_group_id") - @@index([slug], map: "index_posts_on_slug") - @@index([title], map: "index_posts_on_title") - @@index([user_id], map: "index_posts_on_user_id") -} - -model schema_migrations { - version String @unique(map: "unique_schema_migrations") @db.VarChar(255) -} - -model sessions { - id Int @id @default(autoincrement()) - uid String? @db.VarChar(255) - provider String? @db.VarChar(255) - token String? @db.VarChar(1000) - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) -} - -model sponsor_translations { - id Int @id @default(autoincrement()) - sponsor_id Int - locale String @db.VarChar(255) - created_at DateTime @db.DateTime(0) - updated_at DateTime @db.DateTime(0) - title String? @db.VarChar(255) - - @@index([locale], map: "index_sponsor_translations_on_locale") - @@index([sponsor_id], map: "index_sponsor_translations_on_sponsor_id") -} - -model sponsors { - id Int @id @default(autoincrement()) - name String? @db.VarChar(255) - image String? @db.VarChar(255) - created_at DateTime @db.DateTime(0) - updated_at DateTime @db.DateTime(0) - title String? @db.VarChar(255) - order Int? - imagelink String? @db.VarChar(255) -} - -model uploads { - id Int @id @default(autoincrement()) - source String? @db.VarChar(255) - user_id String? @db.VarChar(255) - created_at DateTime? @db.DateTime(0) - updated_at DateTime? @db.DateTime(0) -} - -model user_group_info_translations { - id Int @id @default(autoincrement()) - user_group_info_id Int - locale String @db.VarChar(255) - created_at DateTime @db.DateTime(0) - updated_at DateTime @db.DateTime(0) - body String? @db.VarChar(255) - - @@index([locale], map: "index_user_group_info_translations_on_locale") - @@index([user_group_info_id], map: "index_user_group_info_translations_on_user_group_info_id") -} - -model user_group_infos { - id Int @id @default(autoincrement()) - user_id String? @db.VarChar(20) - group_id String? @db.VarChar(20) - body String? @db.VarChar(255) - created_at DateTime @db.DateTime(0) - updated_at DateTime @db.DateTime(0) -} diff --git a/src/actions/migration.ts b/src/actions/migration.ts deleted file mode 100644 index 88a37431..00000000 --- a/src/actions/migration.ts +++ /dev/null @@ -1,11 +0,0 @@ -'use server'; - -import MigrationService from '@/services/migrationService'; -import SessionService from '@/services/sessionService'; - -export async function migrate() { - if (!(await SessionService.isAdmin())) { - throw new Error('Unauthorized'); - } - MigrationService.migrate(); -} diff --git a/src/app/[locale]/post/search/page.tsx b/src/app/[locale]/post/search/page.tsx index b6b50fde..4b5cd6f9 100644 --- a/src/app/[locale]/post/search/page.tsx +++ b/src/app/[locale]/post/search/page.tsx @@ -10,7 +10,6 @@ export default async function Page({ return (
} middle={} right={} /> diff --git a/src/app/[locale]/settings/page.tsx b/src/app/[locale]/settings/page.tsx index 66f8a3d9..6cf0395c 100644 --- a/src/app/[locale]/settings/page.tsx +++ b/src/app/[locale]/settings/page.tsx @@ -1,12 +1,8 @@ -import SessionService from '@/services/sessionService'; -import MigrateButton from '@/components/MigrationButton/MigrateButton'; - export default async function Page() { return (
Kontrollpanel

There is nothing to see here yet. Please check back later!

- {(await SessionService.isAdmin()) && }
); } diff --git a/src/components/MigrationButton/MigrateButton.tsx b/src/components/MigrationButton/MigrateButton.tsx deleted file mode 100644 index 6a924753..00000000 --- a/src/components/MigrationButton/MigrateButton.tsx +++ /dev/null @@ -1,18 +0,0 @@ -'use client'; - -import { migrate } from '@/actions/migration'; -import ActionButton from '@/components/ActionButton/ActionButton'; - -const MigrateButton = () => { - return ( - { - migrate().then((r) => console.log(r)); - }} - > - Migrate all the things - - ); -}; - -export default MigrateButton; diff --git a/src/services/migrationService.ts b/src/services/migrationService.ts deleted file mode 100644 index efed4c6f..00000000 --- a/src/services/migrationService.ts +++ /dev/null @@ -1,265 +0,0 @@ -import prisma from '@/prisma'; -import { PrismaClient } from '@/../prisma-old-site/client/old-db'; -import GammaService from '@/services/gammaService'; -import DivisionGroupService from '@/services/divisionGroupService'; -import { PostStatus } from '@prisma/client'; -import MediaService from '@/services/mediaService'; -import { MediaType } from '@/services/fileService'; - -const oldPrisma = new PrismaClient(); - -const mediaUrlRegexPattern = - '(?<=\\((?:(?:\\s*?https?:\\/\\/chalmers\\.it)|(?:\\s*)))((\\/uploads\\/)|(\\/core\\/wp-content\\/uploads\\/))\\S*?(?=(?:(?:\\s*)|(?:\\s+\\".*?\\"\\s*?))\\))'; - -const mediaUrlRegex = new RegExp(mediaUrlRegexPattern, 'gi'); - -export default class MigrationService { - static async migrate() { - await this.migrateGroupPages(); - await this.migrateNewsPosts(); - await this.migratePages(); - } - - static async migrateGroupPages() { - console.log('Migrating group pages'); - const committees = await oldPrisma.committees.findMany(); - - const gammaGroups = await GammaService.getAllSuperGroups(); - - const gammaGroupsInDb = await DivisionGroupService.getAll(); - - const gammaGroupToIdDict: { [key: string]: number } = {}; - for (const group of gammaGroups) { - const groupInDb = gammaGroupsInDb.find( - (g) => g.gammaSuperGroupId == group.superGroup.id - ); - if (!groupInDb) { - continue; - } - gammaGroupToIdDict[group.superGroup.name] = groupInDb.id; - } - - for (const committee of committees) { - console.log(`Migrating committee ${committee.name}`); - - if (gammaGroupToIdDict[committee.slug!] == undefined) { - console.error(`Committee ${committee.name} is missing in the database`); - continue; - } - - const committee_translations = - await oldPrisma.committee_translations.findMany({ - where: { committee_id: committee.id } - }); - - if (committee_translations.length != 2) { - console.error( - `Committee ${committee.id} has ${committee_translations.length} translations` - ); - continue; - } - - const enTranslation = committee_translations.find( - (t) => t.locale == 'en' - ); - const svTranslation = committee_translations.find( - (t) => t.locale == 'sv' - ); - - if (!enTranslation || !svTranslation) { - console.error(`Committee ${committee.id} is missing translations`); - continue; - } - - await prisma.divisionGroup.update({ - where: { id: gammaGroupToIdDict[committee.slug!] }, - data: { - prettyName: committee.name!, - descriptionEn: await this.migrateMediaUrls( - enTranslation.description! - ), - descriptionSv: await this.migrateMediaUrls( - svTranslation.description! - ), - createdAt: committee.created_at!, - updatedAt: committee.updated_at! - } - }); - } - console.log('Migration of committees done!'); - } - - static async migratePages() { - console.log('Migrating pages'); - const pages = await oldPrisma.pages.findMany(); - - for (const page of pages) { - console.log(`Migrating page ${page.id}`); - const page_translations = await oldPrisma.page_translations.findMany({ - where: { page_id: page.id } - }); - - if (page_translations.length != 2) { - console.error( - `Page ${page.id} has ${page_translations.length} translations` - ); - continue; - } - - const enTranslation = page_translations.find((t) => t.locale == 'en'); - const svTranslation = page_translations.find((t) => t.locale == 'sv'); - - if (!enTranslation || !svTranslation) { - console.error(`Page ${page.id} is missing translations`); - continue; - } - - await prisma.divisionPage.create({ - data: { - titleSv: svTranslation.title!, - titleEn: enTranslation.title!, - contentSv: await this.migrateMediaUrls(svTranslation.body!), - contentEn: await this.migrateMediaUrls(enTranslation.body!), - slug: page.slug!, - createdAt: page.created_at!, - updatedAt: page.updated_at! - } - }); - } - console.log('Migration of pages done!'); - } - - private static async getAllOldGammaUsers() { - const response = await fetch('https://gamma.chalmers.it/api/admin/users', { - headers: { - Authorization: 'pre-shared ' + process.env.OLD_GAMMA_API_KEY - } - }); - - if (!response.ok) { - const errorData = await response.json().catch(() => response.statusText); - throw new Error(`Gamma request failed with status ${response.status}`, { - cause: errorData - }); - } - - return (await response.json()) as { id: string; cid: string }[]; - } - - private static async migrateNewsPosts() { - const gammaSuperGroups = (await GammaService.getAllSuperGroups()).flatMap( - (value) => value.superGroup - ); - - const gammaSuperGroupsInDb = await DivisionGroupService.getAll(); - - const groupNameToGammaIdDict: { [key: string]: number } = {}; - - for (const superGroup of gammaSuperGroups) { - const gammaSuperGroupInDb = gammaSuperGroupsInDb.find( - (g) => g.gammaSuperGroupId == superGroup.id - ); - if (!gammaSuperGroupInDb) { - console.log( - `Super group ${superGroup.id} is missing from local database` - ); - continue; - } - groupNameToGammaIdDict[superGroup.name] = gammaSuperGroupInDb.id; - } - - const allGammaUsers = await this.getAllOldGammaUsers(); - const gammaCidToIdDict: { [key: string]: string } = {}; - for (const user of allGammaUsers) { - gammaCidToIdDict[user.cid] = user.id; - } - - const newsPosts = await oldPrisma.posts.findMany(); - for (const post of newsPosts) { - const translations = await oldPrisma.post_translations.findMany({ - where: { post_id: post.id } - }); - console.log(`Migrating post ${post.id}`); - - if (translations.length != 2) { - console.error( - `Post ${post.id} has ${translations.length} translations` - ); - continue; - } - - const enTranslation = translations.find((t) => t.locale == 'en'); - const svTranslation = translations.find((t) => t.locale == 'sv'); - - if (!enTranslation || !svTranslation) { - console.error(`Post ${post.id} is missing translations`); - continue; - } - - const writtenByGammaId = gammaCidToIdDict[post.user_id!]; - if (!writtenByGammaId) { - console.error(`Post ${post.id} is missing a author in gamma`); - continue; - } - - await prisma.newsPost.create({ - data: { - titleEn: enTranslation.title!, - titleSv: svTranslation.title!, - contentEn: await this.migrateMediaUrls(enTranslation.body!), - contentSv: await this.migrateMediaUrls(svTranslation.body!), - createdAt: post.created_at!, - updatedAt: post.updated_at!, - divisionGroupId: groupNameToGammaIdDict[post.group_id!], - writtenByGammaUserId: writtenByGammaId, - status: PostStatus.PUBLISHED - } - }); - } - - console.log('Migration of news done!'); - } - - private static async migrateMediaUrls(postContent: string) { - const matches = postContent.match(mediaUrlRegex); - if (!matches) { - return postContent; - } - - for (const match of matches) { - const newUrl = await this.downloadAndImportMedia( - 'https://chalmers.it' + match - ); - postContent = postContent.replace(match, newUrl); - postContent = postContent.replace( - 'https://chalmers.it/api/media/', - '/api/media/' - ); - postContent = postContent.replace( - 'http://chalmers.it/api/media/', - '/api/media/' - ); - } - - return postContent; - } - - private static async downloadAndImportMedia(url: string) { - console.log(`Downloading ${url}`); - const response = await fetch(url); - if (!response.ok) { - console.error(`Failed to download media from ${url}`); - return ''; - } - - const blob = await response.blob(); - - const file = await MediaService.save(blob, Object.values(MediaType)); - - if (!file) { - throw new Error(`Failed to save media from ${url}`); - } - - return `/api/media/${file?.sha256}`; - } -}