Skip to content

Commit abd573e

Browse files
authored
Merge pull request #106 from topcoder-platform/v6
V6 -> dev
2 parents cbfe4f9 + 41b4914 commit abd573e

34 files changed

+1493
-251
lines changed

.circleci/config.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
environment:
5252
DEPLOY_ENV: 'DEV'
5353
LOGICAL_ENV: 'dev'
54-
APPNAME: 'tc-finance-api'
54+
APPNAME: 'finance-api-v6'
5555
DEPLOYMENT_ENVIRONMENT: 'dev'
5656
steps: *build_and_deploy_steps
5757

@@ -60,7 +60,7 @@ jobs:
6060
environment:
6161
DEPLOY_ENV: 'PROD'
6262
LOGICAL_ENV: 'prod'
63-
APPNAME: 'tc-finance-api'
63+
APPNAME: 'finance-api-v6'
6464
DEPLOYMENT_ENVIRONMENT: 'prod'
6565
steps: *build_and_deploy_steps
6666

@@ -74,10 +74,10 @@ workflows:
7474
branches:
7575
only:
7676
- dev
77-
- npm-module-updates
77+
- v6
7878
- 'build-prod':
7979
context: org-global
8080
filters:
8181
branches:
8282
only:
83-
- master
83+
- master

.env.sample

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
TOPCODER_API_BASE_URL="https://api.topcoder-dev.com/v5"
1+
TOPCODER_API_V5_BASE_URL="https://api.topcoder-dev.com/v5"
2+
TOPCODER_API_V6_BASE_URL="https://api.topcoder-dev.com/v6"
23
AUTH0_CERT="-----BEGIN RSA PUBLIC KEY-----
34
MIIBCgKCAQEArAV0dmDkedFdlaQ6KQiqUv+UGshfMXx/4jJCLZ9802ynJqAvIt+Z
45
V7EiPqjc2J1xVfJJEvQ9ZS5A2TFWAk16NUTU4LN+TkjEnqeg+LlUPWY3Y4RXa2OU
@@ -15,4 +16,4 @@ DB_PASSWORD=randompassword
1516
DB_HOST=127.0.0.1
1617
DB_PORT=5434
1718
DB_NAME=walletdb
18-
DATABASE_URL="postgresql://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
19+
DATABASE_URL="postgresql://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
Warnings:
3+
4+
- You are about to drop the `reward` table. If the table is not empty, all the data it contains will be lost.
5+
6+
*/
7+
-- DropForeignKey
8+
ALTER TABLE "reward" DROP CONSTRAINT "reward_winnings_id_fkey";
9+
10+
-- DropTable
11+
DROP TABLE "reward";
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
Warnings:
3+
4+
- You are about to drop the `payoneer_payment_method` table. If the table is not empty, all the data it contains will be lost.
5+
- You are about to drop the `paypal_payment_method` table. If the table is not empty, all the data it contains will be lost.
6+
7+
*/
8+
-- DropForeignKey
9+
ALTER TABLE "payoneer_payment_method" DROP CONSTRAINT "fk_payoneer_user_payment_method";
10+
11+
-- DropForeignKey
12+
ALTER TABLE "paypal_payment_method" DROP CONSTRAINT "fk_paypal_user_payment_method";
13+
14+
-- DropTable
15+
DROP TABLE "payoneer_payment_method";
16+
17+
-- DropTable
18+
DROP TABLE "paypal_payment_method";
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CREATE TABLE "challenge_lock" (
2+
"id" SERIAL PRIMARY KEY,
3+
"external_id" VARCHAR(255) NOT NULL UNIQUE,
4+
"lock_time" TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
5+
"error" TEXT
6+
);

prisma/schema.prisma

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -103,45 +103,11 @@ model payment_releases {
103103
payment_method payment_method @relation(fields: [payment_method_id], references: [payment_method_id], onDelete: NoAction, onUpdate: NoAction)
104104
}
105105

106-
model payoneer_payment_method {
107-
id Int @id @default(autoincrement())
108-
user_payment_method_id String? @db.Uuid
109-
user_id String @unique @db.VarChar(80)
110-
payee_id String @db.VarChar(50)
111-
payoneer_id String? @db.VarChar(50)
112-
user_payment_methods user_payment_methods? @relation(fields: [user_payment_method_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "fk_payoneer_user_payment_method")
113-
}
114-
115-
model paypal_payment_method {
116-
id Int @id @default(autoincrement())
117-
user_payment_method_id String? @db.Uuid
118-
user_id String @unique @db.VarChar(80)
119-
email String? @db.VarChar(150)
120-
payer_id String? @db.VarChar(50)
121-
country_code String? @db.VarChar(2)
122-
user_payment_methods user_payment_methods? @relation(fields: [user_payment_method_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "fk_paypal_user_payment_method")
123-
}
124-
125-
model reward {
126-
reward_id String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
127-
winnings_id String @db.Uuid
128-
points Int?
129-
title String? @db.VarChar(255)
130-
description String?
131-
reference Json?
132-
attributes Json?
133-
created_at DateTime? @default(now()) @db.Timestamp(6)
134-
updated_at DateTime? @default(now()) @db.Timestamp(6)
135-
winnings winnings @relation(fields: [winnings_id], references: [winning_id], onDelete: NoAction, onUpdate: NoAction)
136-
}
137-
138106
model user_payment_methods {
139107
id String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
140108
user_id String @db.VarChar(80)
141109
payment_method_id Int
142110
status payment_method_status? @default(OTP_PENDING)
143-
payoneer_payment_method payoneer_payment_method[]
144-
paypal_payment_method paypal_payment_method[]
145111
trolley_payment_method trolley_recipient[]
146112
payment_method payment_method @relation(fields: [payment_method_id], references: [payment_method_id], onDelete: NoAction, onUpdate: NoAction, map: "fk_user_payment_method")
147113
@@ -172,7 +138,6 @@ model winnings {
172138
updated_at DateTime? @default(now()) @db.Timestamp(6)
173139
audit audit[]
174140
payment payment[]
175-
reward reward[]
176141
origin origin? @relation(fields: [origin_id], references: [origin_id], onDelete: NoAction, onUpdate: NoAction)
177142
178143
@@index([category, created_at(sort: Desc)], map: "idx_winnings_category_created_at")
@@ -223,6 +188,13 @@ model trolley_recipient_payment_method {
223188
trolley_recipient trolley_recipient @relation(fields: [trolley_recipient_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "fk_trolley_recipient_trolley_recipient_payment_method")
224189
}
225190

191+
model challenge_lock {
192+
id Int @id @default(autoincrement())
193+
external_id String @unique @db.VarChar(255)
194+
lock_time DateTime @default(now()) @db.Timestamp(6)
195+
error String? @db.Text
196+
}
197+
226198
enum verification_status {
227199
ACTIVE
228200
INACTIVE

src/api/admin/admin.service.ts

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ import { ResponseDto } from 'src/dto/api-response.dto';
1313
import { PaymentStatus } from 'src/dto/payment.dto';
1414
import { WinningAuditDto, AuditPayoutDto } from './dto/audit.dto';
1515
import { WinningUpdateRequestDto } from './dto/winnings.dto';
16-
import {
17-
AdminPaymentUpdateData,
18-
TopcoderChallengesService,
19-
} from 'src/shared/topcoder/challenges.service';
16+
import { TopcoderChallengesService } from 'src/shared/topcoder/challenges.service';
2017
import { Logger } from 'src/shared/global';
2118

2219
function formatDate(date = new Date()) {
@@ -317,30 +314,6 @@ export class AdminService {
317314
}
318315
});
319316

320-
transactions.push(async () => {
321-
const winning = await this.getWinningById(winningsId);
322-
if (!winning) {
323-
this.logger.error(
324-
`Error updating legacy system for winning ${winningsId}. Winning not found!`,
325-
);
326-
throw new Error(
327-
`Error updating legacy system for winning ${winningsId}. Winning not found!`,
328-
);
329-
}
330-
331-
const payoutData: AdminPaymentUpdateData = {
332-
userId: +winning.winner_id,
333-
status: body.paymentStatus,
334-
amount: body.paymentAmount,
335-
releaseDate: formatDate(new Date(body.releaseDate)),
336-
};
337-
338-
await this.tcChallengesService.updateLegacyPayments(
339-
winning.external_id as string,
340-
payoutData,
341-
);
342-
});
343-
344317
// Run all transaction tasks in a single prisma transaction
345318
await this.prisma.$transaction(async (tx) => {
346319
for (const transaction of transactions) {

src/api/api.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import { WinningsModule } from './winnings/winnings.module';
1717
import { UserModule } from './user/user.module';
1818
import { WalletModule } from './wallet/wallet.module';
1919
import { WithdrawalModule } from './withdrawal/withdrawal.module';
20+
import { ChallengesModule } from './challenges/challenges.module';
21+
import { ChallengePaymentsModule } from './challenge-payments/challenge-payments.module';
2022

2123
@Module({
2224
imports: [
@@ -26,9 +28,11 @@ import { WithdrawalModule } from './withdrawal/withdrawal.module';
2628
WebhooksModule,
2729
AdminModule,
2830
WinningsModule,
31+
ChallengePaymentsModule,
2932
UserModule,
3033
WalletModule,
3134
WithdrawalModule,
35+
ChallengesModule,
3236
],
3337
controllers: [HealthCheckController],
3438
providers: [
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {
2+
Controller,
3+
Get,
4+
Param,
5+
Query,
6+
Req,
7+
} from '@nestjs/common';
8+
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
9+
import { AllowedM2mScope, Roles, User } from 'src/core/auth/decorators';
10+
import { M2mScope, Role } from 'src/core/auth/auth.constants';
11+
import { UserInfo } from 'src/dto/user.type';
12+
import { ChallengePaymentsService } from './challenge-payments.service';
13+
14+
@ApiTags('Payments')
15+
@Controller('/challenge-payments')
16+
@ApiBearerAuth()
17+
export class ChallengePaymentsController {
18+
constructor(
19+
private readonly challengePaymentsService: ChallengePaymentsService,
20+
) {}
21+
22+
@Get('/:challengeId')
23+
@AllowedM2mScope(M2mScope.ReadPayments, M2mScope.CreatePayments)
24+
@Roles(Role.PaymentAdmin, Role.PaymentEditor, Role.PaymentViewer, Role.User)
25+
@ApiOperation({
26+
summary:
27+
'List payments (winnings) for a challenge with role-aware filtering',
28+
})
29+
async getChallengePayments(
30+
@Param('challengeId') challengeId: string,
31+
@Query('winnerOnly') winnerOnly: string | undefined,
32+
@User() user: UserInfo,
33+
@Req() req: any,
34+
) {
35+
return this.challengePaymentsService.listChallengePayments({
36+
challengeId,
37+
requestUserId: user?.id,
38+
isMachineToken: Boolean(req?.m2mTokenScope),
39+
winnerOnly: (winnerOnly || '').toLowerCase() === 'true',
40+
auth0User: req?.auth0User,
41+
});
42+
}
43+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Module } from '@nestjs/common';
2+
import { ChallengePaymentsController } from './challenge-payments.controller';
3+
import { ChallengePaymentsService } from './challenge-payments.service';
4+
import { TopcoderModule } from 'src/shared/topcoder/topcoder.module';
5+
6+
@Module({
7+
imports: [TopcoderModule],
8+
controllers: [ChallengePaymentsController],
9+
providers: [ChallengePaymentsService],
10+
})
11+
export class ChallengePaymentsModule {}

0 commit comments

Comments
 (0)