Skip to content

Commit 20565c9

Browse files
committed
Fix for submission API URL
1 parent 3e576bb commit 20565c9

12 files changed

Lines changed: 278 additions & 36 deletions

File tree

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ DISABLE_KAFKA=false
7373
# Disable pg-boss queue/worker; compile runs inline on API instance when true.
7474
DISABLE_PG_BOSS=false
7575
# CHALLENGE_API_URL=https://api.topcoder-dev.com
76+
# SUBMISSION_API_URL=https://api.topcoder-dev.com/v6
7677
# RESOURCES_API_URL=https://api.topcoder-dev.com/v6/resources
7778

7879
# ECS configs

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ When both `EXAMPLE` and `PROVISIONAL` review summations are complete for a submi
9696
| Variable | Required | Default | Used for |
9797
| ---------------------------------- | --------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
9898
| `CHALLENGE_API_URL` | No | `https://api.topcoder-dev.com` | Challenge API lookup for current active phase |
99+
| `SUBMISSION_API_URL` | No | `${CHALLENGE_API_URL}/v6` | Submission API base URL used for submission lookups/downloads; prod should use `https://api.topcoder.com/v6` |
99100
| `RESOURCES_API_URL` | No | `${CHALLENGE_API_URL}/v6/resources` | Resource API lookup for challenge-specific copilot access to manual reruns |
100101
| `DISABLE_PG_BOSS` | No | `false` | Disable pg-boss queue/worker and run tester compilation inline |
101102
| `DEFAULT_REVIEW_SCORECARD_ID` | Yes (for UI defaults) | None | Default review scorecard returned by `GET /challenge/defaults` |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE marathon_match."marathonMatchConfig"
2+
ALTER COLUMN "submissionApiUrl" DROP DEFAULT;

prisma/schema.prisma

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ model marathonMatchConfig {
6060
active Boolean @default(true)
6161
relativeScoringEnabled Boolean @default(true)
6262
scoreDirection ScoreDirection @default(MAXIMIZE)
63-
submissionApiUrl String @default("https://api.topcoder-dev.com/v6")
63+
submissionApiUrl String
6464
reviewScorecardId String
6565
testerId String @db.VarChar(14)
6666
testTimeout Int

scripts/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ MM_API_BASE="https://api.topcoder-dev.com/v6/marathon-match"
99
CHALLENGE_API_BASE="https://api.topcoder-dev.com/v6/challenges"
1010
RESOURCE_API_BASE="https://api.topcoder-dev.com/v6/resources"
1111
REVIEW_API_BASE="https://api.topcoder-dev.com/v6/reviews"
12+
# Script-only collection endpoint. The API service runtime var is SUBMISSION_API_URL
13+
# and should be the base URL without /submissions.
1214
SUBMISSION_API_BASE="https://api.topcoder-dev.com/v6/submissions"
1315

1416
# Authentication. Use TOKEN/AUTH_TOKEN directly, or configure Auth0 client credentials.

src/api/kafka/marathon-match-submission.handler.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { HttpService } from '@nestjs/axios';
22
import { Injectable, OnModuleInit } from '@nestjs/common';
33
import { CompilationStatus } from '@prisma/client';
44
import { firstValueFrom } from 'rxjs';
5+
import { resolveSubmissionApiBaseUrl } from 'src/shared/config/submission-api-url.config';
56
import { M2MService } from 'src/shared/modules/global/m2m.service';
67
import { LoggerService } from 'src/shared/modules/global/logger.service';
78
import { PrismaService } from 'src/shared/modules/global/prisma.service';
@@ -216,14 +217,11 @@ export class MarathonMatchSubmissionHandler
216217
);
217218
}
218219

219-
const submissionApiBaseUrl =
220-
process.env.SUBMISSION_API_URL?.trim() ||
221-
config.submissionApiUrl?.trim();
222-
if (!submissionApiBaseUrl) {
223-
throw new Error(
224-
`Submission API URL is not configured for challenge ${challengeId}.`,
225-
);
226-
}
220+
const submissionApiBaseUrl = resolveSubmissionApiBaseUrl({
221+
configuredUrl: config.submissionApiUrl,
222+
fallbackApiBaseUrl: this.challengeApiBaseUrl,
223+
environmentUrls: [this.challengeApiBaseUrl],
224+
});
227225

228226
const token = await this.m2mService.getM2MToken();
229227
if (!token) {

src/api/marathon-match-config/marathon-match-config.service.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ import {
3030
TestSubmissionUploadDto,
3131
UpdateMarathonMatchConfigDto,
3232
} from 'src/dto/marathon-match-config.dto';
33+
import {
34+
resolvePersistedSubmissionApiBaseUrl,
35+
resolveSubmissionApiBaseUrl,
36+
} from 'src/shared/config/submission-api-url.config';
3337
import {
3438
EcsService,
3539
MarathonMatchScorerTaskLaunchResult,
@@ -206,6 +210,10 @@ export class MarathonMatchConfigService {
206210
? parsedCompileTimeout
207211
: 120000;
208212
const systemTestTimeout = this.defaultSystemTestTimeout;
213+
const submissionApiUrl = resolvePersistedSubmissionApiBaseUrl(
214+
undefined,
215+
this.challengeApiBaseUrl,
216+
);
209217
const taskDefinitionName =
210218
process.env.DEFAULT_TASK_DEFINITION_NAME?.trim() || '';
211219
const taskDefinitionVersion =
@@ -216,6 +224,7 @@ export class MarathonMatchConfigService {
216224
testTimeout,
217225
compileTimeout,
218226
systemTestTimeout,
227+
submissionApiUrl,
219228
taskDefinitionName,
220229
taskDefinitionVersion,
221230
};
@@ -265,6 +274,10 @@ export class MarathonMatchConfigService {
265274
challengeId,
266275
phaseConfigsWithBigIntSeeds,
267276
);
277+
const submissionApiUrl = resolvePersistedSubmissionApiBaseUrl(
278+
body.submissionApiUrl,
279+
this.challengeApiBaseUrl,
280+
);
268281

269282
const actor = user.isMachine ? 'System' : (user.userId ?? null);
270283
const configId = nanoid(14);
@@ -277,7 +290,7 @@ export class MarathonMatchConfigService {
277290
active: body.active,
278291
relativeScoringEnabled: body.relativeScoringEnabled,
279292
scoreDirection: body.scoreDirection,
280-
submissionApiUrl: body.submissionApiUrl,
293+
submissionApiUrl,
281294
reviewScorecardId: body.reviewScorecardId,
282295
testerId: body.testerId,
283296
testTimeout: body.testTimeout,
@@ -396,6 +409,12 @@ export class MarathonMatchConfigService {
396409
if (scalarFields.reviewScorecardId) {
397410
scalarFields.reviewScorecardId = scalarFields.reviewScorecardId.trim();
398411
}
412+
if (scalarFields.submissionApiUrl !== undefined) {
413+
scalarFields.submissionApiUrl = resolvePersistedSubmissionApiBaseUrl(
414+
scalarFields.submissionApiUrl,
415+
this.challengeApiBaseUrl,
416+
);
417+
}
399418
const phaseConfigs: MarathonMatchPhaseConfigInput[] = [
400419
{ phase: example, configType: PhaseConfigType.EXAMPLE },
401420
{ phase: provisional, configType: PhaseConfigType.PROVISIONAL },
@@ -611,14 +630,11 @@ export class MarathonMatchConfigService {
611630
);
612631
}
613632

614-
const submissionApiBaseUrl =
615-
process.env.SUBMISSION_API_URL?.trim() ||
616-
config.submissionApiUrl?.trim();
617-
if (!submissionApiBaseUrl) {
618-
throw new Error(
619-
`Submission API URL is not configured for challenge ${challengeId}.`,
620-
);
621-
}
633+
const submissionApiBaseUrl = resolveSubmissionApiBaseUrl({
634+
configuredUrl: config.submissionApiUrl,
635+
fallbackApiBaseUrl: this.challengeApiBaseUrl,
636+
environmentUrls: [this.challengeApiBaseUrl],
637+
});
622638

623639
const token = await this.m2mService.getM2MToken();
624640
if (!token) {
@@ -2355,7 +2371,11 @@ export class MarathonMatchConfigService {
23552371
active: config.active,
23562372
relativeScoringEnabled: config.relativeScoringEnabled,
23572373
scoreDirection: config.scoreDirection,
2358-
submissionApiUrl: config.submissionApiUrl,
2374+
submissionApiUrl: resolveSubmissionApiBaseUrl({
2375+
configuredUrl: config.submissionApiUrl,
2376+
fallbackApiBaseUrl: this.challengeApiBaseUrl,
2377+
environmentUrls: [this.challengeApiBaseUrl],
2378+
}),
23592379
reviewScorecardId: config.reviewScorecardId,
23602380
testerId: config.testerId,
23612381
testTimeout: config.testTimeout,

src/api/scoring-result/scoring-result.service.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
} from '@prisma/client';
1414
import { createHash } from 'crypto';
1515
import { firstValueFrom } from 'rxjs';
16+
import { resolveSubmissionApiBaseUrl } from 'src/shared/config/submission-api-url.config';
1617
import {
1718
EcsService,
1819
MarathonMatchScorerTaskLaunchResult,
@@ -731,13 +732,11 @@ export class ScoringResultService {
731732
);
732733
}
733734

734-
const submissionApiBaseUrl =
735-
process.env.SUBMISSION_API_URL?.trim() || config.submissionApiUrl?.trim();
736-
if (!submissionApiBaseUrl) {
737-
throw new Error(
738-
`Submission API URL is not configured for challenge ${challengeId}.`,
739-
);
740-
}
735+
const submissionApiBaseUrl = resolveSubmissionApiBaseUrl({
736+
configuredUrl: config.submissionApiUrl,
737+
fallbackApiBaseUrl: this.challengeApiBaseUrl,
738+
environmentUrls: [this.challengeApiBaseUrl],
739+
});
741740

742741
const token = await this.m2mService.getM2MToken();
743742
if (!token) {
@@ -1167,7 +1166,11 @@ export class ScoringResultService {
11671166

11681167
return {
11691168
challengeId: config.challengeId,
1170-
submissionApiUrl: config.submissionApiUrl.trim() || undefined,
1169+
submissionApiUrl: resolveSubmissionApiBaseUrl({
1170+
configuredUrl: config.submissionApiUrl,
1171+
fallbackApiBaseUrl: this.challengeApiBaseUrl,
1172+
environmentUrls: [this.challengeApiBaseUrl],
1173+
}),
11711174
enabled: relativeScoringEnabled === true,
11721175
scoreDirection,
11731176
};

src/api/submission-runner-log/submission-runner-log.service.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
NotFoundException,
1111
} from '@nestjs/common';
1212
import { firstValueFrom } from 'rxjs';
13+
import { resolveSubmissionApiBaseUrl } from 'src/shared/config/submission-api-url.config';
1314
import { UserRole } from 'src/shared/enums/userRole.enum';
1415
import { JwtUser } from 'src/shared/modules/global/jwt.service';
1516
import { LoggerService } from 'src/shared/modules/global/logger.service';
@@ -332,11 +333,15 @@ export class SubmissionRunnerLogService {
332333
select: { submissionApiUrl: true },
333334
});
334335

335-
return (
336-
config?.submissionApiUrl?.trim() ||
337-
process.env.SUBMISSION_API_URL?.trim() ||
338-
'https://api.topcoder-dev.com/v6'
339-
);
336+
return resolveSubmissionApiBaseUrl({
337+
configuredUrl: config?.submissionApiUrl,
338+
fallbackApiBaseUrl: process.env.CHALLENGE_API_URL,
339+
environmentUrls: [
340+
process.env.CHALLENGE_API_URL,
341+
process.env.MARATHON_MATCH_API_URL,
342+
process.env.REVIEW_API_URL,
343+
],
344+
});
340345
}
341346

342347
/**

src/dto/marathon-match-config.dto.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ export class CreateMarathonMatchConfigDto {
170170
@ApiProperty({
171171
description: 'Submission API base URL',
172172
required: false,
173-
default: 'https://api.topcoder-dev.com/v6',
174-
example: 'https://api.topcoder-dev.com/v6',
173+
default: '${CHALLENGE_API_URL}/v6',
174+
example: 'https://api.topcoder.com/v6',
175175
})
176176
@IsOptional()
177177
@IsUrl()
@@ -317,7 +317,7 @@ export class UpdateMarathonMatchConfigDto {
317317
@ApiProperty({
318318
description: 'Submission API base URL',
319319
required: false,
320-
example: 'https://api.topcoder-dev.com/v6',
320+
example: 'https://api.topcoder.com/v6',
321321
})
322322
@IsOptional()
323323
@IsUrl()
@@ -455,6 +455,13 @@ export class MarathonMatchDefaultsResponseDto {
455455
})
456456
systemTestTimeout: number;
457457

458+
@ApiProperty({
459+
description:
460+
'Default Submission API base URL used to pre-fill new configs. Must be the API base, not the /submissions collection URL.',
461+
example: 'https://api.topcoder.com/v6',
462+
})
463+
submissionApiUrl: string;
464+
458465
@ApiProperty({
459466
description:
460467
'Default ECS task definition name used to pre-fill new configs. Empty string when not configured.',
@@ -540,7 +547,7 @@ export class MarathonMatchConfigResponseDto {
540547

541548
@ApiProperty({
542549
description: 'Submission API base URL',
543-
example: 'https://api.topcoder-dev.com/v6',
550+
example: 'https://api.topcoder.com/v6',
544551
})
545552
submissionApiUrl: string;
546553

0 commit comments

Comments
 (0)