merge: 예약 오픈 공지 잔존 수정 반영
This commit is contained in:
@@ -98,7 +98,6 @@ export class RepositoryProfileStatusService implements GatewayProfileStatusServi
|
|||||||
const [profileRows, recentResetOperations] = await Promise.all([
|
const [profileRows, recentResetOperations] = await Promise.all([
|
||||||
this.profiles.listProfiles(),
|
this.profiles.listProfiles(),
|
||||||
this.profiles.listOperations({
|
this.profiles.listOperations({
|
||||||
statuses: ['QUEUED', 'RUNNING', 'SUCCEEDED'],
|
|
||||||
types: ['RESET'],
|
types: ['RESET'],
|
||||||
limit: 200,
|
limit: 200,
|
||||||
}),
|
}),
|
||||||
@@ -106,15 +105,9 @@ export class RepositoryProfileStatusService implements GatewayProfileStatusServi
|
|||||||
const rows = orderGatewayProfiles(profileRows);
|
const rows = orderGatewayProfiles(profileRows);
|
||||||
const runtimeStates = await this.orchestrator.listRuntimeStates(rows.map((profile) => profile.profileName));
|
const runtimeStates = await this.orchestrator.listRuntimeStates(rows.map((profile) => profile.profileName));
|
||||||
const runtimeMap = new Map(runtimeStates.map((state) => [state.profileName, state]));
|
const runtimeMap = new Map(runtimeStates.map((state) => [state.profileName, state]));
|
||||||
const announcementMap = new Map<string, LobbyUpcomingReset>();
|
|
||||||
const profileStatusMap = new Map(rows.map((row) => [row.profileName, row.status]));
|
const profileStatusMap = new Map(rows.map((row) => [row.profileName, row.status]));
|
||||||
const now = this.now();
|
const now = this.now();
|
||||||
for (const operation of recentResetOperations) {
|
const announcementMap = resolveUpcomingResetAnnouncements(recentResetOperations, profileStatusMap, now);
|
||||||
if (announcementMap.has(operation.profileName)) continue;
|
|
||||||
if (!shouldExposeUpcomingReset(operation, profileStatusMap.get(operation.profileName))) continue;
|
|
||||||
const announcement = resolveUpcomingResetAnnouncement(operation, now);
|
|
||||||
if (announcement) announcementMap.set(operation.profileName, announcement);
|
|
||||||
}
|
|
||||||
return rows.map((row) => this.mapProfile(row, runtimeMap, announcementMap));
|
return rows.map((row) => this.mapProfile(row, runtimeMap, announcementMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,6 +191,23 @@ export const shouldExposeUpcomingReset = (
|
|||||||
operation.status === 'RUNNING' ||
|
operation.status === 'RUNNING' ||
|
||||||
(operation.status === 'SUCCEEDED' && profileStatus === 'RESERVED'));
|
(operation.status === 'SUCCEEDED' && profileStatus === 'RESERVED'));
|
||||||
|
|
||||||
|
export const resolveUpcomingResetAnnouncements = (
|
||||||
|
operations: GatewayOperationRecord[],
|
||||||
|
profileStatusMap: ReadonlyMap<string, GatewayProfileStatus>,
|
||||||
|
now: Date
|
||||||
|
): Map<string, LobbyUpcomingReset> => {
|
||||||
|
const announcements = new Map<string, LobbyUpcomingReset>();
|
||||||
|
const resolvedProfiles = new Set<string>();
|
||||||
|
for (const operation of operations) {
|
||||||
|
if (resolvedProfiles.has(operation.profileName)) continue;
|
||||||
|
resolvedProfiles.add(operation.profileName);
|
||||||
|
if (!shouldExposeUpcomingReset(operation, profileStatusMap.get(operation.profileName))) continue;
|
||||||
|
const announcement = resolveUpcomingResetAnnouncement(operation, now);
|
||||||
|
if (announcement) announcements.set(operation.profileName, announcement);
|
||||||
|
}
|
||||||
|
return announcements;
|
||||||
|
};
|
||||||
|
|
||||||
export const resolveUpcomingResetAnnouncement = (
|
export const resolveUpcomingResetAnnouncement = (
|
||||||
operation: GatewayOperationRecord,
|
operation: GatewayOperationRecord,
|
||||||
now: Date
|
now: Date
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
import { resolveUpcomingResetAnnouncement, shouldExposeUpcomingReset } from '../src/lobby/profileStatusService.js';
|
import {
|
||||||
|
resolveUpcomingResetAnnouncement,
|
||||||
|
resolveUpcomingResetAnnouncements,
|
||||||
|
shouldExposeUpcomingReset,
|
||||||
|
} from '../src/lobby/profileStatusService.js';
|
||||||
import type { GatewayOperationRecord } from '../src/orchestrator/profileRepository.js';
|
import type { GatewayOperationRecord } from '../src/orchestrator/profileRepository.js';
|
||||||
|
|
||||||
const buildOperation = (status: GatewayOperationRecord['status'] = 'QUEUED'): GatewayOperationRecord => ({
|
const buildOperation = (status: GatewayOperationRecord['status'] = 'QUEUED'): GatewayOperationRecord => ({
|
||||||
@@ -101,4 +105,48 @@ describe('resolveUpcomingResetAnnouncement', () => {
|
|||||||
incomplete.payload = { publicAnnouncement: { enabled: true, scenarioTitle: '황건적의 난' } };
|
incomplete.payload = { publicAnnouncement: { enabled: true, scenarioTitle: '황건적의 난' } };
|
||||||
expect(resolveUpcomingResetAnnouncement(incomplete, new Date('2026-08-27T04:00:00.000Z'))).toBeNull();
|
expect(resolveUpcomingResetAnnouncement(incomplete, new Date('2026-08-27T04:00:00.000Z'))).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not restore an older published notice after a newer reset replaces it', () => {
|
||||||
|
const olderPublished = buildOperation('SUCCEEDED');
|
||||||
|
const newerImmediate = {
|
||||||
|
...buildOperation('SUCCEEDED'),
|
||||||
|
id: '22222222-2222-4222-8222-222222222222',
|
||||||
|
payload: {
|
||||||
|
install: {
|
||||||
|
scenarioId: 1011,
|
||||||
|
preopenAt: '2026-09-01T05:30:00.000Z',
|
||||||
|
openAt: '2026-09-01T11:00:00.000Z',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
scheduledAt: undefined,
|
||||||
|
createdAt: '2026-08-27T01:00:00.000Z',
|
||||||
|
updatedAt: '2026-08-27T01:00:00.000Z',
|
||||||
|
} satisfies GatewayOperationRecord;
|
||||||
|
|
||||||
|
const result = resolveUpcomingResetAnnouncements(
|
||||||
|
[newerImmediate, olderPublished],
|
||||||
|
new Map([['che:2', 'RESERVED']]),
|
||||||
|
new Date('2026-08-27T04:00:00.000Z')
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.has('che:2')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('treats a newer cancelled reset as the announcement boundary', () => {
|
||||||
|
const olderPublished = buildOperation('SUCCEEDED');
|
||||||
|
const newerCancelled = {
|
||||||
|
...buildOperation('CANCELLED'),
|
||||||
|
id: '33333333-3333-4333-8333-333333333333',
|
||||||
|
createdAt: '2026-08-27T01:00:00.000Z',
|
||||||
|
updatedAt: '2026-08-27T01:00:00.000Z',
|
||||||
|
} satisfies GatewayOperationRecord;
|
||||||
|
|
||||||
|
const result = resolveUpcomingResetAnnouncements(
|
||||||
|
[newerCancelled, olderPublished],
|
||||||
|
new Map([['che:2', 'RESERVED']]),
|
||||||
|
new Date('2026-08-27T04:00:00.000Z')
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.has('che:2')).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user