Skip to content

Commit

Permalink
channel subscriptions, editing, deleting
Browse files Browse the repository at this point in the history
  • Loading branch information
tudddorrr committed Dec 9, 2024
1 parent 90cb4b9 commit 34bafbf
Show file tree
Hide file tree
Showing 8 changed files with 504 additions and 54 deletions.
240 changes: 240 additions & 0 deletions src/docs/game-channel-api.docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
import GameChannelAPIService from '../services/api/game-channel-api.service'
import APIDocs from './api-docs'

const GameChannelAPIDocs: APIDocs<GameChannelAPIService> = {
index: {
description: 'List game channels',
samples: [
{
title: 'Sample response',
sample: {
channels: [
{
id: 1,
name: 'general-chat',
owner: null,
props: [
{ key: 'channelType', value: 'public' }
],
createdAt: '2024-12-09T12:00:00Z',
updatedAt: '2024-12-09T12:00:00Z'
},
{
id: 2,
name: 'guild-chat',
owner: {
id: 1,
service: 'username',
identifier: 'guild_admin_bob',
player: {
id: '7a4e70ec-6ee6-418e-923d-b3a45051b7f9',
props: [
{ key: 'currentLevel', value: '58' },
{ key: 'xPos', value: '13.29' },
{ key: 'yPos', value: '26.44' },
{ key: 'zoneId', value: '3' }
],
aliases: [
'/* [Circular] */'
],
devBuild: false,
createdAt: '2022-01-15T13:20:32.133Z',
lastSeenAt: '2022-04-12T15:09:43.066Z',
groups: [
{ id: '5826ca71-1964-4a1b-abcb-a61ffbe003be', name: 'Winners' }
]
}
},
props: [
{ key: 'channelType', value: 'guild' },
{ key: 'guildId', value: '5912' }
],
createdAt: '2024-12-09T12:00:00Z',
updatedAt: '2024-12-09T12:00:00Z'
}
]
}
}
]
},
post: {
description: 'Create a game channel',
params: {
headers: {
'x-talo-alias': 'The ID of the player\'s alias'
},
body: {
name: 'The name of the channel',
props: 'An array of @type(Props:prop)'
}
},
samples: [
{
title: 'Sample request',
sample: {
name: 'general-chat',
props: [
{ key: 'channelType', value: 'public' }
]
}
},
{
title: 'Sample response',
sample: {
channel: {
id: 1,
name: 'general-chat',
owner: {
id: 1,
service: 'username',
identifier: 'guild_admin_bob',
player: {
id: '7a4e70ec-6ee6-418e-923d-b3a45051b7f9',
props: [
{ key: 'currentLevel', value: '58' },
{ key: 'xPos', value: '13.29' },
{ key: 'yPos', value: '26.44' },
{ key: 'zoneId', value: '3' }
],
aliases: [
'/* [Circular] */'
],
devBuild: false,
createdAt: '2022-01-15T13:20:32.133Z',
lastSeenAt: '2022-04-12T15:09:43.066Z',
groups: [
{ id: '5826ca71-1964-4a1b-abcb-a61ffbe003be', name: 'Winners' }
]
}
},
props: [
{ key: 'channelType', value: 'public' }
],
createdAt: '2024-12-09T12:00:00Z',
updatedAt: '2024-12-09T12:00:00Z'
}
}
}
]
},
join: {
description: 'Join a game channel',
params: {
headers: {
'x-talo-alias': 'The ID of the player\'s alias'
},
route: {
id: 'The ID of the channel'
}
},
samples: [
{
title: 'Sample request',
sample: {
name: 'general-chat'
}
},
{
title: 'Sample response',
sample: {
channel: {
id: 1,
name: 'general-chat',
owner: null,
props: [
{ key: 'channelType', value: 'public' }
],
createdAt: '2024-12-09T12:00:00Z',
updatedAt: '2024-12-09T12:00:00Z'
}
}
}
]
},
leave: {
description: 'Leave a game channel',
params: {
headers: {
'x-talo-alias': 'The ID of the player\'s alias'
},
route: {
id: 'The ID of the channel'
}
}
},
put: {
description: 'Update a game channel',
params: {
headers: {
'x-talo-alias': 'The ID of the player\'s alias'
},
body: {
name: 'The new name of the channel',
props: 'An array of @type(Props:prop)',
ownerAliasId: 'The ID of the new owner of the channel'
},
route: {
id: 'The ID of the channel'
}
},
samples: [
{
title: 'Sample request',
sample: {
name: 'new-general-chat',
props: [
{ key: 'channelType', value: 'public' },
{ key: 'recentlyUpdated', value: 'true' }
],
ownerAliasId: 2
}
},
{
title: 'Sample response',
sample: {
channel: {
id: 1,
name: 'new-general-chat',
owner: {
id: 2,
service: 'username',
identifier: 'new_admin_john',
player: {
id: '7a4e70ec-6ee6-418e-923d-b3a45051b7f9',
props: [],
aliases: [
'/* [Circular] */'
],
devBuild: false,
createdAt: '2022-01-15T13:20:32.133Z',
lastSeenAt: '2022-04-12T15:09:43.066Z',
groups: [
{ id: '5826ca71-1964-4a1b-abcb-a61ffbe003be', name: 'Winners' }
]
}
},
props: [
{ key: 'channelType', value: 'public' },
{ key: 'recentlyUpdated', value: 'true' }
],
createdAt: '2024-12-09T12:00:00Z',
updatedAt: '2024-12-09T12:01:00Z'
}
}
}
]
},
delete: {
description: 'Delete a game channel',
params: {
headers: {
'x-talo-alias': 'The ID of the player\'s alias'
},
route: {
id: 'The ID of the channel'
}
}
}
}

export default GameChannelAPIDocs
3 changes: 3 additions & 0 deletions src/docs/player-api.docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const PlayerAPIDocs: APIDocs<PlayerAPIService> = {
identify: {
description: 'Identify a player',
params: {
headers: {
'x-talo-session': 'The session token (required if using Talo player authentication)'
},
query: {
service: 'The name of the service where the identity of the player comes from (e.g. "steam", "epic" or "username")',
identifier: 'The unique identifier of the player. This can be their username, an email or a numeric ID'
Expand Down
10 changes: 9 additions & 1 deletion src/entities/game-channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,19 @@ export default class GameChannel {
@Property()
name: string

@ManyToOne(() => PlayerAlias, { nullable: false, cascade: [Cascade.REMOVE] })
@ManyToOne(() => PlayerAlias, { cascade: [Cascade.REMOVE] })
owner: PlayerAlias

@ManyToMany(() => PlayerAlias, (alias) => alias.channels, { owner: true })
members = new Collection<PlayerAlias>(this)

@Property()
totalMessages: number = 0

@Required()
@Property()
autoCleanup: boolean = false

@ManyToOne(() => Game)
game: Game

Expand All @@ -56,6 +63,7 @@ export default class GameChannel {
id: this.id,
name: this.name,
owner: this.owner,
totalMessages: this.totalMessages,
props: this.props,
createdAt: this.createdAt,
updatedAt: this.updatedAt
Expand Down
22 changes: 22 additions & 0 deletions src/migrations/.snapshot-gs_dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -2496,10 +2496,32 @@
"unsigned": true,
"autoincrement": false,
"primary": false,
"nullable": true,
"length": null,
"mappedType": "integer"
},
"total_messages": {
"name": "total_messages",
"type": "int",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": null,
"default": "0",
"mappedType": "integer"
},
"auto_cleanup": {
"name": "auto_cleanup",
"type": "tinyint(1)",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": 1,
"default": "false",
"mappedType": "boolean"
},
"game_id": {
"name": "game_id",
"type": "int",
Expand Down
2 changes: 1 addition & 1 deletion src/migrations/20241206233511CreateGameChannelTables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Migration } from '@mikro-orm/migrations'
export class CreateGameChannelTables extends Migration {

override async up(): Promise<void> {
this.addSql('create table `game_channel` (`id` int unsigned not null auto_increment primary key, `name` varchar(255) not null, `owner_id` int unsigned not null, `game_id` int unsigned not null, `props` json not null, `created_at` datetime not null, `updated_at` datetime not null) default character set utf8mb4 engine = InnoDB;')
this.addSql('create table `game_channel` (`id` int unsigned not null auto_increment primary key, `name` varchar(255) not null, `owner_id` int unsigned null, `game_id` int unsigned not null, `total_messages` int not null default 0, `auto_cleanup` tinyint(1) not null default false, `props` json not null, `created_at` datetime not null, `updated_at` datetime not null) default character set utf8mb4 engine = InnoDB;')
this.addSql('alter table `game_channel` add index `game_channel_owner_id_index`(`owner_id`);')
this.addSql('alter table `game_channel` add index `game_channel_game_id_index`(`game_id`);')

Expand Down
46 changes: 44 additions & 2 deletions src/policies/api/game-channel-api.policy.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,63 @@
import Policy from '../policy'
import { PolicyResponse } from 'koa-clay'
import { PolicyDenial, PolicyResponse } from 'koa-clay'
import { APIKeyScope } from '../../entities/api-key'
import PlayerAlias from '../../entities/player-alias'
import { EntityManager } from '@mikro-orm/mysql'

export default class GameChannelAPIPolicy extends Policy {
async getAlias(): Promise<PlayerAlias | null> {
const em: EntityManager = this.ctx.em
return await em.getRepository(PlayerAlias).findOne({
id: this.ctx.state.currentAliasId,
player: {
game: this.ctx.state.game
}
})
}

async index(): Promise<PolicyResponse> {
return await this.hasScope(APIKeyScope.READ_GAME_CHANNELS)
}

async subscriptions(): Promise<PolicyResponse> {
this.ctx.state.alias = await this.getAlias()
if (!this.ctx.state.alias) return new PolicyDenial({ message: 'Player not found' }, 404)

return await this.hasScope(APIKeyScope.READ_GAME_CHANNELS)
}

async post(): Promise<PolicyResponse> {
this.ctx.state.alias = await this.getAlias()
if (!this.ctx.state.alias) return new PolicyDenial({ message: 'Player not found' }, 404)

return await this.hasScope(APIKeyScope.WRITE_GAME_CHANNELS)
}

async join(): Promise<PolicyResponse> {
return await this.hasScope(APIKeyScope.READ_GAME_CHANNELS)
this.ctx.state.alias = await this.getAlias()
if (!this.ctx.state.alias) return new PolicyDenial({ message: 'Player not found' }, 404)

return await this.hasScope(APIKeyScope.WRITE_GAME_CHANNELS)
}

async leave(): Promise<PolicyResponse> {
this.ctx.state.alias = await this.getAlias()
if (!this.ctx.state.alias) return new PolicyDenial({ message: 'Player not found' }, 404)

return await this.hasScope(APIKeyScope.WRITE_GAME_CHANNELS)
}

async put(): Promise<PolicyResponse> {
this.ctx.state.alias = await this.getAlias()
if (!this.ctx.state.alias) return new PolicyDenial({ message: 'Player not found' }, 404)

return await this.hasScope(APIKeyScope.WRITE_GAME_CHANNELS)
}

async delete(): Promise<PolicyResponse> {
this.ctx.state.alias = await this.getAlias()
if (!this.ctx.state.alias) return new PolicyDenial({ message: 'Player not found' }, 404)

return await this.hasScope(APIKeyScope.WRITE_GAME_CHANNELS)
}
}
Loading

0 comments on commit 34bafbf

Please sign in to comment.