Skip to content

Commit 60738b0

Browse files
TaprootFreakbernd2022davidleomay
authored
Release: develop -> main (#2906)
* chore: rename master branch references to main (#2900) * chore: rename master branch references to main Update all workflow files to use 'main' instead of 'master': - api-prd.yaml: trigger on main branch - api-pr.yaml: run PR checks for main branch - codeql.yml: scan main branch - auto-release-pr.yaml: create release PRs to main * docs: fix CitreaScan branch reference (master -> main) * fix: load wallet relation for autoTradeApproval check in mail login (#2904) In completeSignInByMail(), the wallet relation was not loaded when fetching userData, causing the autoTradeApproval check in checkPendingRecommendation() to always fail. Changes: - Add wallet to relations in getUserData() call - Pass account.wallet to checkPendingRecommendation() This aligns mail-login with wallet-login behavior where the wallet is properly passed to checkPendingRecommendation(). * feat: improve local development experience for mail handling (#2905) - Skip mail sending in local environment and log mail details instead - Log mail login URL in local environment for easy testing - Add SERVICES_URL to .env.local.example for complete login URLs * fix: initialize KYC progress on mail login to set kycLevel 10 (#2903) * fix: initialize KYC progress on mail login to set kycLevel 10 Mail login users had kycLevel 0 even though their email was verified via OTP. This happened because the KYC flow was never triggered after mail login, leaving CONTACT_DATA step uncompleted. Changes: - Add initializeProgress() method to KycService that triggers updateProgress() for a given user - Call initializeProgress() in completeSignInByMail() after successful authentication Now when a user completes mail login: 1. initializeProgress() triggers updateProgress() 2. CONTACT_DATA step is auto-completed (user.mail exists) 3. PERSONAL_DATA becomes next step → kycLevel set to 10 This makes mail login behavior consistent with wallet login where adding an email triggers the same KYC flow. * fix: improve initializeProgress with retry logic and error handling - Set shouldContinue=false to only set kycLevel without initiating next KYC steps (PERSONAL_DATA) - Add Util.retry() with duplicate key check for race conditions (e.g., user double-clicks OTP link) - Make KYC initialization non-blocking in completeSignInByMail() so login succeeds even if KYC init fails * fix: correct initializeProgress to use autoStep=false The previous fix with shouldContinue=false was incorrect - it prevented any KYC progress from happening because CONTACT_DATA doesn't return a nextLevel value. The correct solution is shouldContinue=true, autoStep=false: - shouldContinue=true: allows CONTACT_DATA to be initiated and auto-completed - autoStep=false: prevents PERSONAL_DATA from being initiated (depth > 0) Flow: 1. depth=0: (autoStep || depth===0) = true → CONTACT_DATA initiated/completed 2. depth=1: (autoStep || depth===0) = false → Level 10 set, no further steps * fix: skip initializeProgress for users with CONTACT_DATA completed Prevents unintentionally initiating PERSONAL_DATA step for returning users who already have CONTACT_DATA completed. The level should already be set for these users. * chore: add migration script to fix kycLevel for edge case users 4 active users have CONTACT_DATA completed but kycLevel = 0. This SQL script updates their level to 10. Affected user IDs: 257036, 229330, 1158, 1058 * fix: make migration script safer - Comment out UPDATE statement (must be uncommented manually) - Add transaction wrapper (BEGIN/COMMIT/ROLLBACK) - Use JOIN-based UPDATE syntax for SQL Server - Add clear step-by-step instructions - Add row count verification check * fix: Start KYC process on mail add * fix: script executed --------- Co-authored-by: David May <david.leo.may@gmail.com> --------- Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Co-authored-by: bernd2022 <104787072+bernd2022@users.noreply.github.com> Co-authored-by: David May <david.leo.may@gmail.com>
2 parents b1e65c4 + d31c779 commit 60738b0

10 files changed

Lines changed: 54 additions & 16 deletions

File tree

.env.local.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ SQL_ENCRYPT=false
4444
JWT_SECRET=local-dev-secret-change-in-production
4545
JWT_EXPIRES_IN=14d
4646

47+
# Frontend URLs (for mail login redirect)
48+
SERVICES_URL=http://localhost:3000
49+
4750
# Blockchain Gateway URLs (seeds are generated by 'npm run setup')
4851
SOLANA_GATEWAY_URL=https://api.mainnet-beta.solana.com
4952
TRON_GATEWAY_URL=https://api.trongrid.io

.github/workflows/api-pr.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: API PR CI
33
on:
44
pull_request:
55
branches:
6-
- master
6+
- main
77
- develop
88
workflow_dispatch:
99

.github/workflows/api-prd.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: API PRD CI/CD
22

33
on:
44
push:
5-
branches: [master]
5+
branches: [main]
66
workflow_dispatch:
77

88
permissions:

.github/workflows/auto-release-pr.yaml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,26 @@ jobs:
2323
with:
2424
fetch-depth: 0
2525

26-
- name: Fetch master branch
27-
run: git fetch origin master
26+
- name: Fetch main branch
27+
run: git fetch origin main
2828

2929
- name: Check for existing PR
3030
id: check-pr
3131
run: |
32-
PR_COUNT=$(gh pr list --base master --head develop --state open --json number --jq 'length')
32+
PR_COUNT=$(gh pr list --base main --head develop --state open --json number --jq 'length')
3333
echo "pr_exists=$([[ $PR_COUNT -gt 0 ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
34-
echo "::notice::Open PRs from develop to master: $PR_COUNT"
34+
echo "::notice::Open PRs from develop to main: $PR_COUNT"
3535
env:
3636
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3737

3838
- name: Check for differences
3939
id: check-diff
4040
if: steps.check-pr.outputs.pr_exists == 'false'
4141
run: |
42-
DIFF_COUNT=$(git rev-list --count origin/master..origin/develop)
42+
DIFF_COUNT=$(git rev-list --count origin/main..origin/develop)
4343
echo "has_changes=$([[ $DIFF_COUNT -gt 0 ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
4444
echo "commit_count=$DIFF_COUNT" >> $GITHUB_OUTPUT
45-
echo "::notice::Commits ahead of master: $DIFF_COUNT"
45+
echo "::notice::Commits ahead of main: $DIFF_COUNT"
4646
4747
- name: Create Release PR
4848
if: steps.check-pr.outputs.pr_exists == 'false' && steps.check-diff.outputs.has_changes == 'true'
@@ -64,7 +64,7 @@ jobs:
6464
> /tmp/pr-body.md
6565
6666
gh pr create \
67-
--base master \
67+
--base main \
6868
--head develop \
69-
--title "Release: develop -> master" \
69+
--title "Release: develop -> main" \
7070
--body-file /tmp/pr-body.md

.github/workflows/codeql.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: "CodeQL Advanced"
22

33
on:
44
push:
5-
branches: [ "develop", "master" ]
5+
branches: [ "develop", "main" ]
66
pull_request:
7-
branches: [ "develop", "master" ]
7+
branches: [ "develop", "main" ]
88

99
jobs:
1010
analyze:

infrastructure/citrea/citreascan/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
1. Create the file `docker-compose-blockscout-citrea-testnet.frontend.env` in `/home/{user}`
2727
1. Copy the content of the github repo file `https://github.com/CitreaScan/frontend/blob/develop/.env.dev` in `docker-compose-blockscout-citrea-testnet.frontend.env`
2828

29-
The `docker-compose-blockscout-citrea-testnet.backend.env` and `docker-compose-blockscout-citrea-testnet.frontend.env` files are also located in the corresponding github repos. They will be overwritten by github workflows in case of changes in the `develop` or in the `master` branch.
29+
The `docker-compose-blockscout-citrea-testnet.backend.env` and `docker-compose-blockscout-citrea-testnet.frontend.env` files are also located in the corresponding github repos. They will be overwritten by github workflows in case of changes in the `develop` or in the `main` branch.
3030

3131
# Start Docker Containers
3232

src/subdomains/generic/kyc/services/kyc.service.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,13 @@ export class KycService {
430430
);
431431
}
432432

433+
async initializeProcess(userData: UserData): Promise<UserData> {
434+
const user = await this.getUser(userData.kycHash);
435+
if (user.hasDoneStep(KycStepName.CONTACT_DATA)) return user;
436+
437+
return this.updateProgress(user, true, false);
438+
}
439+
433440
public getMailFailedReason(comment: string, language: string): string {
434441
return `<ul>${comment
435442
?.split(';')

src/subdomains/generic/user/models/auth/auth.service.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import {
22
BadRequestException,
33
ConflictException,
4+
Inject,
45
Injectable,
56
NotFoundException,
67
UnauthorizedException,
8+
forwardRef,
79
} from '@nestjs/common';
810
import { JwtService } from '@nestjs/jwt';
911
import { CronExpression } from '@nestjs/schedule';
1012
import { randomUUID } from 'crypto';
11-
import { Config } from 'src/config/config';
13+
import { Config, Environment } from 'src/config/config';
1214
import { Blockchain } from 'src/integration/blockchain/shared/enums/blockchain.enum';
1315
import { CryptoService } from 'src/integration/blockchain/shared/services/crypto.service';
1416
import { GeoLocationService } from 'src/integration/geolocation/geo-location.service';
@@ -25,6 +27,7 @@ import { Util } from 'src/shared/utils/util';
2527
import { RefService } from 'src/subdomains/core/referral/process/ref.service';
2628
import { KycStepName } from 'src/subdomains/generic/kyc/enums/kyc-step-name.enum';
2729
import { KycAdminService } from 'src/subdomains/generic/kyc/services/kyc-admin.service';
30+
import { KycService } from 'src/subdomains/generic/kyc/services/kyc.service';
2831
import { MailContext, MailType } from 'src/subdomains/supporting/notification/enums';
2932
import { MailKey, MailTranslationKey } from 'src/subdomains/supporting/notification/factories/mail.factory';
3033
import { NotificationService } from 'src/subdomains/supporting/notification/services/notification.service';
@@ -87,6 +90,7 @@ export class AuthService {
8790
private readonly settingService: SettingService,
8891
private readonly recommendationService: RecommendationService,
8992
private readonly kycAdminService: KycAdminService,
93+
@Inject(forwardRef(() => KycService)) private readonly kycService: KycService,
9094
) {}
9195

9296
@DfxCron(CronExpression.EVERY_MINUTE)
@@ -255,6 +259,11 @@ export class AuthService {
255259
const key = randomUUID();
256260
const loginUrl = `${Config.frontend.services}/mail-login?otp=${key}`;
257261

262+
// Log login URL in local environment for testing
263+
if (Config.environment === Environment.LOC) {
264+
this.logger.info(`[LOCAL DEV] Mail login URL for ${dto.mail}: ${loginUrl}`);
265+
}
266+
258267
this.mailKeyList.set(key, {
259268
created: new Date(),
260269
key,
@@ -299,7 +308,7 @@ export class AuthService {
299308
const entry = this.mailKeyList.get(code);
300309
if (!this.isMailKeyValid(entry)) throw new Error('Login link expired');
301310

302-
const account = await this.userDataService.getUserData(entry.userDataId, { users: true });
311+
const account = await this.userDataService.getUserData(entry.userDataId, { users: true, wallet: true });
303312

304313
const ipLog = await this.ipLogService.create(ip, entry.loginUrl, entry.mail, undefined, account);
305314
if (!ipLog.result) throw new Error('The country of IP address is not allowed');
@@ -311,7 +320,13 @@ export class AuthService {
311320
if (account.isDeactivated)
312321
await this.userDataService.updateUserDataInternal(account, account.reactivateUserData());
313322

314-
if (!account.tradeApprovalDate) await this.checkPendingRecommendation(account);
323+
if (!account.tradeApprovalDate) await this.checkPendingRecommendation(account, account.wallet);
324+
325+
try {
326+
await this.kycService.initializeProcess(account);
327+
} catch (e) {
328+
this.logger.error(`Failed to initialize KYC process for account ${account.id}:`, e);
329+
}
315330

316331
const url = new URL(entry.redirectUri ?? `${Config.frontend.services}/account`);
317332
url.searchParams.set('session', token);

src/subdomains/generic/user/models/user-data/user-data.service.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,12 @@ export class UserDataService {
647647

648648
await this.kycLogService.createMailChangeLog(userData, userData.mail, mail);
649649

650+
try {
651+
await this.kycService.initializeProcess(userData);
652+
} catch (e) {
653+
this.logger.error(`Failed to initialize KYC process for account ${userData.id}:`, e);
654+
}
655+
650656
return userData;
651657
}
652658

src/subdomains/supporting/notification/services/mail.service.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { MailerOptions, MailerService } from '@nestjs-modules/mailer';
22
import { Injectable } from '@nestjs/common';
3+
import { Config, Environment } from 'src/config/config';
34
import { DfxLogger } from 'src/shared/services/dfx-logger';
45
import { Mail } from '../entities/mail/base/mail';
56

@@ -21,6 +22,12 @@ export class MailService {
2122
constructor(private readonly mailerService: MailerService) {}
2223

2324
async send(mail: Mail): Promise<void> {
25+
// Skip mail sending in local environment
26+
if (Config.environment === Environment.LOC) {
27+
this.logger.info(`[LOCAL DEV] Mail skipped - to: ${mail.to}, subject: ${mail.subject}`);
28+
return;
29+
}
30+
2431
try {
2532
await this.mailerService.sendMail({
2633
from: mail.from,

0 commit comments

Comments
 (0)