wip
This commit is contained in:
@@ -40,6 +40,20 @@ import type { IFeedRepository } from '@gridpilot/social/domain/repositories/IFee
|
||||
import type { ISocialGraphRepository } from '@gridpilot/social/domain/repositories/ISocialGraphRepository';
|
||||
import type { ImageServicePort } from '@gridpilot/media';
|
||||
|
||||
// Notifications package imports
|
||||
import type { INotificationRepository, INotificationPreferenceRepository } from '@gridpilot/notifications/application';
|
||||
import {
|
||||
SendNotificationUseCase,
|
||||
MarkNotificationReadUseCase,
|
||||
GetUnreadNotificationsQuery
|
||||
} from '@gridpilot/notifications/application';
|
||||
import {
|
||||
InMemoryNotificationRepository,
|
||||
InMemoryNotificationPreferenceRepository,
|
||||
NotificationGatewayRegistry,
|
||||
InAppNotificationAdapter,
|
||||
} from '@gridpilot/notifications/infrastructure';
|
||||
|
||||
import { InMemoryDriverRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryDriverRepository';
|
||||
import { InMemoryLeagueRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryLeagueRepository';
|
||||
import { InMemoryRaceRepository } from '@gridpilot/racing/infrastructure/repositories/InMemoryRaceRepository';
|
||||
@@ -92,7 +106,10 @@ import {
|
||||
ApplyPenaltyUseCase,
|
||||
GetRaceProtestsQuery,
|
||||
GetRacePenaltiesQuery,
|
||||
RequestProtestDefenseUseCase,
|
||||
SubmitProtestDefenseUseCase,
|
||||
} from '@gridpilot/racing/application';
|
||||
import { TransferLeagueOwnershipUseCase } from '@gridpilot/racing/application/use-cases/TransferLeagueOwnershipUseCase';
|
||||
import type { DriverRatingProvider } from '@gridpilot/racing/application';
|
||||
import {
|
||||
createStaticRacingSeed,
|
||||
@@ -194,6 +211,14 @@ class DIContainer {
|
||||
private _trackRepository: ITrackRepository;
|
||||
private _carRepository: ICarRepository;
|
||||
|
||||
// Notifications
|
||||
private _notificationRepository: INotificationRepository;
|
||||
private _notificationPreferenceRepository: INotificationPreferenceRepository;
|
||||
private _notificationGatewayRegistry: NotificationGatewayRegistry;
|
||||
private _sendNotificationUseCase: SendNotificationUseCase;
|
||||
private _markNotificationReadUseCase: MarkNotificationReadUseCase;
|
||||
private _getUnreadNotificationsQuery: GetUnreadNotificationsQuery;
|
||||
|
||||
// Racing application use-cases / queries
|
||||
private _joinLeagueUseCase: JoinLeagueUseCase;
|
||||
private _registerForRaceUseCase: RegisterForRaceUseCase;
|
||||
@@ -219,6 +244,8 @@ class DIContainer {
|
||||
private _applyPenaltyUseCase: ApplyPenaltyUseCase;
|
||||
private _getRaceProtestsQuery: GetRaceProtestsQuery;
|
||||
private _getRacePenaltiesQuery: GetRacePenaltiesQuery;
|
||||
private _requestProtestDefenseUseCase: RequestProtestDefenseUseCase;
|
||||
private _submitProtestDefenseUseCase: SubmitProtestDefenseUseCase;
|
||||
|
||||
private _createTeamUseCase: CreateTeamUseCase;
|
||||
private _joinTeamUseCase: JoinTeamUseCase;
|
||||
@@ -231,6 +258,7 @@ class DIContainer {
|
||||
private _getTeamMembersQuery: GetTeamMembersQuery;
|
||||
private _getTeamJoinRequestsQuery: GetTeamJoinRequestsQuery;
|
||||
private _getDriverTeamQuery: GetDriverTeamQuery;
|
||||
private _transferLeagueOwnershipUseCase: TransferLeagueOwnershipUseCase;
|
||||
|
||||
private constructor() {
|
||||
// Create seed data
|
||||
@@ -435,8 +463,7 @@ class DIContainer {
|
||||
|
||||
for (const league of seedData.leagues) {
|
||||
const archetype = getDemoLeagueArchetypeByName(league.name);
|
||||
if (!archetype) continue;
|
||||
|
||||
|
||||
const season = Season.create({
|
||||
id: `season-${league.id}-demo`,
|
||||
leagueId: league.id,
|
||||
@@ -450,15 +477,14 @@ class DIContainer {
|
||||
});
|
||||
seededSeasons.push(season);
|
||||
|
||||
const infraPreset = getLeagueScoringPresetById(
|
||||
archetype.scoringPresetId,
|
||||
);
|
||||
if (!infraPreset) {
|
||||
// If a preset is missing, skip scoring config for this league in alpha seed.
|
||||
continue;
|
||||
// Use archetype preset if available, otherwise fall back to default club preset
|
||||
const presetId = archetype?.scoringPresetId ?? 'club-default';
|
||||
const infraPreset = getLeagueScoringPresetById(presetId);
|
||||
|
||||
if (infraPreset) {
|
||||
const config = infraPreset.createConfig({ seasonId: season.id });
|
||||
seededScoringConfigs.push(config);
|
||||
}
|
||||
const config = infraPreset.createConfig({ seasonId: season.id });
|
||||
seededScoringConfigs.push(config);
|
||||
}
|
||||
|
||||
this._gameRepository = new InMemoryGameRepository([game]);
|
||||
@@ -550,6 +576,33 @@ class DIContainer {
|
||||
});
|
||||
}
|
||||
|
||||
// Seed sample league stewards for the primary driver's league (alpha demo)
|
||||
if (primaryLeagueForAdmins) {
|
||||
const stewardCandidates = seedData.drivers
|
||||
.filter((d) => d.id !== primaryLeagueForAdmins.ownerId)
|
||||
.slice(2, 5);
|
||||
|
||||
stewardCandidates.forEach((driver) => {
|
||||
const existing = seededMemberships.find(
|
||||
(m) =>
|
||||
m.leagueId === primaryLeagueForAdmins.id && m.driverId === driver.id,
|
||||
);
|
||||
if (existing) {
|
||||
if (existing.role !== 'owner' && existing.role !== 'admin') {
|
||||
existing.role = 'steward';
|
||||
}
|
||||
} else {
|
||||
seededMemberships.push({
|
||||
leagueId: primaryLeagueForAdmins.id,
|
||||
driverId: driver.id,
|
||||
role: 'steward',
|
||||
status: 'active',
|
||||
joinedAt: new Date(),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Seed a few pending join requests for demo leagues (expanded to more leagues)
|
||||
const seededJoinRequests: JoinRequest[] = [];
|
||||
const demoLeagues = seedData.leagues.slice(0, 6); // Expanded from 2 to 6 leagues
|
||||
@@ -762,6 +815,11 @@ class DIContainer {
|
||||
this._teamMembershipRepository,
|
||||
);
|
||||
|
||||
this._transferLeagueOwnershipUseCase = new TransferLeagueOwnershipUseCase(
|
||||
this._leagueRepository,
|
||||
this._leagueMembershipRepository,
|
||||
);
|
||||
|
||||
// Stewarding use cases and queries
|
||||
this._fileProtestUseCase = new FileProtestUseCase(
|
||||
this._protestRepository,
|
||||
@@ -787,6 +845,14 @@ class DIContainer {
|
||||
this._penaltyRepository,
|
||||
this._driverRepository,
|
||||
);
|
||||
this._requestProtestDefenseUseCase = new RequestProtestDefenseUseCase(
|
||||
this._protestRepository,
|
||||
this._raceRepository,
|
||||
this._leagueMembershipRepository,
|
||||
);
|
||||
this._submitProtestDefenseUseCase = new SubmitProtestDefenseUseCase(
|
||||
this._protestRepository,
|
||||
);
|
||||
|
||||
// Social and feed adapters backed by static seed
|
||||
this._feedRepository = new InMemoryFeedRepository(seedData);
|
||||
@@ -972,6 +1038,29 @@ class DIContainer {
|
||||
|
||||
this._trackRepository = new InMemoryTrackRepository(seedTracks);
|
||||
this._carRepository = new InMemoryCarRepository(seedCars);
|
||||
|
||||
// Initialize notifications
|
||||
this._notificationRepository = new InMemoryNotificationRepository();
|
||||
this._notificationPreferenceRepository = new InMemoryNotificationPreferenceRepository();
|
||||
|
||||
// Set up gateway registry with adapters
|
||||
this._notificationGatewayRegistry = new NotificationGatewayRegistry([
|
||||
new InAppNotificationAdapter(),
|
||||
// Future: DiscordNotificationAdapter, EmailNotificationAdapter
|
||||
]);
|
||||
|
||||
// Notification use cases
|
||||
this._sendNotificationUseCase = new SendNotificationUseCase(
|
||||
this._notificationRepository,
|
||||
this._notificationPreferenceRepository,
|
||||
this._notificationGatewayRegistry,
|
||||
);
|
||||
this._markNotificationReadUseCase = new MarkNotificationReadUseCase(
|
||||
this._notificationRepository,
|
||||
);
|
||||
this._getUnreadNotificationsQuery = new GetUnreadNotificationsQuery(
|
||||
this._notificationRepository,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1187,6 +1276,26 @@ class DIContainer {
|
||||
return this._carRepository;
|
||||
}
|
||||
|
||||
get notificationRepository(): INotificationRepository {
|
||||
return this._notificationRepository;
|
||||
}
|
||||
|
||||
get notificationPreferenceRepository(): INotificationPreferenceRepository {
|
||||
return this._notificationPreferenceRepository;
|
||||
}
|
||||
|
||||
get sendNotificationUseCase(): SendNotificationUseCase {
|
||||
return this._sendNotificationUseCase;
|
||||
}
|
||||
|
||||
get markNotificationReadUseCase(): MarkNotificationReadUseCase {
|
||||
return this._markNotificationReadUseCase;
|
||||
}
|
||||
|
||||
get getUnreadNotificationsQuery(): GetUnreadNotificationsQuery {
|
||||
return this._getUnreadNotificationsQuery;
|
||||
}
|
||||
|
||||
get fileProtestUseCase(): FileProtestUseCase {
|
||||
return this._fileProtestUseCase;
|
||||
}
|
||||
@@ -1206,6 +1315,18 @@ class DIContainer {
|
||||
get getRacePenaltiesQuery(): GetRacePenaltiesQuery {
|
||||
return this._getRacePenaltiesQuery;
|
||||
}
|
||||
|
||||
get requestProtestDefenseUseCase(): RequestProtestDefenseUseCase {
|
||||
return this._requestProtestDefenseUseCase;
|
||||
}
|
||||
|
||||
get submitProtestDefenseUseCase(): SubmitProtestDefenseUseCase {
|
||||
return this._submitProtestDefenseUseCase;
|
||||
}
|
||||
|
||||
get transferLeagueOwnershipUseCase(): TransferLeagueOwnershipUseCase {
|
||||
return this._transferLeagueOwnershipUseCase;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1388,6 +1509,26 @@ export function getCarRepository(): ICarRepository {
|
||||
return DIContainer.getInstance().carRepository;
|
||||
}
|
||||
|
||||
export function getNotificationRepository(): INotificationRepository {
|
||||
return DIContainer.getInstance().notificationRepository;
|
||||
}
|
||||
|
||||
export function getNotificationPreferenceRepository(): INotificationPreferenceRepository {
|
||||
return DIContainer.getInstance().notificationPreferenceRepository;
|
||||
}
|
||||
|
||||
export function getSendNotificationUseCase(): SendNotificationUseCase {
|
||||
return DIContainer.getInstance().sendNotificationUseCase;
|
||||
}
|
||||
|
||||
export function getMarkNotificationReadUseCase(): MarkNotificationReadUseCase {
|
||||
return DIContainer.getInstance().markNotificationReadUseCase;
|
||||
}
|
||||
|
||||
export function getGetUnreadNotificationsQuery(): GetUnreadNotificationsQuery {
|
||||
return DIContainer.getInstance().getUnreadNotificationsQuery;
|
||||
}
|
||||
|
||||
export function getFileProtestUseCase(): FileProtestUseCase {
|
||||
return DIContainer.getInstance().fileProtestUseCase;
|
||||
}
|
||||
@@ -1408,6 +1549,18 @@ export function getGetRacePenaltiesQuery(): GetRacePenaltiesQuery {
|
||||
return DIContainer.getInstance().getRacePenaltiesQuery;
|
||||
}
|
||||
|
||||
export function getRequestProtestDefenseUseCase(): RequestProtestDefenseUseCase {
|
||||
return DIContainer.getInstance().requestProtestDefenseUseCase;
|
||||
}
|
||||
|
||||
export function getSubmitProtestDefenseUseCase(): SubmitProtestDefenseUseCase {
|
||||
return DIContainer.getInstance().submitProtestDefenseUseCase;
|
||||
}
|
||||
|
||||
export function getTransferLeagueOwnershipUseCase(): TransferLeagueOwnershipUseCase {
|
||||
return DIContainer.getInstance().transferLeagueOwnershipUseCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset function for testing
|
||||
*/
|
||||
|
||||
@@ -5,7 +5,7 @@ import type {
|
||||
MembershipRole,
|
||||
MembershipStatus,
|
||||
} from '@gridpilot/racing/domain/entities/LeagueMembership';
|
||||
import { leagues, memberships as seedMemberships } from '@gridpilot/testing-support';
|
||||
import { leagues, memberships as seedMemberships, drivers } from '@gridpilot/testing-support';
|
||||
|
||||
/**
|
||||
* Lightweight league membership model mirroring the domain type but with
|
||||
@@ -65,6 +65,63 @@ const leagueMemberships = new Map<string, LeagueMembership[]>();
|
||||
byLeague.set(league.id, list);
|
||||
}
|
||||
|
||||
// Seed sample league admins for the primary driver's league (alpha demo)
|
||||
const primaryDriverId = drivers[0]?.id ?? 'driver-1';
|
||||
const primaryLeagueForAdmins = leagues.find((l) => l.ownerId === primaryDriverId) ?? leagues[0];
|
||||
|
||||
if (primaryLeagueForAdmins) {
|
||||
const adminCandidates = drivers
|
||||
.filter((d) => d.id !== primaryLeagueForAdmins.ownerId)
|
||||
.slice(0, 2);
|
||||
|
||||
adminCandidates.forEach((driver) => {
|
||||
const list = byLeague.get(primaryLeagueForAdmins.id) ?? [];
|
||||
const existing = list.find((m) => m.driverId === driver.id);
|
||||
if (existing) {
|
||||
if (existing.role !== 'owner') {
|
||||
existing.role = 'admin';
|
||||
}
|
||||
} else {
|
||||
const joinedAt = new Date().toISOString();
|
||||
list.push({
|
||||
leagueId: primaryLeagueForAdmins.id,
|
||||
driverId: driver.id,
|
||||
role: 'admin',
|
||||
status: 'active',
|
||||
joinedAt,
|
||||
});
|
||||
}
|
||||
byLeague.set(primaryLeagueForAdmins.id, list);
|
||||
});
|
||||
}
|
||||
|
||||
// Seed sample league stewards for the primary driver's league (alpha demo)
|
||||
if (primaryLeagueForAdmins) {
|
||||
const stewardCandidates = drivers
|
||||
.filter((d) => d.id !== primaryLeagueForAdmins.ownerId)
|
||||
.slice(2, 5);
|
||||
|
||||
stewardCandidates.forEach((driver) => {
|
||||
const list = byLeague.get(primaryLeagueForAdmins.id) ?? [];
|
||||
const existing = list.find((m) => m.driverId === driver.id);
|
||||
if (existing) {
|
||||
if (existing.role !== 'owner' && existing.role !== 'admin') {
|
||||
existing.role = 'steward';
|
||||
}
|
||||
} else {
|
||||
const joinedAt = new Date().toISOString();
|
||||
list.push({
|
||||
leagueId: primaryLeagueForAdmins.id,
|
||||
driverId: driver.id,
|
||||
role: 'steward',
|
||||
status: 'active',
|
||||
joinedAt,
|
||||
});
|
||||
}
|
||||
byLeague.set(primaryLeagueForAdmins.id, list);
|
||||
});
|
||||
}
|
||||
|
||||
for (const [leagueId, list] of byLeague.entries()) {
|
||||
leagueMemberships.set(leagueId, list);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user