diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 980c1e4a..38d979f9 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -27,7 +27,7 @@ jobs: run: npm run build - name: Create GitHub release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 if: "!contains(github.event.head_commit.message, '--no-release')" with: generate_release_notes: true diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 9d47f2d7..6884eff2 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -10,13 +10,13 @@ jobs: - run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -24,7 +24,7 @@ jobs: - name: Build and push id: docker_build - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: push: true tags: | diff --git a/.husky/install.mjs b/.husky/install.mjs new file mode 100644 index 00000000..ba8e33dd --- /dev/null +++ b/.husky/install.mjs @@ -0,0 +1,6 @@ +// Skip Husky install in production and CI +if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') { + process.exit(0) +} +const husky = (await import('husky')).default +console.log(husky()) diff --git a/Dockerfile b/Dockerfile index 3942a0ff..a9d6f019 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,7 @@ COPY package-lock.json . EXPOSE 80 FROM base AS dev +COPY .husky .husky RUN npm ci CMD [ "npm", "run", "watch" ] diff --git a/docker-compose.ci.yml b/docker-compose.ci.yml index 3905b528..bd6eb951 100644 --- a/docker-compose.ci.yml +++ b/docker-compose.ci.yml @@ -2,8 +2,8 @@ version: '3.9' services: test-db: - image: mysql:8 - command: --default-authentication-plugin=mysql_native_password --sql_mode= + image: mysql:8.4 + command: --mysql-native-password=ON environment: - MYSQL_DATABASE=${DB_NAME} - MYSQL_ROOT_PASSWORD=${DB_PASS} diff --git a/docker-compose.test.yml b/docker-compose.test.yml index b517559c..9731e55b 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -3,7 +3,7 @@ version: '3.9' services: test-db: image: mysql:8 - command: --default-authentication-plugin=mysql_native_password --sql_mode= + command: --mysql-native-password=ON environment: - MYSQL_DATABASE=${DB_NAME} - MYSQL_ROOT_PASSWORD=${DB_PASS} diff --git a/docker-compose.yml b/docker-compose.yml index b007ea72..ad84e354 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,7 +10,7 @@ services: db: image: mysql:8 - command: --default-authentication-plugin=mysql_native_password --sql_mode= + command: --mysql-native-password=ON environment: - MYSQL_DATABASE=${DB_NAME} - MYSQL_ROOT_PASSWORD=${DB_PASS} diff --git a/package-lock.json b/package-lock.json index fa335df6..ccef60aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,20 @@ { "name": "game-services", - "version": "0.31.1", + "version": "0.32.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "game-services", - "version": "0.31.1", + "version": "0.32.0", "license": "MIT", "dependencies": { "@dinero.js/currencies": "^2.0.0-alpha.14", "@koa/cors": "^5.0.0", - "@mikro-orm/core": "^6.2.3", - "@mikro-orm/migrations": "^6.2.3", - "@mikro-orm/mysql": "^6.2.3", - "@mikro-orm/reflection": "^6.2.3", + "@mikro-orm/core": "^6.2.8", + "@mikro-orm/migrations": "^6.2.8", + "@mikro-orm/mysql": "^6.2.8", + "@mikro-orm/reflection": "^6.2.8", "@sendgrid/mail": "^7.6.2", "@sentry/node": "^7.47.0", "@sentry/utils": "^7.47.0", @@ -22,6 +22,7 @@ "axios": "^1.6.8", "bcrypt": "^5.1.0", "bullmq": "^3.2.0", + "casual": "^1.6.2", "date-fns": "^2.28.0", "dinero.js": "^2.0.0-alpha.14", "dotenv": "^16.0.0", @@ -45,7 +46,7 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@mikro-orm/cli": "^6.2.3", + "@mikro-orm/cli": "^6.2.8", "@types/koa": "^2.13.5", "@types/koa-bodyparser": "^4.3.7", "@types/koa-logger": "^3.1.2", @@ -56,7 +57,6 @@ "@typescript-eslint/parser": "^5.40.1", "@vitest/coverage-v8": "^1.5.2", "axios-mock-adapter": "^1.22.0", - "casual": "^1.6.2", "eslint": "^8.26.0", "hefty": "^1.1.0", "husky": "^9.0.11", @@ -787,14 +787,14 @@ } }, "node_modules/@mikro-orm/cli": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.2.3.tgz", - "integrity": "sha512-CAvqBugClipxhAKW4DgW+qnT/iOmOBumdhI+EhL7mYuem+UZa96RLgq/N0u3LHrd0rsNPCmDUSefMHXaadPXeQ==", + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.2.8.tgz", + "integrity": "sha512-ahQQ6doFX3OmO70ALu+XihR5yA4ZC1luJFN1M+q1xHd+qB0xZcZfmCvFgs8K6FafsS6ttre/0W271fEWe8LecA==", "dev": true, "dependencies": { "@jercle/yargonaut": "1.1.5", - "@mikro-orm/core": "6.2.3", - "@mikro-orm/knex": "6.2.3", + "@mikro-orm/core": "6.2.8", + "@mikro-orm/knex": "6.2.8", "fs-extra": "11.2.0", "tsconfig-paths": "4.2.0", "yargs": "17.7.2" @@ -808,16 +808,16 @@ } }, "node_modules/@mikro-orm/core": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.2.3.tgz", - "integrity": "sha512-FtUZ7xlmEwC1Kk4fZ2Coy6e79WlKYF4cGrEeE1k+n9g1TJpuBSzaXzF3kmXsy6cv0yiR9W6unJVFyIOGIr4X5Q==", + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.2.8.tgz", + "integrity": "sha512-zXw9THLF3zq/zUmL+nKZqM3kSVuOrSC2rs7ZSlnoselcqkXfYeblYC9E1Fg7ktpNa/4zzovYAWHrifFzpz2FHg==", "dependencies": { "dataloader": "2.2.2", "dotenv": "16.4.5", "esprima": "4.0.1", "fs-extra": "11.2.0", "globby": "11.1.0", - "mikro-orm": "6.2.3", + "mikro-orm": "6.2.8", "reflect-metadata": "0.2.2" }, "engines": { @@ -828,9 +828,9 @@ } }, "node_modules/@mikro-orm/knex": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.2.3.tgz", - "integrity": "sha512-9YZxEmS/32ivgWxDhY1gLrL0ovjVZoS/4wsA0gulIxC8ORkMnY9hzyvdJoMQ0hdVENXC8oAF4LMjtYvBghGQGA==", + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.2.8.tgz", + "integrity": "sha512-lO434glly1YSTYtgxXgdAhBYYb0t81iSbutsD3/L2hiDgcyXspmEIKb3lROnfXzSrfCNCLU65Z/HZPEHKlO27w==", "dependencies": { "fs-extra": "11.2.0", "knex": "3.1.0", @@ -844,11 +844,11 @@ } }, "node_modules/@mikro-orm/migrations": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/migrations/-/migrations-6.2.3.tgz", - "integrity": "sha512-nJWLan5/BIfbwJrd/gp0sT+HCysof0lb9269AzeTjl/+xAh/8AhuQW88oqxlmyr3kiSu8K42yb/L/Nbm0vFTww==", + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@mikro-orm/migrations/-/migrations-6.2.8.tgz", + "integrity": "sha512-frdGTcP0ncY3Qx0QplLeXoTiANC5R2kfrAPqG7CrfryZg+/hhULjHDJK7lcKDEQ5ukzxEz8HvNPAAU7RSrVk0w==", "dependencies": { - "@mikro-orm/knex": "6.2.3", + "@mikro-orm/knex": "6.2.8", "fs-extra": "11.2.0", "umzug": "3.8.0" }, @@ -860,11 +860,11 @@ } }, "node_modules/@mikro-orm/mysql": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/mysql/-/mysql-6.2.3.tgz", - "integrity": "sha512-LMLAO/OXru5RkBi4L6QYm6xckfNP9dUps9s/xYdZYwPBvezoQSzpPhaWFR5XKgzww8NyGjDS9N1FNr/SMp079Q==", + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@mikro-orm/mysql/-/mysql-6.2.8.tgz", + "integrity": "sha512-/76cE+O+Kt4WoOi0QO6eSNpRyp02P0K+VY5eNnoGjsWTRJ0FwtfIpbXXpeulVvZk7eR5sCNv+IsUEKNeGYIbEg==", "dependencies": { - "@mikro-orm/knex": "6.2.3", + "@mikro-orm/knex": "6.2.8", "mysql2": "3.9.7" }, "engines": { @@ -875,9 +875,9 @@ } }, "node_modules/@mikro-orm/reflection": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.2.3.tgz", - "integrity": "sha512-VtaBP2DOso6wiMorytGN5xseMzRqMfG85nXkDQLcHw97wu5wApxC1btOJvK/4KZREfkrNGfmUbye4zG1L6Xlbw==", + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.2.8.tgz", + "integrity": "sha512-/G0vdyWnadzAR+aWXE4/j2fC6gm89/OJq1iX/Nen8JLHfddyl+G6pQ7xV1NelO1mJ2MA7NOMKQ/Uvweniddvkg==", "dependencies": { "globby": "11.1.0", "ts-morph": "22.0.0" @@ -1673,7 +1673,9 @@ } }, "node_modules/@types/koa-logger": { - "version": "3.1.3", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/koa-logger/-/koa-logger-3.1.5.tgz", + "integrity": "sha512-N4f9GRdokJ/gLiCSvd3GGar/D74HJWzuvSJiruayCsz2e7gGkG6DQaque+kM3xo6LjyCRVUUt9HHJCSMjsXrIA==", "dev": true, "license": "MIT", "dependencies": { @@ -1805,9 +1807,10 @@ } }, "node_modules/@types/supertest": { - "version": "2.0.12", + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.16.tgz", + "integrity": "sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg==", "dev": true, - "license": "MIT", "dependencies": { "@types/superagent": "*" } @@ -2665,8 +2668,6 @@ "version": "1.6.2", "resolved": "https://registry.npmjs.org/casual/-/casual-1.6.2.tgz", "integrity": "sha512-NQObL800rg32KZ9bBajHbyDjxLXxxuShChQg7A4tbSeG3n1t7VYGOSkzFSI9gkSgOHp+xilEJ7G0L5l6M30KYA==", - "dev": true, - "license": "MIT", "dependencies": { "mersenne-twister": "^1.0.1", "moment": "^2.15.2" @@ -5871,9 +5872,7 @@ "node_modules/mersenne-twister": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mersenne-twister/-/mersenne-twister-1.1.0.tgz", - "integrity": "sha512-mUYWsMKNrm4lfygPkL3OfGzOPTR2DBlTkBNHM//F6hGp8cLThY897crAlk3/Jo17LEOOjQUrNAx6DvgO77QJkA==", - "dev": true, - "license": "MIT" + "integrity": "sha512-mUYWsMKNrm4lfygPkL3OfGzOPTR2DBlTkBNHM//F6hGp8cLThY897crAlk3/Jo17LEOOjQUrNAx6DvgO77QJkA==" }, "node_modules/methods": { "version": "1.1.2", @@ -5899,9 +5898,9 @@ } }, "node_modules/mikro-orm": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.2.3.tgz", - "integrity": "sha512-oXVDLZWl9b4th2d28QaQt7CdX/eMeNjLkQfeIqNK1tJpXgJ45wICNutHe94ivhOqHPIQC5XMuwIEkSgWMCWSgg==", + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.2.8.tgz", + "integrity": "sha512-UMPa7QtzP5Cb98NDHtL7Q4rBCoUB6BQ3wa+vXPlZO79TVfQTd9fAdJuIdB+49qZJRPcEMowg2POYs1axtJoAPQ==", "engines": { "node": ">= 18.12.0" } @@ -6031,11 +6030,9 @@ } }, "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "dev": true, - "license": "MIT", + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "engines": { "node": "*" } diff --git a/package.json b/package.json index 561feabd..baeddd55 100644 --- a/package.json +++ b/package.json @@ -1,28 +1,28 @@ { "name": "game-services", - "version": "0.31.1", + "version": "0.32.0", "description": "", "main": "src/index.ts", "scripts": { "watch": "tsnd --respawn src/index.ts", "build": "npx tsc -p tsconfig.build.json", - "seed": "docker-compose -f docker-compose.yml -f docker-compose.dev.yml exec backend npx ts-node tests/seed.ts", "dc": "docker-compose -f docker-compose.yml -f docker-compose.dev.yml", + "seed": "npm run dc -- exec backend npx ts-node tests/seed.ts", "test": "./tests/run-tests.sh", - "up": "npm run dc up --build -d", - "down": "npm run dc down", - "restart": "npm run dc restart backend && npm run logs", - "logs": "npm run dc logs --follow backend", + "up": "npm run dc -- up --build -d", + "down": "npm run dc -- down", + "restart": "npm run dc -- restart backend && npm run logs", + "logs": "npm run dc -- logs backend --follow", "migration:create": "DB_HOST=127.0.0.1 mikro-orm migration:create", "migration:up": "DB_HOST=127.0.0.1 mikro-orm migration:up", "service:create": "hygen service new", - "prepare": "husky || true", + "prepare": "node .husky/install.mjs", "lint": "eslint src/**/*.ts tests/**/*.ts" }, "author": "Sleepy Studios", "license": "MIT", "devDependencies": { - "@mikro-orm/cli": "^6.2.3", + "@mikro-orm/cli": "^6.2.8", "@types/koa": "^2.13.5", "@types/koa-bodyparser": "^4.3.7", "@types/koa-logger": "^3.1.2", @@ -33,7 +33,6 @@ "@typescript-eslint/parser": "^5.40.1", "@vitest/coverage-v8": "^1.5.2", "axios-mock-adapter": "^1.22.0", - "casual": "^1.6.2", "eslint": "^8.26.0", "hefty": "^1.1.0", "husky": "^9.0.11", @@ -49,10 +48,10 @@ "dependencies": { "@dinero.js/currencies": "^2.0.0-alpha.14", "@koa/cors": "^5.0.0", - "@mikro-orm/core": "^6.2.3", - "@mikro-orm/migrations": "^6.2.3", - "@mikro-orm/mysql": "^6.2.3", - "@mikro-orm/reflection": "^6.2.3", + "@mikro-orm/core": "^6.2.8", + "@mikro-orm/migrations": "^6.2.8", + "@mikro-orm/mysql": "^6.2.8", + "@mikro-orm/reflection": "^6.2.8", "@sendgrid/mail": "^7.6.2", "@sentry/node": "^7.47.0", "@sentry/utils": "^7.47.0", @@ -60,6 +59,7 @@ "axios": "^1.6.8", "bcrypt": "^5.1.0", "bullmq": "^3.2.0", + "casual": "^1.6.2", "date-fns": "^2.28.0", "dinero.js": "^2.0.0-alpha.14", "dotenv": "^16.0.0", diff --git a/src/lib/demo-data/generateDemoEvents.ts b/src/lib/demo-data/generateDemoEvents.ts new file mode 100644 index 00000000..cdfe9263 --- /dev/null +++ b/src/lib/demo-data/generateDemoEvents.ts @@ -0,0 +1,137 @@ +import { EntityManager } from '@mikro-orm/mysql' +import { Request } from 'koa-clay' +import Event from '../../entities/event' +import { addDays, differenceInDays, endOfDay, startOfDay, subMonths } from 'date-fns' +import casual from 'casual' +import Prop from '../../entities/prop' +import Game from '../../entities/game' +import randomDate from '../dates/randomDate' +import PlayerAlias from '../../entities/player-alias' + +type DemoEvent = { + name: string + props?: { + [key: string]: () => string + } +} + +const demoEvents: DemoEvent[] = [ + { + name: 'Treasure Discovered', + props: { + zoneId: () => casual.integer(1, 30).toString(), + treasureId: () => casual.integer(1, 255).toString() + } + }, + { + name: 'Levelled up', + props: { + newLevel: () => casual.integer(2, 60).toString(), + timeTaken: () => casual.integer(10, 1000).toString() + } + }, + { + name: 'Potion Used', + props: { + itemId: () => casual.integer(1, 255).toString(), + type: () => casual.random_element(['HP', 'MP']) + } + }, + { + name: 'Item Crafted', + props: { + itemId: () => casual.integer(1, 255).toString(), + quantity: () => casual.integer(1, 5).toString() + } + }, + { + name: 'Quest Completed', + props: { + questId: () => casual.integer(1, 255).toString() + } + } +] + +function getDemoEventProps(demoEvent: DemoEvent) { + const eventProps: Prop[] = [] + + for (const key in demoEvent.props) { + eventProps.push(new Prop(key, demoEvent.props[key]())) + } + + eventProps.push(new Prop('TALO_DEMO_EVENT', '1')) + + return eventProps +} + +export function generateEventData(date: Date): Partial { + const randomEvent: DemoEvent = casual.random_element(demoEvents) + const eventProps: Prop[] = getDemoEventProps(randomEvent) + const createdAt = randomDate(startOfDay(date), endOfDay(date)) + + return { + name: randomEvent.name, + props: eventProps, + createdAt + } +} + +export async function generateDemoEvents(req: Request): Promise { + const em: EntityManager = req.ctx.em + + const games = await em.getRepository(Game).find({ + organisation: { + name: process.env.DEMO_ORGANISATION_NAME + } + }) + + const startDate = subMonths(new Date(), 1) + + for (const game of games) { + const events = await em.getRepository(Event).find({ + playerAlias: { + player: { + game + } + }, + createdAt: { + $gte: startDate + } + }) + + if (events.length === 0) { + const prev: { [key: string]: number } = {} + + const playerAliases = await em.getRepository(PlayerAlias).find({ + player: { + game + } + }) + + for (let dayStep = 0; dayStep < differenceInDays(new Date(), startDate) + 1; dayStep++) { + const day = addDays(startDate, dayStep) + + for (const demoEvent of demoEvents) { + let numToGenerate = casual.integer(1, 3) + + if (prev[demoEvent.name]) { + const increaseAmount = Math.max(casual.integer(0, 3) === 0 ? 0 : 1, Math.ceil(prev[demoEvent.name] * (casual.integer(0, 30) / 100))) + numToGenerate = prev[demoEvent.name] + (increaseAmount * (casual.integer(0, 2) === 0 ? -1 : 1)) + } + + prev[demoEvent.name] = numToGenerate + + for (let i = 0; i < numToGenerate; i++) { + const event = new Event(demoEvent.name, game) + event.setProps(getDemoEventProps(demoEvent)) + event.playerAlias = casual.random_element(playerAliases) + event.createdAt = randomDate(startOfDay(day), endOfDay(day)) + await em.persist(event) + } + } + } + } + } + + await em.flush() +} diff --git a/src/middlewares/api-key-middleware.ts b/src/middlewares/api-key-middleware.ts index 68865167..51a2e9be 100644 --- a/src/middlewares/api-key-middleware.ts +++ b/src/middlewares/api-key-middleware.ts @@ -12,14 +12,17 @@ export default async function apiKeyMiddleware(ctx: Context, next: Next): Promis const decodedToken = jwt.decode(parts[1]) if (decodedToken) { - const apiKey = await em.getRepository(APIKey).findOne(decodedToken.sub) - await em.populate(apiKey, ['game.apiSecret']) + const apiKey = await em.getRepository(APIKey).findOne(decodedToken.sub, { + populate: ['game.apiSecret'] + }) - ctx.state.key = apiKey - ctx.state.secret = apiKey.game.apiSecret.getPlainSecret() + if (apiKey) { + ctx.state.key = apiKey + ctx.state.secret = apiKey.game.apiSecret.getPlainSecret() - if (!apiKey.revokedAt) apiKey.lastUsedAt = new Date() - await em.flush() + if (!apiKey.revokedAt) apiKey.lastUsedAt = new Date() + await em.flush() + } } } } diff --git a/src/services/public/demo.service.ts b/src/services/public/demo.service.ts index 54ac1ae8..990a6229 100644 --- a/src/services/public/demo.service.ts +++ b/src/services/public/demo.service.ts @@ -3,15 +3,13 @@ import User, { UserType } from '../../entities/user' import { EntityManager, MikroORM } from '@mikro-orm/mysql' import buildTokenPair from '../../lib/auth/buildTokenPair' import Organisation from '../../entities/organisation' -import { sub } from 'date-fns' import ormConfig from '../../config/mikro-orm.config' import createQueue from '../../lib/queues/createQueue' import UserSession from '../../entities/user-session' -import Event from '../../entities/event' -import randomDate from '../../lib/dates/randomDate' import bcrypt from 'bcrypt' import GameActivity from '../../entities/game-activity' import { Job, Queue } from 'bullmq' +import { generateDemoEvents } from '../../lib/demo-data/generateDemoEvents' interface DemoUserJob { userId: number @@ -24,31 +22,6 @@ async function scheduleDeletion(req: Request, res: Response, caller: DemoService } } -async function updateEventDates(req: Request): Promise { - const em: EntityManager = req.ctx.em - - const events = await em.getRepository(Event).find({ - playerAlias: { - player: { - game: { - organisation: { - name: process.env.DEMO_ORGANISATION_NAME - } - } - } - }, - createdAt: { - $lt: sub(new Date(), { months: 3 }) - } - }) - - for (const event of events) { - event.createdAt = randomDate(sub(new Date(), { months: 2 }), new Date()) - } - - await em.flush() -} - export default class DemoService extends Service { queue: Queue @@ -70,7 +43,7 @@ export default class DemoService extends Service { }) } - @Before(updateEventDates) + @Before(generateDemoEvents) @After(scheduleDeletion) async post(req: Request): Promise { const em: EntityManager = req.ctx.em diff --git a/tests/fixtures/EventFactory.ts b/tests/fixtures/EventFactory.ts index 5a374cbd..183649d5 100644 --- a/tests/fixtures/EventFactory.ts +++ b/tests/fixtures/EventFactory.ts @@ -3,8 +3,8 @@ import casual from 'casual' import Event from '../../src/entities/event' import Player from '../../src/entities/player' import { sub } from 'date-fns' -import Prop from '../../src/entities/prop' import randomDate from '../../src/lib/dates/randomDate' +import { generateEventData } from '../../src/lib/demo-data/generateDemoEvents' export default class EventFactory extends Factory { private availablePlayers: Player[] @@ -24,19 +24,10 @@ export default class EventFactory extends Factory { protected async base(): Promise> { const player: Player = casual.random_element(this.availablePlayers) - const availableProps = ['itemId', 'zoneId', 'treasureId', 'currentLevel', 'timeTaken', 'positionX', 'positionY', 'objectId', 'actionId', 'positionZ', 'currentHealth', 'currentMana', 'currentEnergy', 'npcId'] - const propsCount = casual.integer(0, 4) - const props: Prop[] = [] - - for (let i = 0; i < propsCount; i++) { - props.push(new Prop(casual.random_element(availableProps), String(casual.integer(0, 999)))) - } - return { - name: casual.random_element(this.eventTitles), + ...generateEventData(new Date()), game: player.game, - playerAlias: casual.random_element(player.aliases.getItems()), - props + playerAlias: casual.random_element(player.aliases.getItems()) } } diff --git a/tests/services/_public/demo/post.test.ts b/tests/services/_public/demo/post.test.ts index 8d70cbea..c53000c9 100644 --- a/tests/services/_public/demo/post.test.ts +++ b/tests/services/_public/demo/post.test.ts @@ -1,5 +1,6 @@ import { EntityManager } from '@mikro-orm/mysql' import request from 'supertest' +import Event from '../../../../src/entities/event' import Organisation from '../../../../src/entities/organisation' import OrganisationFactory from '../../../fixtures/OrganisationFactory' import User, { UserType } from '../../../../src/entities/user' @@ -7,6 +8,7 @@ import EventFactory from '../../../fixtures/EventFactory' import PlayerFactory from '../../../fixtures/PlayerFactory' import GameFactory from '../../../fixtures/GameFactory' import { sub } from 'date-fns' +import randomDate from '../../../../src/lib/dates/randomDate' describe('Demo service - post', () => { let demoOrg: Organisation @@ -31,24 +33,33 @@ describe('Demo service - post', () => { expect(user).toBeNull() }) - it('should update the createdAt of events older than 3 months', async () => { + it('should insert events if there arent any for the last month', async () => { const game = await new GameFactory(demoOrg).one() const players = await new PlayerFactory([game]).many(2) - let events = await new EventFactory(players).state('this year').many(20) - await (global.em).persistAndFlush(events) - events = events.filter((event) => event.createdAt < sub(new Date(), { months: 3 })) - expect(events.length).toBeGreaterThan(0) + let eventsThisMonth = await (global.em).getRepository(Event).find({ + createdAt: { + $gte: sub(new Date(), { months: 1 }) + } + }) + + expect(eventsThisMonth).toHaveLength(0) + + const randomEvents = await new EventFactory(players).with(() => ({ + createdAt: randomDate(sub(new Date(), { years: 1 }), sub(new Date(), { months: 2 })) + })).many(20) + await (global.em).persistAndFlush(randomEvents) await request(global.app) .post('/public/demo') .expect(200) - for (const event of events) { - await (global.em).refresh(event) - } - events = events.filter((event) => event.createdAt < sub(new Date(), { months: 3 })) + eventsThisMonth = await (global.em).getRepository(Event).find({ + createdAt: { + $gte: sub(new Date(), { months: 1 }) + } + }) - expect(events).toHaveLength(0) + expect(eventsThisMonth.length).toBeGreaterThan(0) }) })