Skip to content

Commit 440a7b5

Browse files
authored
Merge pull request #71 from TaloDev/develop
Release 0.7.0
2 parents fc1ad84 + c2fcc07 commit 440a7b5

File tree

10 files changed

+64
-117
lines changed

10 files changed

+64
-117
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "game-services",
3-
"version": "0.6.2",
3+
"version": "0.7.0",
44
"description": "",
55
"main": "src/index.ts",
66
"scripts": {

src/policies/api/leaderboard-api.policy.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,14 @@ export default class LeaderboardAPIPolicy extends Policy {
1818
return leaderboard
1919
}
2020

21-
async get(): Promise<PolicyResponse> {
22-
return await this.hasScope('read:leaderboards')
21+
async get(req: Request): Promise<PolicyResponse> {
22+
const scopeCheck = await this.hasScope('read:leaderboards')
23+
if (scopeCheck !== true) return scopeCheck
24+
25+
const leaderboard = await this.getLeaderboard(req)
26+
if (!leaderboard) return new PolicyDenial({ message: 'Leaderboard not found' }, 404)
27+
28+
return await true
2329
}
2430

2531
async post(req: Request): Promise<PolicyResponse> {

src/policies/leaderboard.policy.ts

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,10 @@ export default class LeaderboardPolicy extends Policy {
99
return await this.canAccessGame(Number(gameId))
1010
}
1111

12-
async get(req: Request): Promise<PolicyResponse> {
13-
const { internalName } = req.params
14-
const { gameId } = req.query
15-
16-
// get and entries endpoints share this policy
17-
const relations = req.path.endsWith('entries') ? ['entries'] : []
12+
async canAccessLeaderboard(req: Request, relations: string[] = []): Promise<PolicyResponse> {
13+
const { id } = req.params
1814

19-
const leaderboard = await this.em.getRepository(Leaderboard).findOne({
20-
internalName,
21-
game: Number(gameId)
22-
}, {
15+
const leaderboard = await this.em.getRepository(Leaderboard).findOne(Number(id), {
2316
populate: relations as never[]
2417
})
2518

@@ -28,7 +21,11 @@ export default class LeaderboardPolicy extends Policy {
2821
this.ctx.state.leaderboard = leaderboard
2922

3023
if (this.isAPICall()) return true
31-
return await this.canAccessGame(Number(gameId))
24+
return await this.canAccessGame(leaderboard.game.id)
25+
}
26+
27+
async get(req: Request): Promise<PolicyResponse> {
28+
return await this.canAccessLeaderboard(req)
3229
}
3330

3431
async post(req: Request): Promise<PolicyResponse> {
@@ -41,32 +38,17 @@ export default class LeaderboardPolicy extends Policy {
4138
}
4239

4340
async updateEntry(req: Request): Promise<PolicyResponse> {
44-
return await this.get({
45-
...req,
46-
query: {
47-
gameId: req.body.gameId
48-
}
49-
})
41+
return await this.canAccessLeaderboard(req, ['entries'])
5042
}
5143

5244
async updateLeaderboard(req: Request): Promise<PolicyResponse> {
53-
return await this.get({
54-
...req,
55-
query: {
56-
gameId: req.body.gameId
57-
}
58-
})
45+
return await this.canAccessLeaderboard(req)
5946
}
6047

6148
async delete(req: Request): Promise<PolicyResponse> {
6249
const user = await this.getUser()
6350
if (user.type !== UserType.ADMIN) return new PolicyDenial({ message: 'You do not have permissions to delete leaderboards' })
6451

65-
return await this.get({
66-
...req,
67-
query: {
68-
gameId: req.body.gameId
69-
}
70-
})
52+
return await this.canAccessLeaderboard(req)
7153
}
7254
}

src/services/api/leaderboard-api.service.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ export default class LeaderboardAPIService extends APIService<LeaderboardService
2323

2424
@HasPermission(LeaderboardAPIPolicy, 'get')
2525
async get(req: Request): Promise<Response> {
26-
const key = await this.getAPIKey(req.ctx)
2726
return this.forwardRequest('entries', req, {
28-
query: {
29-
gameId: key.game.id.toString()
27+
params: {
28+
id: String(req.ctx.state.leaderboard.id)
3029
}
3130
})
3231
}

src/services/leaderboard.service.ts

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import LeaderboardPolicy from '../policies/leaderboard.policy'
99
@Routes([
1010
{
1111
method: 'GET',
12-
path: '/:internalName',
12+
path: '/:id',
1313
handler: 'get'
1414
},
1515
{
@@ -21,22 +21,22 @@ import LeaderboardPolicy from '../policies/leaderboard.policy'
2121
},
2222
{
2323
method: 'GET',
24-
path: '/:internalName/entries',
24+
path: '/:id/entries',
2525
handler: 'entries'
2626
},
2727
{
2828
method: 'PATCH',
29-
path: '/:internalName/entries/:id',
29+
path: '/:id/entries/:entryId',
3030
handler: 'updateEntry'
3131
},
3232
{
3333
method: 'PATCH',
34-
path: '/:internalName',
34+
path: '/:id',
3535
handler: 'updateLeaderboard'
3636
},
3737
{
3838
method: 'DELETE',
39-
path: '/:internalName'
39+
path: '/:id'
4040
}
4141
])
4242
export default class LeaderboardService implements Service {
@@ -57,9 +57,6 @@ export default class LeaderboardService implements Service {
5757
}
5858
}
5959

60-
@Validate({
61-
query: ['gameId']
62-
})
6360
@HasPermission(LeaderboardPolicy, 'get')
6461
async get(req: Request): Promise<Response> {
6562
return {
@@ -141,7 +138,7 @@ export default class LeaderboardService implements Service {
141138
}
142139

143140
@Validate({
144-
query: ['gameId', 'page']
141+
query: ['page']
145142
})
146143
@HasPermission(LeaderboardPolicy, 'get')
147144
async entries(req: Request): Promise<Response> {
@@ -174,6 +171,8 @@ export default class LeaderboardService implements Service {
174171
.offset(Number(page) * itemsPerPage)
175172
.getResultList()
176173

174+
await em.populate(entries, ['playerAlias'])
175+
177176
return {
178177
status: 200,
179178
body: {
@@ -183,15 +182,12 @@ export default class LeaderboardService implements Service {
183182
}
184183
}
185184

186-
@Validate({
187-
body: ['gameId']
188-
})
189185
@HasPermission(LeaderboardPolicy, 'updateEntry')
190186
async updateEntry(req: Request): Promise<Response> {
191-
const { id } = req.params
187+
const { entryId } = req.params
192188
const em: EntityManager = req.ctx.em
193189

194-
const entry = await em.getRepository(LeaderboardEntry).findOne(Number(id))
190+
const entry = await em.getRepository(LeaderboardEntry).findOne(Number(entryId))
195191
if (!entry) {
196192
req.ctx.throw(404, 'Leaderboard entry not found')
197193
}
@@ -227,9 +223,6 @@ export default class LeaderboardService implements Service {
227223
}
228224
}
229225

230-
@Validate({
231-
body: ['gameId']
232-
})
233226
@HasPermission(LeaderboardPolicy, 'updateLeaderboard')
234227
async updateLeaderboard(req: Request): Promise<Response> {
235228
const em: EntityManager = req.ctx.em
@@ -263,9 +256,6 @@ export default class LeaderboardService implements Service {
263256
}
264257
}
265258

266-
@Validate({
267-
body: ['gameId']
268-
})
269259
@HasPermission(LeaderboardPolicy, 'delete')
270260
async delete(req: Request): Promise<Response> {
271261
const em: EntityManager = req.ctx.em

tests/services/leaderboard/delete.test.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ describe('Leaderboard service - delete', () => {
3838
await (<EntityManager>app.context.em).persistAndFlush(leaderboard)
3939

4040
await request(app.callback())
41-
.delete(`${baseUrl}/${leaderboard.internalName}`)
42-
.send({ gameId: validGame.id })
41+
.delete(`${baseUrl}/${leaderboard.id}`)
4342
.auth(token, { type: 'bearer' })
4443
.expect(204)
4544

@@ -61,8 +60,7 @@ describe('Leaderboard service - delete', () => {
6160
const invalidUserToken = await genAccessToken(invalidUser)
6261

6362
const res = await request(app.callback())
64-
.delete(`${baseUrl}/${leaderboard.internalName}`)
65-
.send({ gameId: validGame.id })
63+
.delete(`${baseUrl}/${leaderboard.id}`)
6664
.auth(invalidUserToken, { type: 'bearer' })
6765
.expect(403)
6866

@@ -77,8 +75,7 @@ describe('Leaderboard service - delete', () => {
7775
const invalidUserToken = await genAccessToken(invalidUser)
7876

7977
const res = await request(app.callback())
80-
.delete(`${baseUrl}/${leaderboard.internalName}`)
81-
.send({ gameId: validGame.id })
78+
.delete(`${baseUrl}/${leaderboard.id}`)
8279
.auth(invalidUserToken, { type: 'bearer' })
8380
.expect(403)
8481

@@ -92,16 +89,14 @@ describe('Leaderboard service - delete', () => {
9289
await (<EntityManager>app.context.em).persistAndFlush([otherOrg, otherGame, leaderboard])
9390

9491
await request(app.callback())
95-
.delete(`${baseUrl}/${leaderboard.internalName}`)
96-
.send({ gameId: otherGame.id })
92+
.delete(`${baseUrl}/${leaderboard.id}`)
9793
.auth(token, { type: 'bearer' })
9894
.expect(403)
9995
})
10096

10197
it('should not delete a non-existent leaderboard', async () => {
10298
const res = await request(app.callback())
103-
.delete(`${baseUrl}/blah`)
104-
.send({ gameId: 99 })
99+
.delete(`${baseUrl}/31223`)
105100
.auth(token, { type: 'bearer' })
106101
.expect(404)
107102

tests/services/leaderboard/entries.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ describe('Leaderboard service - entries', () => {
3939
await (<EntityManager>app.context.em).persistAndFlush(leaderboard)
4040

4141
const res = await request(app.callback())
42-
.get(`${baseUrl}/${leaderboard.internalName}/entries`)
43-
.query({ gameId: validGame.id, page: 0 })
42+
.get(`${baseUrl}/${leaderboard.id}/entries`)
43+
.query({ page: 0 })
4444
.auth(token, { type: 'bearer' })
4545
.expect(200)
4646

@@ -49,8 +49,8 @@ describe('Leaderboard service - entries', () => {
4949

5050
it('should not return entries for a non-existent leaderboard', async () => {
5151
const res = await request(app.callback())
52-
.get(`${baseUrl}/blah/entries`)
53-
.query({ gameId: 99, page: 0 })
52+
.get(`${baseUrl}/21312312/entries`)
53+
.query({ page: 0 })
5454
.auth(token, { type: 'bearer' })
5555
.expect(404)
5656

@@ -64,8 +64,8 @@ describe('Leaderboard service - entries', () => {
6464
await (<EntityManager>app.context.em).persistAndFlush(leaderboard)
6565

6666
await request(app.callback())
67-
.get(`${baseUrl}/${leaderboard.internalName}/entries`)
68-
.query({ gameId: otherGame.id, page: 0 })
67+
.get(`${baseUrl}/${leaderboard.id}/entries`)
68+
.query({ page: 0 })
6969
.auth(token, { type: 'bearer' })
7070
.expect(403)
7171
})

tests/services/leaderboard/get.test.ts

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ describe('Leaderboard service - get', () => {
3737
await (<EntityManager>app.context.em).persistAndFlush(leaderboard)
3838

3939
const res = await request(app.callback())
40-
.get(`${baseUrl}/${leaderboard.internalName}`)
41-
.query({ gameId: validGame.id })
40+
.get(`${baseUrl}/${leaderboard.id}`)
4241
.auth(token, { type: 'bearer' })
4342
.expect(200)
4443

@@ -47,8 +46,7 @@ describe('Leaderboard service - get', () => {
4746

4847
it('should not return a non-existent leaderboard', async () => {
4948
const res = await request(app.callback())
50-
.get(`${baseUrl}/blah`)
51-
.query({ gameId: 99 })
49+
.get(`${baseUrl}/321312`)
5250
.auth(token, { type: 'bearer' })
5351
.expect(404)
5452

@@ -62,30 +60,7 @@ describe('Leaderboard service - get', () => {
6260
await (<EntityManager>app.context.em).persistAndFlush(leaderboard)
6361

6462
await request(app.callback())
65-
.get(`${baseUrl}/${leaderboard.internalName}`)
66-
.query({ gameId: otherGame.id })
67-
.auth(token, { type: 'bearer' })
68-
.expect(403)
69-
})
70-
71-
it('should not return a leaderboard with the same name as a valid leaderboard for a game the user has no access to', async () => {
72-
const otherOrg = await new OrganisationFactory().one()
73-
const otherGame = await new GameFactory(otherOrg).one()
74-
const validLeaderboard = await new LeaderboardFactory([validGame]).with(() => ({ internalName: 'points' })).one()
75-
const otherLeaderboard = await new LeaderboardFactory([otherGame]).with(() => ({ internalName: 'points' })).one()
76-
await (<EntityManager>app.context.em).persistAndFlush([validLeaderboard, otherLeaderboard])
77-
78-
const res = await request(app.callback())
79-
.get(`${baseUrl}/${validLeaderboard.internalName}`)
80-
.query({ gameId: validGame.id })
81-
.auth(token, { type: 'bearer' })
82-
.expect(200)
83-
84-
expect(res.body.leaderboard.id).toBe(validLeaderboard.id)
85-
86-
await request(app.callback())
87-
.get(`${baseUrl}/${validLeaderboard.internalName}`)
88-
.query({ gameId: otherGame.id })
63+
.get(`${baseUrl}/${leaderboard.id}`)
8964
.auth(token, { type: 'bearer' })
9065
.expect(403)
9166
})

tests/services/leaderboard/updateEntry.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ describe('Leaderboard service - update entry', () => {
4646
await (<EntityManager>app.context.em).persistAndFlush(entry)
4747

4848
const res = await request(app.callback())
49-
.patch(`${baseUrl}/${leaderboard.internalName}/entries/${entry.id}`)
50-
.send({ gameId: validGame.id, hidden: true })
49+
.patch(`${baseUrl}/${leaderboard.id}/entries/${entry.id}`)
50+
.send({ hidden: true })
5151
.auth(token, { type: 'bearer' })
5252
.expect(200)
5353

@@ -72,8 +72,8 @@ describe('Leaderboard service - update entry', () => {
7272
await (<EntityManager>app.context.em).persistAndFlush(entry)
7373

7474
const res = await request(app.callback())
75-
.patch(`${baseUrl}/${leaderboard.internalName}/entries/${entry.id}`)
76-
.send({ gameId: validGame.id, hidden: false })
75+
.patch(`${baseUrl}/${leaderboard.id}/entries/${entry.id}`)
76+
.send({ hidden: false })
7777
.auth(token, { type: 'bearer' })
7878
.expect(200)
7979

@@ -98,8 +98,8 @@ describe('Leaderboard service - update entry', () => {
9898
await (<EntityManager>app.context.em).persistAndFlush(entry)
9999

100100
const res = await request(app.callback())
101-
.patch(`${baseUrl}/${leaderboard.internalName}/entries/${entry.id}`)
102-
.send({ gameId: validGame.id })
101+
.patch(`${baseUrl}/${leaderboard.id}/entries/${entry.id}`)
102+
.send({})
103103
.auth(token, { type: 'bearer' })
104104
.expect(200)
105105

@@ -121,8 +121,8 @@ describe('Leaderboard service - update entry', () => {
121121

122122
it('should not update a non-existent entry', async () => {
123123
const res = await request(app.callback())
124-
.patch(`${baseUrl}/${leaderboard.internalName}/entries/12312321`)
125-
.send({ gameId: validGame.id, hidden: true })
124+
.patch(`${baseUrl}/${leaderboard.id}/entries/12312321`)
125+
.send({ hidden: true })
126126
.auth(token, { type: 'bearer' })
127127
.expect(404)
128128

0 commit comments

Comments
 (0)