Skip to content

Commit

Permalink
feat: batch-create-wallet endpoint protected by csv file check
Browse files Browse the repository at this point in the history
  • Loading branch information
yunchipang committed Dec 17, 2024
1 parent d8bb927 commit f328495
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 48 deletions.
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ services:
environment:
- DATABASE_URL=postgresql://wallet_user:secret@db:5432/wallet_user
- NODE_ENV=development
- S3_BUCKET=aws-s3
- S3_REGION=aws-s3
ports:
- '3006:3006'
depends_on:
Expand Down
16 changes: 10 additions & 6 deletions src/common/utils/csvFileFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ export const csvFileFilter = (
file: Express.Multer.File,
callback: (error: Error | null, acceptFile: boolean) => void,
) => {
if (file.mimetype !== 'text/csv') {
return callback(
new BadRequestException('Only CSV files are supported.'),
false,
);
// Check for CSV MIME types or file extension
if (
file.mimetype === 'text/csv' ||
file.mimetype === 'application/csv' ||
file.mimetype === 'application/vnd.ms-excel' ||
file.originalname.toLowerCase().endsWith('.csv')
) {
callback(null, true);
} else {
callback(new BadRequestException('Only CSV files are supported.'), false);
}
callback(null, true);
};
5 changes: 5 additions & 0 deletions src/modules/event/event-enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export enum EVENT_TYPES {
transfer_completed = 'transfer_completed',
transfer_requested = 'transfer_requested',
transfer_request_cancelled_by_destination = 'transfer_request_cancelled_by_destination',
transfer_request_cancelled_by_source = 'transfer_request_cancelled_by_source',
transfer_request_cancelled_by_originator = 'transfer_request_cancelled_by_originator',
transfer_pending_cancelled_by_source = 'transfer_pending_cancelled_by_source',
transfer_pending_cancelled_by_destination = 'transfer_pending_cancelled_by_destination',
transfer_pending_cancelled_by_requestor = 'transfer_pending_cancelled_by_requestor',
transfer_failed = 'transfer_failed',

Expand All @@ -14,6 +18,7 @@ export enum EVENT_TYPES {
trust_request_granted = 'trust_request_granted',
trust_request_cancelled_by_target = 'trust_request_cancelled_by_target',
trust_request_cancelled_by_originator = 'trust_request_cancelled_by_originator',
trust_request_cancelled_by_actor = 'trust_request_cancelled_by_actor',

// WALLET_EVENTS
wallet_created = 'wallet_created',
Expand Down
7 changes: 4 additions & 3 deletions src/modules/token/token.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { TokenRepository } from './token.repository';
import { TokenService } from './token.service';
import { TransactionModule } from '../transaction/transaction.module';
import { Token } from './entity/token.entity';

@Module({
imports: [TypeOrmModule.forFeature([TokenRepository]), TransactionModule],
providers: [TokenService],
exports: [TokenService],
imports: [TypeOrmModule.forFeature([Token]), TransactionModule],
providers: [TokenRepository, TokenService],
exports: [TokenRepository, TokenService],
})
export class TokenModule {}
7 changes: 4 additions & 3 deletions src/modules/trust/trust.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TrustRepository } from './trust.repository';
import { TrustService } from './trust.service';
import { Trust } from './entity/trust.entity';

@Module({
imports: [TypeOrmModule.forFeature([TrustRepository])],
providers: [TrustService],
exports: [TrustService],
imports: [TypeOrmModule.forFeature([Trust])],
providers: [TrustRepository, TrustService],
exports: [TrustRepository, TrustService],
})
export class TrustModule {}
27 changes: 13 additions & 14 deletions src/modules/wallet/dto/batch-create-wallet.dto.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import {
IsString,
IsArray,
IsOptional,
ValidateNested,
IsNumber,
Validate,
} from 'class-validator';
import { Type } from 'class-transformer';
import { UniqueWalletNameConstraint, CsvItemDto } from './csv-item.dto';
import { IsString, IsOptional, IsNumber, ValidateIf } from 'class-validator';
import { Transform } from 'class-transformer';
import { CsvItemDto } from './csv-item.dto';

export class BatchCreateWalletDto {
@IsString()
Expand All @@ -16,16 +9,22 @@ export class BatchCreateWalletDto {

@IsNumber()
@IsOptional()
@ValidateIf((o) => o.token_transfer_amount_default !== undefined)
@Transform(({ value }) => {
if (value === '') return undefined;
const num = Number(value);
return isNaN(num) ? value : num;
})
token_transfer_amount_default: number;

@IsString()
@IsOptional()
wallet_id: string;

@IsArray()
@Validate(UniqueWalletNameConstraint)
@ValidateNested({ each: true })
@Type(() => CsvItemDto)
// @IsArray()
// @Validate(UniqueWalletNameConstraint)
// @ValidateNested({ each: true })
// @Type(() => CsvItemDto)
csvJson: CsvItemDto[];

@IsString()
Expand Down
9 changes: 8 additions & 1 deletion src/modules/wallet/dto/csv-item.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export class UniqueWalletNameConstraint
implements ValidatorConstraintInterface
{
validate(csvJson: CsvItemDto[]): boolean {
if (!csvJson || !Array.isArray(csvJson)) {
return false;
}
const walletNames = csvJson.map((item) => item.wallet_name);
return walletNames.length === new Set(walletNames).size;
}
Expand All @@ -33,5 +36,9 @@ export class CsvItemDto {

@IsOptional()
@IsString()
extra_wallet_data_about?: string;
extra_wallet_data_logo_url?: string;

@IsOptional()
@IsString()
extra_wallet_data_cover_url?: string;
}
56 changes: 38 additions & 18 deletions src/modules/wallet/wallet.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
BadRequestException,
Body,
Controller,
Get,
Expand All @@ -23,6 +24,9 @@ import * as csvtojson from 'csvtojson';
import { BatchCreateWalletDto } from './dto/batch-create-wallet.dto';
import { BatchTransferWalletDto } from './dto/batch-transfer-wallet.dto';
import { CsvFileUploadInterceptor } from '../../common/interceptors/csvFileUpload.interceptor';
import { plainToClass } from 'class-transformer';
import { CsvItemDto } from './dto/csv-item.dto';
import { validate } from 'class-validator';

export const imageUpload = multer({
fileFilter: (req, file, cb) => {
Expand Down Expand Up @@ -94,26 +98,42 @@ export class WalletController {
@Body() batchCreateWalletDto: BatchCreateWalletDto,
@UploadedFile() file: Express.Multer.File,
) {
const { path } = file;
const csvJson = await csvtojson().fromFile(path);
batchCreateWalletDto.csvJson = csvJson;
batchCreateWalletDto.filePath = path;
if (!file) {
throw new BadRequestException('CSV file is required');
}

const {
sender_wallet,
token_transfer_amount_default,
wallet_id,
csvJson: validatedCsvJson,
filePath,
} = batchCreateWalletDto;
try {
const csvJson = await csvtojson().fromFile(file.path);

return await this.walletService.batchCreateWallet(
sender_wallet,
token_transfer_amount_default,
wallet_id,
validatedCsvJson,
filePath,
);
// Validate CSV data
const csvItems = csvJson.map((item) => plainToClass(CsvItemDto, item));
const errors = await validate(csvItems);
if (errors.length > 0) {
throw new BadRequestException(errors);
}

// Check for unique wallet names
const walletNames = csvItems.map((item) => item.wallet_name);
if (walletNames.length !== new Set(walletNames).size) {
throw new BadRequestException(
'Each wallet_name in csvJson must be unique.',
);
}

batchCreateWalletDto.csvJson = csvItems;
batchCreateWalletDto.filePath = file.path;

const result = await this.walletService.batchCreateWallet(
batchCreateWalletDto.sender_wallet,
batchCreateWalletDto.token_transfer_amount_default,
batchCreateWalletDto.wallet_id,
batchCreateWalletDto.csvJson,
batchCreateWalletDto.filePath,
);
return result;
} catch (error) {
throw error;
}
}

@Post('batch-transfer')
Expand Down
9 changes: 6 additions & 3 deletions src/modules/wallet/wallet.module.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import { forwardRef, Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { WalletController } from './wallet.controller';
import { WalletService } from './wallet.service';
import { WalletRepository } from './wallet.repository';
import { TokenModule } from '../token/token.module';
import { TrustModule } from '../trust/trust.module';
import { EventModule } from '../event/event.module';
import { S3Service } from '../../common/services/s3.service';
import { TransferModule } from '../transfer/transfer.module';
import { Wallet } from './entity/wallet.entity';

@Module({
imports: [
TypeOrmModule.forFeature([WalletRepository]),
TypeOrmModule.forFeature([Wallet]),
forwardRef(() => TransferModule),
EventModule,
TokenModule,
TrustModule,
],
providers: [WalletService, S3Service],
exports: [WalletService],
controllers: [WalletController],
providers: [WalletRepository, WalletService, S3Service],
exports: [WalletRepository, WalletService],
})
export class WalletModule {}
10 changes: 10 additions & 0 deletions src/modules/wallet/wallet.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,9 @@ export class WalletService {
} of walletsToCreate) {
const newWallet = await this.createWallet(wallet_id, walletName);

// debug
console.log('checkpoint 1');

if (amount && senderWallet) {
await this.transferService.transferBundle(
wallet_id,
Expand All @@ -425,6 +428,9 @@ export class WalletService {
);
}

// debug
console.log('checkpoint 2');

if (extra_wallet_data_logo_url || extra_wallet_data_cover_url) {
await this.addWalletToMapConfig({
walletId: newWallet.id,
Expand All @@ -433,6 +439,10 @@ export class WalletService {
walletCoverUrl: extra_wallet_data_cover_url,
});
}

// debug
console.log('checkpoint 3');

createdWallets.push(newWallet);
}

Expand Down

0 comments on commit f328495

Please sign in to comment.