diff --git a/packages/app-api/src/controllers/DomainController.ts b/packages/app-api/src/controllers/DomainController.ts index 2f3141f9f7..affb053755 100644 --- a/packages/app-api/src/controllers/DomainController.ts +++ b/packages/app-api/src/controllers/DomainController.ts @@ -44,6 +44,10 @@ export class DomainSearchInputAllowedFilters { @IsOptional() @IsEnum(Object.values(DOMAIN_STATES), { each: true }) state!: DOMAIN_STATES[]; + + @IsOptional() + @IsString({ each: true }) + externalReference!: string[]; } export class DomainSearchInputDTO extends ITakaroQuery { diff --git a/packages/app-api/src/controllers/PlayerController.ts b/packages/app-api/src/controllers/PlayerController.ts index e1a9273ab7..a0872a5a27 100644 --- a/packages/app-api/src/controllers/PlayerController.ts +++ b/packages/app-api/src/controllers/PlayerController.ts @@ -147,15 +147,7 @@ export class PlayerController { ) { const service = new PlayerService(req.domainId); - try { - await service.assignRole(params.roleId, params.id, data.gameServerId, data.expiresAt); - } catch (error) { - if (error instanceof Error && error.name === 'UniqueViolationError') { - throw new errors.BadRequestError('Role already assigned'); - } else { - throw error; - } - } + await service.assignRole(params.roleId, params.id, data.gameServerId, data.expiresAt); return apiResponse(); } diff --git a/packages/app-api/src/controllers/__tests__/PlayerController.integration.test.ts b/packages/app-api/src/controllers/__tests__/PlayerController.integration.test.ts index 3caec09b2e..c98d33bdd4 100644 --- a/packages/app-api/src/controllers/__tests__/PlayerController.integration.test.ts +++ b/packages/app-api/src/controllers/__tests__/PlayerController.integration.test.ts @@ -20,23 +20,6 @@ const tests = [ return this.client.player.playerControllerAssignRole(player.id, role.data.data.id); }, }), - new IntegrationTest({ - group, - snapshot: true, - name: 'Assigning the same role twice should fail', - setup: SetupGameServerPlayers.setup, - test: async function () { - const permissions = await this.client.permissionCodesToInputs([PERMISSIONS.MANAGE_GAMESERVERS]); - const role = await this.client.role.roleControllerCreate({ - name: 'Test role', - permissions, - }); - const player = this.setupData.players[0]; - await this.client.player.playerControllerAssignRole(player.id, role.data.data.id); - return this.client.player.playerControllerAssignRole(player.id, role.data.data.id); - }, - expectedStatus: 400, - }), new IntegrationTest({ group, snapshot: true, @@ -58,27 +41,6 @@ const tests = [ }); }, }), - new IntegrationTest({ - group, - snapshot: true, - name: 'Assigning the same role for same gameserver should fail', - setup: SetupGameServerPlayers.setup, - test: async function () { - const permissions = await this.client.permissionCodesToInputs([PERMISSIONS.MANAGE_GAMESERVERS]); - const role = await this.client.role.roleControllerCreate({ - name: 'Test role', - permissions, - }); - const player = this.setupData.players[0]; - await this.client.player.playerControllerAssignRole(player.id, role.data.data.id, { - gameServerId: this.setupData.gameServer1.id, - }); - return this.client.player.playerControllerAssignRole(player.id, role.data.data.id, { - gameServerId: this.setupData.gameServer1.id, - }); - }, - expectedStatus: 400, - }), new IntegrationTest({ group, snapshot: true, @@ -202,6 +164,53 @@ const tests = [ }, filteredFields: ['name', 'playerId', 'steamId', 'roleId', 'gameServerId', 'epicOnlineServicesId', 'xboxLiveId'], }), + new IntegrationTest({ + group, + snapshot: true, + name: 'Can override the expiry of a role assignment', + setup: SetupGameServerPlayers.setup, + test: async function () { + // Assign a role with expiry + // Assign same role with new expiry + // -> Role should have new expiry + + const permissions = await this.client.permissionCodesToInputs([PERMISSIONS.MANAGE_GAMESERVERS]); + + const role = await this.client.role.roleControllerCreate({ + name: 'Test role', + permissions, + }); + + const player = this.setupData.players[0]; + const expiresAt = new Date(Date.now() - 10).toISOString(); + const newExpiresAt = new Date(Date.now() + 1000 * 60 * 60).toISOString(); + + await this.client.player.playerControllerAssignRole(player.id, role.data.data.id, { + expiresAt, + }); + + await this.client.player.playerControllerAssignRole(player.id, role.data.data.id, { + expiresAt: newExpiresAt, + }); + + const res = await this.client.player.playerControllerGetOne(player.id); + const roleAssignment = res.data.data.roleAssignments.find((a) => a.role.name === role.data.data.name); + if (!roleAssignment) throw new Error('Role assignment not found'); + + expect(roleAssignment.expiresAt).to.be.eq(newExpiresAt); + return res; + }, + filteredFields: [ + 'name', + 'playerId', + 'steamId', + 'roleId', + 'gameServerId', + 'epicOnlineServicesId', + 'xboxLiveId', + 'expiresAt', + ], + }), ]; describe(group, function () { diff --git a/packages/app-api/src/db/player.ts b/packages/app-api/src/db/player.ts index 4a0034adb2..0be44d8d79 100644 --- a/packages/app-api/src/db/player.ts +++ b/packages/app-api/src/db/player.ts @@ -235,7 +235,20 @@ export class PlayerRepo extends ITakaroRepo = { + playerId, + roleId, + }; + + if (gameServerId) whereObj.gameServerId = gameServerId; + + const existing = await roleOnPlayerModel.query().findOne(whereObj); + + if (existing) { + await roleOnPlayerModel.query().update(updateObj).where(whereObj); + } else { + await roleOnPlayerModel.query().insert(updateObj); + } } async removeRole(playerId: string, roleId: string, gameServerId?: string): Promise { diff --git a/packages/lib-apiclient/src/generated/api.ts b/packages/lib-apiclient/src/generated/api.ts index e81105d441..cdc0dfea19 100644 --- a/packages/lib-apiclient/src/generated/api.ts +++ b/packages/lib-apiclient/src/generated/api.ts @@ -1,11 +1,11 @@ /* tslint:disable */ /* eslint-disable */ /** - * + * Takaro API * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) * - * The version of the OpenAPI document: 1.0.0 - * + * The version of the OpenAPI document: unset-unset-unset + * Contact: support@takaro.io * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * https://openapi-generator.tech @@ -6148,6 +6148,12 @@ export interface PlayerOutputDTO { * @memberof PlayerOutputDTO */ steamNumberOfVACBans?: number; + /** + * + * @type {number} + * @memberof PlayerOutputDTO + */ + steamLevel?: number; /** * * @type {Array} @@ -6294,6 +6300,12 @@ export interface PlayerOutputWithRolesDTO { * @memberof PlayerOutputWithRolesDTO */ steamNumberOfVACBans?: number; + /** + * + * @type {number} + * @memberof PlayerOutputWithRolesDTO + */ + steamLevel?: number; /** * * @type {Array} @@ -7891,10 +7903,10 @@ export interface TakaroEventCommandExecuted { data: any; /** * - * @type {Array} + * @type {TakaroEventFunctionResult} * @memberof TakaroEventCommandExecuted */ - result: Array; + result: TakaroEventFunctionResult; /** * * @type {TakaroEventCommandDetails} @@ -7941,10 +7953,10 @@ export interface TakaroEventCronjobExecuted { data: any; /** * - * @type {Array} + * @type {TakaroEventFunctionResult} * @memberof TakaroEventCronjobExecuted */ - result: Array; + result: TakaroEventFunctionResult; /** * * @type {TakaroEventCronjobDetails} @@ -8079,10 +8091,10 @@ export interface TakaroEventHookExecuted { data: any; /** * - * @type {Array} + * @type {TakaroEventFunctionResult} * @memberof TakaroEventHookExecuted */ - result: Array; + result: TakaroEventFunctionResult; /** * * @type {TakaroEventHookDetails} diff --git a/packages/lib-apiclient/src/generated/base.ts b/packages/lib-apiclient/src/generated/base.ts index 577d7cf2a5..af913f3b0f 100644 --- a/packages/lib-apiclient/src/generated/base.ts +++ b/packages/lib-apiclient/src/generated/base.ts @@ -1,11 +1,11 @@ /* tslint:disable */ /* eslint-disable */ /** - * + * Takaro API * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) * - * The version of the OpenAPI document: 1.0.0 - * + * The version of the OpenAPI document: unset-unset-unset + * Contact: support@takaro.io * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * https://openapi-generator.tech diff --git a/packages/lib-apiclient/src/generated/common.ts b/packages/lib-apiclient/src/generated/common.ts index d1ecf5be82..d09d908ff9 100644 --- a/packages/lib-apiclient/src/generated/common.ts +++ b/packages/lib-apiclient/src/generated/common.ts @@ -1,11 +1,11 @@ /* tslint:disable */ /* eslint-disable */ /** - * + * Takaro API * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) * - * The version of the OpenAPI document: 1.0.0 - * + * The version of the OpenAPI document: unset-unset-unset + * Contact: support@takaro.io * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * https://openapi-generator.tech diff --git a/packages/lib-apiclient/src/generated/configuration.ts b/packages/lib-apiclient/src/generated/configuration.ts index 5c372f629a..13d3eeae31 100644 --- a/packages/lib-apiclient/src/generated/configuration.ts +++ b/packages/lib-apiclient/src/generated/configuration.ts @@ -1,11 +1,11 @@ /* tslint:disable */ /* eslint-disable */ /** - * + * Takaro API * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) * - * The version of the OpenAPI document: 1.0.0 - * + * The version of the OpenAPI document: unset-unset-unset + * Contact: support@takaro.io * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * https://openapi-generator.tech diff --git a/packages/lib-apiclient/src/generated/index.ts b/packages/lib-apiclient/src/generated/index.ts index 54fc5e82a3..10c8d6dfc3 100644 --- a/packages/lib-apiclient/src/generated/index.ts +++ b/packages/lib-apiclient/src/generated/index.ts @@ -1,11 +1,11 @@ /* tslint:disable */ /* eslint-disable */ /** - * + * Takaro API * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) * - * The version of the OpenAPI document: 1.0.0 - * + * The version of the OpenAPI document: unset-unset-unset + * Contact: support@takaro.io * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * https://openapi-generator.tech diff --git a/packages/lib-modules/src/dto/takaroEvents.ts b/packages/lib-modules/src/dto/takaroEvents.ts index b834c59138..d3e8a9d92e 100644 --- a/packages/lib-modules/src/dto/takaroEvents.ts +++ b/packages/lib-modules/src/dto/takaroEvents.ts @@ -144,7 +144,7 @@ export class TakaroEventCommandExecuted extends BaseEvent; - @ValidateNested({ each: true }) + @ValidateNested() @Type(() => TakaroEventFunctionResult) result: TakaroEventFunctionResult; @@ -161,7 +161,7 @@ export class TakaroEventHookExecuted extends BaseEvent @IsDefined() data: Record; - @ValidateNested({ each: true }) + @ValidateNested() @Type(() => TakaroEventFunctionResult) result: TakaroEventFunctionResult; @@ -178,7 +178,7 @@ export class TakaroEventCronjobExecuted extends BaseEvent; - @ValidateNested({ each: true }) + @ValidateNested() @Type(() => TakaroEventFunctionResult) result: TakaroEventFunctionResult; diff --git a/packages/test/src/__snapshots__/PlayerController/Assigning the same role for same gameserver should fail.json b/packages/test/src/__snapshots__/PlayerController/Assigning the same role for same gameserver should fail.json deleted file mode 100644 index e320cc81dc..0000000000 --- a/packages/test/src/__snapshots__/PlayerController/Assigning the same role for same gameserver should fail.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "body": { - "meta": { - "error": { - "code": "BadRequestError", - "message": "Role already assigned" - } - }, - "data": {} - }, - "status": 400, - "test": { - "group": "PlayerController", - "snapshot": true, - "name": "Assigning the same role for same gameserver should fail", - "expectedStatus": 400, - "filteredFields": [], - "standardEnvironment": true - } -} \ No newline at end of file diff --git a/packages/test/src/__snapshots__/PlayerController/Assigning the same role twice should fail.json b/packages/test/src/__snapshots__/PlayerController/Assigning the same role twice should fail.json deleted file mode 100644 index c4d7cab498..0000000000 --- a/packages/test/src/__snapshots__/PlayerController/Assigning the same role twice should fail.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "body": { - "meta": { - "error": { - "code": "BadRequestError", - "message": "Role already assigned" - } - }, - "data": {} - }, - "status": 400, - "test": { - "group": "PlayerController", - "snapshot": true, - "name": "Assigning the same role twice should fail", - "expectedStatus": 400, - "filteredFields": [], - "standardEnvironment": true - } -} \ No newline at end of file diff --git a/packages/test/src/__snapshots__/PlayerController/Can override the expiry of a role assignment.json b/packages/test/src/__snapshots__/PlayerController/Can override the expiry of a role assignment.json new file mode 100644 index 0000000000..bceef6046b --- /dev/null +++ b/packages/test/src/__snapshots__/PlayerController/Can override the expiry of a role assignment.json @@ -0,0 +1,82 @@ +{ + "body": { + "meta": {}, + "data": { + "createdAt": "2024-08-17T14:54:58.892Z", + "updatedAt": "2024-08-17T14:54:59.406Z", + "id": "0bc2831c-42fb-4bc8-876d-37a7f789cf63", + "name": "Candice_Berge", + "steamId": "xf5eryn8r1gs02tu", + "xboxLiveId": "ne67y6p9cmjncz8m", + "epicOnlineServicesId": "x606jagm8uou2go9", + "steamAvatar": null, + "steamLastFetch": null, + "steamAccountCreated": null, + "steamCommunityBanned": null, + "steamEconomyBan": null, + "steamVacBanned": null, + "steamsDaysSinceLastBan": null, + "steamNumberOfVACBans": null, + "steamLevel": null, + "roleAssignments": [ + { + "createdAt": "2024-08-17T14:54:59.664Z", + "updatedAt": "2024-08-17T14:54:59.690Z", + "id": "0a6d9fe7-e80a-410a-bf12-7095eac25143", + "playerId": "0bc2831c-42fb-4bc8-876d-37a7f789cf63", + "roleId": "e6de15d8-f192-4a90-a663-c5322f2e2d6f", + "gameServerId": null, + "expiresAt": "2024-08-17T15:54:59.646Z", + "role": { + "createdAt": "2024-08-17T14:54:59.638Z", + "updatedAt": "2024-08-17T14:54:59.639Z", + "id": "e6de15d8-f192-4a90-a663-c5322f2e2d6f", + "name": "Test role", + "system": false, + "permissions": [ + { + "createdAt": "2024-08-17T14:54:59.641Z", + "updatedAt": "2024-08-17T14:54:59.641Z", + "id": "95ca3c75-4659-4be8-a1a9-3784cf84f0ea", + "roleId": "e6de15d8-f192-4a90-a663-c5322f2e2d6f", + "count": 0, + "permissionId": "3b7f6e7e-14fa-48b2-9b62-2aff6575350f" + } + ] + } + }, + { + "playerId": "0bc2831c-42fb-4bc8-876d-37a7f789cf63", + "roleId": "7b6d0471-cc33-4226-8155-d5584d559601", + "role": { + "createdAt": "2024-08-17T14:54:58.381Z", + "updatedAt": "2024-08-17T14:54:58.382Z", + "id": "7b6d0471-cc33-4226-8155-d5584d559601", + "name": "Player", + "system": true, + "permissions": [] + } + } + ], + "ipHistory": [] + } + }, + "status": 200, + "test": { + "group": "PlayerController", + "snapshot": true, + "name": "Can override the expiry of a role assignment", + "filteredFields": [ + "name", + "playerId", + "steamId", + "roleId", + "gameServerId", + "epicOnlineServicesId", + "xboxLiveId", + "expiresAt" + ], + "expectedStatus": 200, + "standardEnvironment": true + } +} \ No newline at end of file diff --git a/packages/test/src/integrationTest.ts b/packages/test/src/integrationTest.ts index 77a11d4363..3b2d6a1337 100644 --- a/packages/test/src/integrationTest.ts +++ b/packages/test/src/integrationTest.ts @@ -2,7 +2,7 @@ import 'reflect-metadata'; import { matchSnapshot } from './snapshots.js'; import { integrationConfig, sandbox } from './main.js'; import { expect } from './test/expect.js'; -import { AdminClient, Client, AxiosResponse, isAxiosError } from '@takaro/apiclient'; +import { AdminClient, Client, AxiosResponse, isAxiosError, TakaroEventCommandExecuted } from '@takaro/apiclient'; import { randomUUID } from 'crypto'; import { retry } from '@takaro/util'; @@ -138,6 +138,21 @@ export class IntegrationTest { } if (integrationTestContext.standardDomainId) { + try { + const failedFunctionsRes = await integrationTestContext.client.event.eventControllerGetFailedFunctions(); + + if (failedFunctionsRes.data.data.length > 0) { + console.error(`There were ${failedFunctionsRes.data.data.length} failed functions`); + for (const failedFn of failedFunctionsRes.data.data) { + const name = (failedFn.meta as TakaroEventCommandExecuted).command?.name; + const msgs = (failedFn.meta as TakaroEventCommandExecuted)?.result.logs.map((l) => l.msg); + console.log(`Function with name "${name}" failed with messages: ${msgs}`); + } + } + } catch (_error) { + // Ignore, just reporting + } + try { await integrationTestContext.adminClient.domain.domainControllerRemove( integrationTestContext.standardDomainId,