Skip to content

Commit b430ffd

Browse files
authored
Merge pull request #117 from TaloDev/develop
Release 0.18.0
2 parents aac4878 + 6a1d42c commit b430ffd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+411
-642
lines changed

_templates/service/new/api-service.ejs.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default class <%= h.changeCase.pascal(name) %>APIService extends APIServi
1212
async post(req: Request): Promise<Response> {
1313
const key: APIKey = await this.getAPIKey(req.ctx)
1414
return await forwardRequest(req, {
15-
body: {
15+
params: {
1616
gameId: key.game.id
1717
}
1818
})

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "game-services",
3-
"version": "0.17.0",
3+
"version": "0.18.0",
44
"description": "",
55
"main": "src/index.ts",
66
"scripts": {
@@ -22,7 +22,7 @@
2222
"author": "Sleepy Studios",
2323
"license": "MIT",
2424
"devDependencies": {
25-
"@mikro-orm/cli": "^5.1.4",
25+
"@mikro-orm/cli": "^5.2.2",
2626
"@types/ioredis": "4.22.3",
2727
"@types/jest": "^27.4.1",
2828
"@types/koa": "^2.13.4",
@@ -51,9 +51,9 @@
5151
"dependencies": {
5252
"@dinero.js/currencies": "^2.0.0-alpha.8",
5353
"@koa/cors": "^3.3.0",
54-
"@mikro-orm/core": "^5.1.4",
55-
"@mikro-orm/migrations": "^5.1.4",
56-
"@mikro-orm/mysql": "^5.1.4",
54+
"@mikro-orm/core": "^5.2.2",
55+
"@mikro-orm/migrations": "^5.2.2",
56+
"@mikro-orm/mysql": "^5.2.2",
5757
"@sendgrid/mail": "^7.6.2",
5858
"@sentry/node": "^6.19.6",
5959
"@sentry/tracing": "^6.19.6",
@@ -68,7 +68,7 @@
6868
"jsonwebtoken": "^8.5.1",
6969
"koa": "^2.13.4",
7070
"koa-bodyparser": "^4.3.0",
71-
"koa-clay": "^6.2.0",
71+
"koa-clay": "^6.4.0",
7272
"koa-helmet": "^6.1.0",
7373
"koa-jwt": "^4.0.3",
7474
"koa-logger": "^3.2.1",

src/config/protected-routes.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ export default (app: Koa) => {
3232
app.use(service('/billing', new BillingService(), serviceOpts))
3333
app.use(service('/organisations', new OrganisationService(), serviceOpts))
3434
app.use(service('/invites', new InviteService(), serviceOpts))
35-
app.use(service('/game-stats', new GameStatService(), serviceOpts))
36-
app.use(service('/game-activities', new GameActivityService(), serviceOpts))
37-
app.use(service('/leaderboards', new LeaderboardService(), serviceOpts))
38-
app.use(service('/data-exports', new DataExportService(), serviceOpts))
39-
app.use(service('/api-keys', new APIKeyService(), serviceOpts))
40-
app.use(service('/events', new EventService(), serviceOpts))
41-
app.use(service('/players', new PlayerService(), serviceOpts))
35+
app.use(service('/games/:gameId/game-stats', new GameStatService(), serviceOpts))
36+
app.use(service('/games/:gameId/game-activities', new GameActivityService(), serviceOpts))
37+
app.use(service('/games/:gameId/leaderboards', new LeaderboardService(), serviceOpts))
38+
app.use(service('/games/:gameId/data-exports', new DataExportService(), serviceOpts))
39+
app.use(service('/games/:gameId/api-keys', new APIKeyService(), serviceOpts))
40+
app.use(service('/games/:gameId/events', new EventService(), serviceOpts))
41+
app.use(service('/games/:gameId/players', new PlayerService(), serviceOpts))
42+
app.use(service('/games/:gameId/headlines', new HeadlineService(), serviceOpts))
4243
app.use(service('/games', new GameService(), serviceOpts))
4344
app.use(service('/users', new UserService(), serviceOpts))
44-
app.use(service('/headlines', new HeadlineService(), serviceOpts))
4545
}

src/entities/game-stat.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ export default class GameStat {
99
id: number
1010

1111
@Required({
12-
methods: ['POST'],
1312
validation: async (val: unknown, req: Request): Promise<ValidationCondition[]> => {
13+
const { gameId, id } = req.params
1414
const em: EntityManager = req.ctx.em
15-
const duplicateInternalName = await em.getRepository(GameStat).findOne({ internalName: val, game: req.body.gameId })
15+
const duplicateInternalName = await em.getRepository(GameStat).findOne({
16+
id: { $ne: Number(id ?? null) },
17+
internalName: val,
18+
game: Number(gameId)
19+
})
1620

1721
return [
1822
{
@@ -25,11 +29,11 @@ export default class GameStat {
2529
@Property()
2630
internalName: string
2731

28-
@Required({ methods: ['POST'] })
32+
@Required()
2933
@Property()
3034
name: string
3135

32-
@Required({ methods: ['POST'] })
36+
@Required()
3337
@Property()
3438
global: boolean
3539

@@ -42,7 +46,6 @@ export default class GameStat {
4246
maxChange: number
4347

4448
@Required({
45-
methods: [],
4649
validation: async (value: number, req: Request): Promise<ValidationCondition[]> => [{
4750
check: value < (req.body.maxValue ?? Infinity),
4851
error: 'minValue must be less than maxValue'
@@ -52,7 +55,6 @@ export default class GameStat {
5255
minValue: number
5356

5457
@Required({
55-
methods: [],
5658
validation: async (value: number, req: Request): Promise<ValidationCondition[]> => [{
5759
check: value > (req.body.minValue ?? -Infinity),
5860
error: 'maxValue must be greater than minValue'
@@ -62,7 +64,6 @@ export default class GameStat {
6264
maxValue: number
6365

6466
@Required({
65-
methods: ['POST'],
6667
validation: async (value: number, req: Request): Promise<ValidationCondition[]> => [{
6768
check: value >= (req.body.minValue ?? -Infinity) && value <= (req.body.maxValue ?? Infinity),
6869
error: 'defaultValue must be between minValue and maxValue'
@@ -71,14 +72,10 @@ export default class GameStat {
7172
@Property({ type: 'double' })
7273
defaultValue: number
7374

74-
@Required({ methods: ['POST'] })
75+
@Required()
7576
@Property()
7677
minTimeBetweenUpdates: number
7778

78-
@Required({
79-
methods: ['POST'],
80-
as: 'gameId'
81-
})
8279
@ManyToOne(() => Game)
8380
game: Game
8481

src/entities/leaderboard.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
1+
import { Collection, Entity, EntityManager, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
2+
import { Request, Required, ValidationCondition } from 'koa-clay'
23
import Game from './game'
34
import LeaderboardEntry from './leaderboard-entry'
45

@@ -12,15 +13,47 @@ export default class Leaderboard {
1213
@PrimaryKey()
1314
id: number
1415

16+
@Required({
17+
validation: async (val: unknown, req: Request): Promise<ValidationCondition[]> => {
18+
const { gameId, id } = req.params
19+
const em: EntityManager = req.ctx.em
20+
const duplicateInternalName = await em.getRepository(Leaderboard).findOne({
21+
id: { $ne: Number(id ?? null) },
22+
internalName: val,
23+
game: Number(gameId)
24+
})
25+
26+
return [
27+
{
28+
check: !duplicateInternalName,
29+
error: `A leaderboard with the internalName ${val} already exists`
30+
}
31+
]
32+
}
33+
})
1534
@Property()
1635
internalName: string
1736

37+
@Required()
1838
@Property()
1939
name: string
2040

41+
@Required({
42+
validation: async (val: unknown): Promise<ValidationCondition[]> => {
43+
const keys = Object.keys(LeaderboardSortMode).map((key) => LeaderboardSortMode[key])
44+
45+
return [
46+
{
47+
check: keys.includes(val),
48+
error: `Sort mode must be one of ${keys.join(', ')}`
49+
}
50+
]
51+
}
52+
})
2153
@Enum(() => LeaderboardSortMode)
2254
sortMode: LeaderboardSortMode = LeaderboardSortMode.DESC
2355

56+
@Required()
2457
@Property()
2558
unique: boolean
2659

src/policies/api-key.policy.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,12 @@ export default class APIKeyPolicy extends Policy {
99
@UserTypeGate([UserType.ADMIN], 'create API keys')
1010
@EmailConfirmedGate('create API keys')
1111
async post(req: Request): Promise<PolicyResponse> {
12-
const { gameId } = req.body
13-
14-
const canAccessGame = await this.canAccessGame(gameId)
15-
return canAccessGame
12+
const { gameId } = req.params
13+
return await this.canAccessGame(Number(gameId))
1614
}
1715

1816
async index(req: Request): Promise<boolean> {
19-
const { gameId } = req.query
17+
const { gameId } = req.params
2018
return await this.canAccessGame(Number(gameId))
2119
}
2220

src/policies/data-export.policy.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import EmailConfirmedGate from './email-confirmed-gate'
77
export default class DataExportPolicy extends Policy {
88
@UserTypeGate([UserType.ADMIN], 'view data exports')
99
async index(req: Request): Promise<PolicyResponse> {
10-
const { gameId } = req.query
10+
const { gameId } = req.params
1111
return await this.canAccessGame(Number(gameId))
1212
}
1313

1414
@UserTypeGate([UserType.ADMIN], 'create data exports')
1515
@EmailConfirmedGate('create data exports')
1616
async post(req: Request): Promise<PolicyResponse> {
17-
const { gameId } = req.body
18-
return await this.canAccessGame(gameId)
17+
const { gameId } = req.params
18+
return await this.canAccessGame(Number(gameId))
1919
}
2020
}

src/policies/event.policy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Request } from 'koa-clay'
33

44
export default class EventPolicy extends Policy {
55
async index(req: Request): Promise<boolean> {
6-
const { gameId } = req.query
6+
const { gameId } = req.params
77
return await this.canAccessGame(Number(gameId))
88
}
99
}

src/policies/game-activity.policy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import UserTypeGate from './user-type-gate'
66
export default class GameActivityPolicy extends Policy {
77
@UserTypeGate([UserType.ADMIN, UserType.DEMO], 'view game activities')
88
async index(req: Request): Promise<PolicyResponse> {
9-
const { gameId } = req.query
9+
const { gameId } = req.params
1010
return await this.canAccessGame(Number(gameId))
1111
}
1212
}

src/policies/game-stat.policy.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import UserTypeGate from './user-type-gate'
66

77
export default class GameStatPolicy extends Policy {
88
async index(req: Request): Promise<PolicyResponse> {
9-
const { gameId } = req.query
9+
const { gameId } = req.params
1010
return await this.canAccessGame(Number(gameId))
1111
}
1212

1313
@UserTypeGate([UserType.ADMIN, UserType.DEV], 'create stats')
1414
async post(req: Request): Promise<PolicyResponse> {
15-
const { gameId } = req.body
16-
return await this.canAccessGame(gameId)
15+
const { gameId } = req.params
16+
return await this.canAccessGame(Number(gameId))
1717
}
1818

1919
async getStat(id: number): Promise<GameStat> {
@@ -22,7 +22,7 @@ export default class GameStatPolicy extends Policy {
2222
return stat
2323
}
2424

25-
async patch(req: Request): Promise<PolicyResponse> {
25+
async put(req: Request): Promise<PolicyResponse> {
2626
const { id } = req.params
2727

2828
const stat = await this.getStat(Number(id))

0 commit comments

Comments
 (0)