Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bid model + Create Bid + Active landing page bid response #99

Merged
merged 17 commits into from
Oct 25, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
840b689
feat-wip(bid): add bid model, get auction bids endpoint and service
vikinatora Oct 18, 2021
5efe018
feat(place-bid): add bid model, temp bidding functionality and upgrad…
vikinatora Oct 19, 2021
bbaeeb5
fix(bid-entity): combine the two migration files into a single on
vikinatora Oct 20, 2021
291e813
fix(auction-page): more active auctions returns only active, removed …
vikinatora Oct 20, 2021
1fedf7c
improve(bids): add get user bids endpoint, change auction page link, …
vikinatora Oct 22, 2021
8648706
fix(auction-page): reversed start and end date queries
vikinatora Oct 22, 2021
6869227
improve(my-bids): optimize queries and make code more readable and or…
vikinatora Oct 22, 2021
02710a6
Merge branch 'dev' into auctions
vikinatora Oct 22, 2021
5603fd7
refactor: remove unnecessary bidder grouping function
vikinatora Oct 22, 2021
502ac55
Merge branch 'auctions' of https://github.com/UniverseXYZ/UniverseApp…
vikinatora Oct 22, 2021
98fb06a
fix(my-bids): fix min and max bids query
vikinatora Oct 22, 2021
2ec0fdc
fix(my-bids): add auction creator info to auction response
vikinatora Oct 22, 2021
c92b930
optimize(my-bids): merge bid table queries together
vikinatora Oct 22, 2021
f238390
improve(my-bids): reduce .find() calls
vikinatora Oct 22, 2021
bee7ae5
improve(my-active-auctions): add bids response
vikinatora Oct 25, 2021
d4a843b
improve(past-auctions): add bids info to past auctions endpoint
vikinatora Oct 25, 2021
accdd0f
fix(active-auction-page): return all bids for the auction
vikinatora Oct 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions migrations/1634645086422-AuctionBid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";

export class AuctionBid1634645086422 implements MigrationInterface {
name = 'AuctionBid1634645086422'

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "universe-backend"."auction_bid" ("id" SERIAL NOT NULL, "userId" integer NOT NULL, "auctionId" integer NOT NULL, "amount" numeric NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_022e4f8fe9416b6f1e13c55cdfb" PRIMARY KEY ("id"))`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "universe-backend"."auction_bid"`);
}

}
3 changes: 2 additions & 1 deletion src/modules/auction/auction.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { MulterConfigService } from '../multer/multer.service';
import { Nft } from '../nft/domain/nft.entity';
import { User } from '../users/user.entity';
import { Auction } from './domain/auction.entity';
import { AuctionBid } from './domain/auction.bid.entity';
import { RewardTierNft } from './domain/reward-tier-nft.entity';
import { RewardTier } from './domain/reward-tier.entity';
import { AuctionController } from './entrypoints/auction.controller';
Expand All @@ -22,7 +23,7 @@ import { NftCollection } from '../nft/domain/collection.entity';
MulterModule.registerAsync({
useClass: MulterConfigService,
}),
TypeOrmModule.forFeature([User, Auction, RewardTier, RewardTierNft, Nft, NftCollection]),
TypeOrmModule.forFeature([User, Auction, RewardTier, RewardTierNft, Nft, NftCollection, AuctionBid]),
FileSystemModule,
UsersModule,
],
Expand Down
24 changes: 24 additions & 0 deletions src/modules/auction/domain/auction.bid.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Exclude } from 'class-transformer';
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity({
schema: 'universe-backend',
})
export class AuctionBid {
@PrimaryGeneratedColumn()
id: number;

@Column()
@Exclude()
userId: number;

@Column()
@Exclude()
auctionId: number;

@Column({ type: 'decimal' })
amount: number;

@CreateDateColumn()
createdAt: Date;
}
13 changes: 13 additions & 0 deletions src/modules/auction/entrypoints/auction.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
GetAuctionPageParams,
GetMyAuctionsQuery,
GetMyAuctionsResponse,
PlaceBidBody,
UpdateAuctionExtraBody,
UpdateRewardTierBody,
UpdateRewardTierExtraBody,
Expand Down Expand Up @@ -284,6 +285,18 @@ export class AuctionController {
return await this.auctionService.listAuctionsByStatus(status, page, limit);
}

@Post('auctions/bid')
@UseGuards(JwtAuthGuard)
async placeAuctionBid(@Req() req, @Body() placeBidBody: PlaceBidBody) {
return await this.auctionService.placeAuctionBid(req.user.sub, placeBidBody);
}

@Get('auctions/bids')
@UseGuards(JwtAuthGuard)
async getAuctionBids(@Req() req, @Query('auctionId') auctionId: number) {
return await this.auctionService.getAuctionBids(auctionId);
}

//Todo: add tier info
@Get('auction/{:id}')
@UseGuards(JwtAuthGuard)
Expand Down
23 changes: 23 additions & 0 deletions src/modules/auction/entrypoints/dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,3 +660,26 @@ export class GetAuctionPageParams {
@IsString()
auctionName: string;
}

export class PlaceBidBody {
@ApiProperty({
example: 1,
description: 'The id of the auction to which the user is bidding',
})
@IsNumber()
auctionId: number;

@ApiProperty({
example: '0.1',
description: 'Amount of crypto the user is bidding',
})
@IsNumber()
amount: number;

// @ApiProperty({
// example: '0.1',
// description: 'The crypto currency the user is bidding',
// })
// @IsString()
// currency: string;
}
62 changes: 55 additions & 7 deletions src/modules/auction/service-layer/auction.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable } from '@nestjs/common';
import { getManager, In, LessThan, MoreThan, Repository, Transaction, TransactionRepository } from 'typeorm';
import { getManager, In, LessThan, MoreThan, Not, Repository, Transaction, TransactionRepository } from 'typeorm';
import { RewardTier } from '../domain/reward-tier.entity';
import { RewardTierNft } from '../domain/reward-tier-nft.entity';
import { Auction } from '../domain/auction.entity';
Expand All @@ -13,6 +13,7 @@ import {
EditAuctionBody,
UpdateRewardTierBody,
DepositNftsBody,
PlaceBidBody,
} from '../entrypoints/dto';
import { Nft } from 'src/modules/nft/domain/nft.entity';
import { AuctionNotFoundException } from './exceptions/AuctionNotFoundException';
Expand All @@ -24,6 +25,8 @@ import { UsersService } from '../../users/users.service';
import { classToPlain } from 'class-transformer';
import { UploadResult } from 'src/modules/file-storage/model/UploadResult';
import { NftCollection } from 'src/modules/nft/domain/collection.entity';
import { AuctionBid } from '../domain/auction.bid.entity';
import { User } from 'src/modules/users/user.entity';

@Injectable()
export class AuctionService {
Expand All @@ -39,6 +42,8 @@ export class AuctionService {
private nftCollectionRepository: Repository<NftCollection>,
@InjectRepository(Nft)
private nftRepository: Repository<Nft>,
@InjectRepository(AuctionBid)
private auctionBidRepository: Repository<AuctionBid>,
private s3Service: S3Service,
private fileSystemService: FileSystemService,
private readonly config: AppConfig,
Expand All @@ -55,21 +60,20 @@ export class AuctionService {
throw new AuctionNotFoundException();
}

// TODO: Add collection info for each nft
// TODO: Add collection info for each nft(Maybe won't be needed)
const rewardTiers = await this.rewardTierRepository.find({ where: { auctionId: auction.id } });
const rewardTierNfts = await this.rewardTierNftRepository.find({
where: { rewardTierId: In(rewardTiers.map((rewardTier) => rewardTier.id)) },
});

const nftIds = rewardTierNfts.map((rewardTierNft) => rewardTierNft.nftId);
// console.log(nftIds);

const nfts = await this.nftRepository.find({ where: { id: In(nftIds) } });
const nftCollectionids = nfts.map((nft) => nft.collectionId);

const collections = await this.nftCollectionRepository.find({ id: In(nftCollectionids) });
const idNftMap = nfts.reduce((acc, nft) => ({ ...acc, [nft.id]: nft }), {} as Record<string, Nft>);
// console.log(idNftMap);

const rewardTierNftsMap = rewardTierNfts.reduce(
(acc, rewardTierNft) => ({
...acc,
Expand All @@ -78,16 +82,30 @@ export class AuctionService {
{} as Record<string, Nft[]>,
);

//TODO: Add pagination to this query to reduce the load on the BE
// https://github.com/UniverseXYZ/UniverseApp-Backend/issues/100
const now = new Date().toISOString();
const moreActiveAuctions = await this.auctionRepository.find({
where: { userId: artist.id, id: Not(auction.id), startDate: MoreThan(now), endDate: LessThan(now) },
});

const bids = await this.auctionBidRepository
.createQueryBuilder('bid')
.leftJoinAndMapOne('bid.user', User, 'bidder', 'bidder.id = bid.userId')
.where({ auctionId: auction.id })
.orderBy('bid.amount', 'DESC')
.getMany();

return {
auction: classToPlain(auction),
auction: auction,
artist: classToPlain(artist),
collections: classToPlain(collections),
rewardTiers: rewardTiers.map((rewardTier) => ({
...classToPlain(rewardTier),
nfts: rewardTierNftsMap[rewardTier.id].map((nft) => classToPlain(nft)),
})),
bids: [],
moreActiveAuctions: [],
moreActiveAuctions: moreActiveAuctions.map((a) => classToPlain(a)),
bids: bids,
};
}

Expand Down Expand Up @@ -729,6 +747,36 @@ export class AuctionService {
};
}

public async getAuctionBids(auctionId: number) {
//TODO: Add results limit to get only (reward tiers * reward tier slots)
const bids = await this.auctionBidRepository.find({ where: { auctionId: auctionId }, order: { amount: 'DESC' } });

return {
bids: bids.map((bid) => classToPlain(bid)),
};
}

public async placeAuctionBid(userId: number, placeBidBody: PlaceBidBody) {
//TODO: This is a temporartu endpoint until the scraper functionality is finished
const bidder = await this.usersService.getById(userId);
const auction = await this.auctionRepository.findOne(placeBidBody.auctionId);

if (!auction) {
throw new AuctionNotFoundException();
}

const bid = await this.auctionBidRepository.save({
userId: userId,
amount: placeBidBody.amount,
auctionId: placeBidBody.auctionId,
});

const response = { ...bid, user: bidder };
return {
bid: response,
};
}

private setPagination(query, page: number, limit: number) {
if (limit === 0 || page === 0) return;

Expand Down
2 changes: 2 additions & 0 deletions src/modules/database/database.providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { DeployCollectionEvent } from '../ethEventsScraper/domain/deploy-collect
import { MintingCollection } from '../nft/domain/minting-collection.entity';
import { LoginChallenge } from '../auth/model/login-challenge.entity';
import { MintingNft } from '../nft/domain/minting-nft.entity';
import { AuctionBid } from '../auction/domain/auction.bid.entity';

// TODO: Add db entities here
const entities = [
Expand All @@ -28,6 +29,7 @@ const entities = [
MintingCollection,
LoginChallenge,
MintingNft,
AuctionBid,
];

@Injectable()
Expand Down