Skip to content

Commit

Permalink
Merge pull request #288 from TaloDev/better-demo-events
Browse files Browse the repository at this point in the history
create more natural looking demo events
  • Loading branch information
tudddorrr authored May 26, 2024
2 parents 38e9550 + d7600aa commit b909532
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 67 deletions.
4 changes: 2 additions & 2 deletions docker-compose.ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
16 changes: 5 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
137 changes: 137 additions & 0 deletions src/lib/demo-data/generateDemoEvents.ts
Original file line number Diff line number Diff line change
@@ -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<Event> {
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<void> {
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()
}
31 changes: 2 additions & 29 deletions src/services/public/demo.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -24,31 +22,6 @@ async function scheduleDeletion(req: Request, res: Response, caller: DemoService
}
}

async function updateEventDates(req: Request): Promise<void> {
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<DemoUserJob>

Expand All @@ -70,7 +43,7 @@ export default class DemoService extends Service {
})
}

@Before(updateEventDates)
@Before(generateDemoEvents)
@After(scheduleDeletion)
async post(req: Request): Promise<Response> {
const em: EntityManager = req.ctx.em
Expand Down
15 changes: 3 additions & 12 deletions tests/fixtures/EventFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Event> {
private availablePlayers: Player[]
Expand All @@ -24,19 +24,10 @@ export default class EventFactory extends Factory<Event> {
protected async base(): Promise<Partial<Event>> {
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())
}
}

Expand Down
31 changes: 21 additions & 10 deletions tests/services/_public/demo/post.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
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'
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
Expand All @@ -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 (<EntityManager>global.em).persistAndFlush(events)

events = events.filter((event) => event.createdAt < sub(new Date(), { months: 3 }))
expect(events.length).toBeGreaterThan(0)
let eventsThisMonth = await (<EntityManager>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 (<EntityManager>global.em).persistAndFlush(randomEvents)

await request(global.app)
.post('/public/demo')
.expect(200)

for (const event of events) {
await (<EntityManager>global.em).refresh(event)
}
events = events.filter((event) => event.createdAt < sub(new Date(), { months: 3 }))
eventsThisMonth = await (<EntityManager>global.em).getRepository(Event).find({
createdAt: {
$gte: sub(new Date(), { months: 1 })
}
})

expect(events).toHaveLength(0)
expect(eventsThisMonth.length).toBeGreaterThan(0)
})
})

0 comments on commit b909532

Please sign in to comment.