diff --git a/core/migrations/1670957155866-Automigration.ts b/core/migrations/1670957155866-Automigration.ts new file mode 100644 index 000000000..1780962a4 --- /dev/null +++ b/core/migrations/1670957155866-Automigration.ts @@ -0,0 +1,28 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Automigration1670957155866 implements MigrationInterface { + name = 'Automigration1670957155866' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "sprocket"."user_platform_account" ("id" SERIAL NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP, "userId" integer NOT NULL, "platformId" integer NOT NULL, "platformAccountId" character varying NOT NULL, CONSTRAINT "UQ_c1e293939718af0341848e0828a" UNIQUE ("platformId", "platformAccountId"), CONSTRAINT "PK_bcd8ff22acd439360a79b6e0b3f" PRIMARY KEY ("id"))`); + await queryRunner.query(`ALTER TABLE "sprocket"."user_platform_account" ADD CONSTRAINT "FK_122bbbcdec97c1b5e8dd1298376" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "sprocket"."user_platform_account" ADD CONSTRAINT "FK_edf33e55f97c0d3ac66406bce9f" FOREIGN KEY ("platformId") REFERENCES "platform"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(` + WITH accounts AS (SELECT DISTINCT mpa."createdAt", mpa."platformId", mpa."platformAccountId", m."userId" + FROM sprocket.member_platform_account mpa INNER JOIN sprocket.member m ON m.id = mpa."memberId") + INSERT INTO sprocket.user_platform_account ("createdAt", "platformId", "platformAccountId", "userId") + SELECT "createdAt", "platformId", "platformAccountId", "userId" FROM accounts; + `); + await queryRunner.query(`DROP TABLE "sprocket"."member_platform_account"`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "sprocket"."user_platform_account" DROP CONSTRAINT "FK_edf33e55f97c0d3ac66406bce9f"`); + await queryRunner.query(`ALTER TABLE "sprocket"."user_platform_account" DROP CONSTRAINT "FK_122bbbcdec97c1b5e8dd1298376"`); + await queryRunner.query(`DROP TABLE "sprocket"."user_platform_account"`); + await queryRunner.query(`CREATE TABLE "sprocket"."member_platform_account" ("id" SERIAL NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP, "memberId" integer NOT NULL, "platformId" integer NOT NULL, "platformAccountId" character varying NOT NULL, CONSTRAINT "UQ_c1e293939718af0341848e0828a" UNIQUE ("platformId", "platformAccountId"), CONSTRAINT "PK_bcd8ff22acd439360a79b6e0b3f" PRIMARY KEY ("id"))`); + await queryRunner.query(`ALTER TABLE "sprocket"."member_platform_account" ADD CONSTRAINT "FK_122bbbcdec97c1b5e8dd1298376" FOREIGN KEY ("memberId") REFERENCES "member"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "sprocket"."member_platform_account" ADD CONSTRAINT "FK_edf33e55f97c0d3ac66406bce9f" FOREIGN KEY ("platformId") REFERENCES "platform"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + +} diff --git a/core/src/franchise/player/player.service.ts b/core/src/franchise/player/player.service.ts index c2591c14a..52cf3d38b 100644 --- a/core/src/franchise/player/player.service.ts +++ b/core/src/franchise/player/player.service.ts @@ -372,11 +372,13 @@ export class PlayerService { }, }, member: { - platformAccounts: { - platform: { - id: platformId, + user: { + platformAccounts: { + platform: { + id: platformId, + }, + platformAccountId: platformAccountId, }, - platformAccountId: platformAccountId, }, }, }, @@ -433,13 +435,14 @@ export class PlayerService { .innerJoinAndSelect("player.skillGroup", "skillGroup") .innerJoinAndSelect("skillGroup.game", "game") .innerJoinAndSelect("player.member", "member") - .innerJoinAndSelect("member.platformAccounts", "platformAccount") + .innerJoinAndSelect("member.user", "user") + .innerJoinAndSelect("user.platformAccounts", "platformAccount") .innerJoinAndSelect("platformAccount.platform", "platform") .innerJoinAndSelect("platform.supportedGames", "supportedGame", "supportedGame.gameId = game.id") .where("player.id = :id", {id: playerId}) .andWhere("supportedGame.canSaveDemos = true") .getOne(); - return Boolean(player?.member.platformAccounts.length); + return Boolean(player?.member.user.platformAccounts.length); } } diff --git a/core/src/game/database/platform.entity.ts b/core/src/game/database/platform.entity.ts index af7bbe391..7de6a2364 100644 --- a/core/src/game/database/platform.entity.ts +++ b/core/src/game/database/platform.entity.ts @@ -1,6 +1,6 @@ import {Column, Entity, OneToMany} from "typeorm"; -import {MemberPlatformAccount} from "../../organization/database/member-platform-account.entity"; +import {UserPlatformAccount} from "../../identity/database/user-platform-account.entity"; import {BaseEntity} from "../../types/base-entity"; import {GamePlatform} from "./game-platform.entity"; @@ -9,8 +9,8 @@ export class Platform extends BaseEntity { @Column() code: string; - @OneToMany(() => MemberPlatformAccount, mpa => mpa.platform) - memberAccounts: MemberPlatformAccount[]; + @OneToMany(() => UserPlatformAccount, mpa => mpa.platform) + userAccounts: UserPlatformAccount[]; @OneToMany(() => GamePlatform, gp => gp.platform) supportedGames: GamePlatform[]; diff --git a/core/src/identity/database/identity-database.module.ts b/core/src/identity/database/identity-database.module.ts index 2124ff65b..3de593cc6 100644 --- a/core/src/identity/database/identity-database.module.ts +++ b/core/src/identity/database/identity-database.module.ts @@ -5,12 +5,20 @@ import {User} from "./user.entity"; import {UserProfiledRepository, UserRepository} from "./user.repository"; import {UserAuthenticationAccount} from "./user-authentication-account.entity"; import {UserAuthenticationAccountRepository} from "./user-authentication-account.repository"; +import {UserPlatformAccount} from "./user-platform-account.entity"; +import {UserPlatformAccountRepository} from "./user-platform-account.repository"; import {UserProfile} from "./user-profile.entity"; import {UserProfileRepository} from "./user-profile.repository"; -const ormModule = TypeOrmModule.forFeature([UserAuthenticationAccount, UserProfile, User]); +const ormModule = TypeOrmModule.forFeature([UserAuthenticationAccount, UserProfile, User, UserPlatformAccount]); -const providers = [UserAuthenticationAccountRepository, UserProfileRepository, UserRepository, UserProfiledRepository]; +const providers = [ + UserAuthenticationAccountRepository, + UserProfileRepository, + UserRepository, + UserProfiledRepository, + UserPlatformAccountRepository, +]; @Module({ imports: [ormModule], diff --git a/core/src/organization/database/member-platform-account.entity.ts b/core/src/identity/database/user-platform-account.entity.ts similarity index 73% rename from core/src/organization/database/member-platform-account.entity.ts rename to core/src/identity/database/user-platform-account.entity.ts index 0e7dca375..e2aa41d97 100644 --- a/core/src/organization/database/member-platform-account.entity.ts +++ b/core/src/identity/database/user-platform-account.entity.ts @@ -2,17 +2,17 @@ import {Column, Entity, JoinColumn, ManyToOne, Unique} from "typeorm"; import {Platform} from "../../game/database/platform.entity"; import {BaseEntity} from "../../types/base-entity"; -import {Member} from "./member.entity"; +import {User} from "./user.entity"; @Entity({schema: "sprocket"}) @Unique(["platform", "platformAccountId"]) -export class MemberPlatformAccount extends BaseEntity { - @ManyToOne(() => Member) +export class UserPlatformAccount extends BaseEntity { + @ManyToOne(() => User) @JoinColumn() - member: Member; + user: User; @Column() - memberId: number; + userId: number; @ManyToOne(() => Platform) @JoinColumn() diff --git a/core/src/organization/database/member-platform-account.repository.ts b/core/src/identity/database/user-platform-account.repository.ts similarity index 50% rename from core/src/organization/database/member-platform-account.repository.ts rename to core/src/identity/database/user-platform-account.repository.ts index f20e54b92..63f147df8 100644 --- a/core/src/organization/database/member-platform-account.repository.ts +++ b/core/src/identity/database/user-platform-account.repository.ts @@ -2,11 +2,11 @@ import {Injectable} from "@nestjs/common"; import {DataSource} from "typeorm"; import {ExtendedRepository} from "../../types/extended-repositories"; -import {MemberPlatformAccount} from "./member-platform-account.entity"; +import {UserPlatformAccount} from "./user-platform-account.entity"; @Injectable() -export class MemberPlatformAccountRepository extends ExtendedRepository { +export class UserPlatformAccountRepository extends ExtendedRepository { constructor(readonly dataSource: DataSource) { - super(MemberPlatformAccount, dataSource); + super(UserPlatformAccount, dataSource); } } diff --git a/core/src/identity/database/user.entity.ts b/core/src/identity/database/user.entity.ts index 0d526a3e2..5c6d9bde1 100644 --- a/core/src/identity/database/user.entity.ts +++ b/core/src/identity/database/user.entity.ts @@ -3,6 +3,7 @@ import {Entity, OneToMany, OneToOne} from "typeorm"; import {Member} from "../../organization/database/member.entity"; import {BaseEntity} from "../../types/base-entity"; import {UserAuthenticationAccount} from "./user-authentication-account.entity"; +import {UserPlatformAccount} from "./user-platform-account.entity"; import {UserProfile} from "./user-profile.entity"; @Entity({schema: "sprocket"}) @@ -10,6 +11,9 @@ export class User extends BaseEntity { @OneToMany(() => UserAuthenticationAccount, uaa => uaa.user) authenticationAccounts: UserAuthenticationAccount[]; + @OneToMany(() => UserPlatformAccount, upa => upa.user) + platformAccounts: UserPlatformAccount[]; + @OneToOne(() => UserProfile, profile => profile.user) profile: UserProfile; diff --git a/core/src/organization/database/member.entity.ts b/core/src/organization/database/member.entity.ts index 4ec1ed571..99f37b69a 100644 --- a/core/src/organization/database/member.entity.ts +++ b/core/src/organization/database/member.entity.ts @@ -4,16 +4,12 @@ import {OrganizationStaffSeat} from "../../authorization/database/organization-s import {Player} from "../../franchise/database/player.entity"; import {User} from "../../identity/database/user.entity"; import {BaseEntity} from "../../types/base-entity"; -import {MemberPlatformAccount} from "./member-platform-account.entity"; import {MemberProfile} from "./member-profile.entity"; import {MemberRestriction} from "./member-restriction.entity"; import {Organization} from "./organization.entity"; @Entity({schema: "sprocket"}) export class Member extends BaseEntity { - @OneToMany(() => MemberPlatformAccount, mpa => mpa.member) - platformAccounts: MemberPlatformAccount[]; - @OneToOne(() => MemberProfile, mp => mp.member) profile: MemberProfile; diff --git a/core/src/organization/database/organization-database.module.ts b/core/src/organization/database/organization-database.module.ts index 4404d3877..e7fb7a307 100644 --- a/core/src/organization/database/organization-database.module.ts +++ b/core/src/organization/database/organization-database.module.ts @@ -6,8 +6,6 @@ import {Approval} from "./approval.entity"; import {ApprovalRepository} from "./approval.repository"; import {Member} from "./member.entity"; import {MemberProfiledRepository, MemberRepository} from "./member.repository"; -import {MemberPlatformAccount} from "./member-platform-account.entity"; -import {MemberPlatformAccountRepository} from "./member-platform-account.repository"; import {MemberProfile} from "./member-profile.entity"; import {MemberProfileRepository} from "./member-profile.repository"; import {MemberRestriction} from "./member-restriction.entity"; @@ -26,7 +24,6 @@ import {PronounsRepository} from "./pronouns.repository"; const ormModule = TypeOrmModule.forFeature([ Approval, Member, - MemberPlatformAccount, MemberProfile, MemberRestriction, Organization, @@ -39,7 +36,6 @@ const ormModule = TypeOrmModule.forFeature([ const providers = [ ApprovalRepository, MemberRepository, - MemberPlatformAccountRepository, MemberProfileRepository, MemberProfiledRepository, MemberRestrictionRepository, diff --git a/core/src/scheduling/finalization/rocket-league-finalization/rocket-league-finalization.service.ts b/core/src/scheduling/finalization/rocket-league-finalization/rocket-league-finalization.service.ts index 49be1a168..836a0458e 100644 --- a/core/src/scheduling/finalization/rocket-league-finalization/rocket-league-finalization.service.ts +++ b/core/src/scheduling/finalization/rocket-league-finalization/rocket-league-finalization.service.ts @@ -184,22 +184,25 @@ export class RocketLeagueFinalizationService { const {home, away} = isMatch ? await this.matchService.getFranchisesForMatch(match.id) : {home: undefined, away: undefined}; - const [homeTeam, awayTeam] = isMatch - ? await Promise.all([ - await this.teamRepository.findOneOrFail({ - where: { - franchiseId: home!.id, - skillGroupId: match.skillGroupId, - }, - }), - await this.teamRepository.findOneOrFail({ - where: { - franchiseId: away!.id, - skillGroupId: match.skillGroupId, - }, - }), - ]) - : [undefined, undefined]; + + if (isMatch && (!home || !away)) throw new Error("Failed to find associated franchises"); + const [homeTeam, awayTeam] = + isMatch && home && away + ? await Promise.all([ + await this.teamRepository.findOneOrFail({ + where: { + franchiseId: home.id, + skillGroupId: match.skillGroupId, + }, + }), + await this.teamRepository.findOneOrFail({ + where: { + franchiseId: away.id, + skillGroupId: match.skillGroupId, + }, + }), + ]) + : [undefined, undefined]; const allPlayers: Player[] = []; @@ -229,6 +232,8 @@ export class RocketLeagueFinalizationService { orangeTeam: Team | undefined, orangeTeamName: string; if (isMatch) { + if (!home || !away) throw new Error("Failed to find associated franchises"); + const blueCaptain = blue[0].player; const orangeCaptain = orange[0].player; const [blueMle, orangeMle] = await Promise.all([ @@ -243,8 +248,8 @@ export class RocketLeagueFinalizationService { /* * Identify which team is home; and which is away */ - homeColor = blueTeamName === home!.profile.title ? "blue" : "orange"; - awayColor = blueTeamName === home!.profile.title ? "orange" : "blue"; + homeColor = blueTeamName === home.profile.title ? "blue" : "orange"; + awayColor = blueTeamName === home.profile.title ? "orange" : "blue"; blueTeam = homeColor === "blue" ? homeTeam : awayTeam; orangeTeam = homeColor === "orange" ? homeTeam : awayTeam; } else { @@ -359,15 +364,17 @@ export class RocketLeagueFinalizationService { this.playerRepository.findOneOrFail({ where: { member: { - platformAccounts: { - platformAccountId: p.id.id, - platform: { - code: p.id.platform.toUpperCase(), + user: { + platformAccounts: { + platformAccountId: p.id.id, + platform: { + code: p.id.platform.toUpperCase(), + }, }, }, }, }, - relations: {member: {platformAccounts: {platform: true}}}, + relations: {member: {user: {platformAccounts: {platform: true}}}}, }); const bluePlayerIds = new Array();