From c7f4a9e14af47b0e577ced15cb993afa7eef2311 Mon Sep 17 00:00:00 2001 From: tsa96 Date: Sat, 2 Mar 2024 06:27:09 +0000 Subject: [PATCH] refactor(back): apply class-transformer transformations to static map list files --- .../src/app/modules/maps/map-list.service.ts | 9 +++- libs/db/src/scripts/seed.ts | 46 +++++++++++++++++-- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/apps/backend/src/app/modules/maps/map-list.service.ts b/apps/backend/src/app/modules/maps/map-list.service.ts index e4aaf4e2c..bd0ff8aab 100644 --- a/apps/backend/src/app/modules/maps/map-list.service.ts +++ b/apps/backend/src/app/modules/maps/map-list.service.ts @@ -2,7 +2,7 @@ import { Inject, Injectable, OnModuleInit } from '@nestjs/common'; import { FileStoreService } from '../filestore/file-store.service'; import { EXTENDED_PRISMA_SERVICE } from '../database/db.constants'; import { ExtendedPrismaService } from '../database/prisma.extension'; -import { DtoFactory } from '../../dto'; +import { DtoFactory, MapDto } from '../../dto'; import { MapListVersionDto } from '../../dto/map/map-list-version.dto'; import { CombinedMapStatuses, @@ -13,6 +13,7 @@ import { } from '@momentum/constants'; import * as zlib from 'node:zlib'; import { promisify } from 'node:util'; +import { instanceToPlain, plainToInstance } from 'class-transformer'; @Injectable() export class MapListService implements OnModuleInit { @@ -107,7 +108,11 @@ export class MapListService implements OnModuleInit { } }); - const mapListJson = JSON.stringify(maps); + // Convert to DTO then serialize back to JSON so any class-transformer + // transformations are applied. + const mapListJson = JSON.stringify( + maps.map((map) => instanceToPlain(plainToInstance(MapDto, map))) + ); const compressed = await promisify(zlib.deflate)(mapListJson); const oldVersion = this.version[type]; diff --git a/libs/db/src/scripts/seed.ts b/libs/db/src/scripts/seed.ts index 065d83cdc..22ea8590d 100644 --- a/libs/db/src/scripts/seed.ts +++ b/libs/db/src/scripts/seed.ts @@ -29,6 +29,9 @@ import { FlatMapList, CombinedMapStatuses, mapListPath, + imgSmallPath, + imgMediumPath, + imgLargePath, AdminActivityType } from '@momentum/constants'; import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'; @@ -165,10 +168,15 @@ prismaWrapper(async (prisma: PrismaClient) => { const doFileUploads = args.has('--s3files'); let imageBuffers: { small: Buffer; medium: Buffer; large: Buffer }[]; + + const s3EndpointUrl = process.env['STORAGE_ENDPOINT_URL']; + const s3BucketName = process.env['STORAGE_BUCKET_NAME']; + const s3Url = (str: string) => `${s3EndpointUrl}/${s3BucketName}/${str}`; + const s3 = doFileUploads ? new S3Client({ region: process.env['STORAGE_REGION'], - endpoint: process.env['STORAGE_ENDPOINT_URL'], + endpoint: s3EndpointUrl, credentials: { accessKeyId: process.env['STORAGE_ACCESS_KEY_ID'], secretAccessKey: process.env['STORAGE_SECRET_ACCESS_KEY'] @@ -315,7 +323,7 @@ prismaWrapper(async (prisma: PrismaClient) => { // () => // s3.send( // new PutObjectCommand({ - // Bucket: process.env['STORAGE_BUCKET_NAME'], + // Bucket: s3BucketName, // Key: approvedBspPath('dev_flatgrid'), // Body: mapFile // }) @@ -656,7 +664,7 @@ prismaWrapper(async (prisma: PrismaClient) => { ['small', 'medium', 'large'].map((size) => s3.send( new PutObjectCommand({ - Bucket: process.env['STORAGE_BUCKET_NAME'], + Bucket: s3BucketName, Key: `img/${image.id}-${size}.jpg`, Body: buffer[size] }) @@ -944,11 +952,41 @@ prismaWrapper(async (prisma: PrismaClient) => { } }); + // Unless we illegally cross some module boundaries, we can't use + // class-transformer @Transform/@Expose/@Excludes here. Trust me, I tried + // getting CT working, but doesn't even seem possible with ESBuild. + for (const map of maps) { + delete map.info.mapID; + + for (const image of [...map.images, map.thumbnail] as any[]) { + delete image.mapID; + image.small = s3Url(imgSmallPath(image.id)); + image.medium = s3Url(imgMediumPath(image.id)); + image.large = s3Url(imgLargePath(image.id)); + } + + for (const credit of map.credits as any[]) { + credit.user.steamID = credit.user.steamID.toString(); + credit.user.avatarURL = `https://avatars.cloudflare.steamstatic.com/${credit.user.avatar}`; + delete credit.user.avatar; + delete credit.mapID; + } + + for (const leaderboard of map.leaderboards) { + delete leaderboard.mapID; + } + } + const mapListJson = JSON.stringify(maps); + + // Uncomment below line and import writeFileSync to write this out to disk + // if you want to debug output of this. + // writeFileSync(`./map-list-${type}.json`, mapListJson); + const compressed = await promisify(zlib.deflate)(mapListJson); await s3.send( new PutObjectCommand({ - Bucket: process.env['STORAGE_BUCKET_NAME'], + Bucket: s3BucketName, Key: mapListPath(type, 1), Body: compressed })