Skip to content

Commit

Permalink
Create transactions resource (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
DXRovang authored Jan 30, 2022
1 parent 467b266 commit 9639696
Show file tree
Hide file tree
Showing 17 changed files with 2,682 additions and 13,896 deletions.
16,341 changes: 2,452 additions & 13,889 deletions server/package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
"@nestjs/typeorm": "^7.1.5",
"@types/cookie-parser": "^1.4.2",
"bcrypt": "^5.0.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"config": "^3.3.6",
"cookie-parser": "^1.4.6",
"dotenv": "^10.0.0",
Expand All @@ -44,12 +46,12 @@
"passport": "^0.4.1",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"pg": "^8.5.1",
"pg": "^8.7.1",
"pg-promise": "^10.9.5",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"save": "^2.4.0",
"typeorm": "^0.2.32"
"typeorm": "^0.2.41"
},
"devDependencies": {
"@nestjs/cli": "^7.5.6",
Expand Down
2 changes: 2 additions & 0 deletions server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { AssetsModule } from './assets/assets.module';
import { MessagesModule } from './messages/messages.module';
import { UsersModule } from './users/users.module';
import { OrganizationsModule } from './organizations/organizations.module';
import { TransactionsModule } from './transactions/transactions.module';
import { CategoriesModule } from './categories/categories.module';

@Module({
Expand All @@ -28,6 +29,7 @@ import { CategoriesModule } from './categories/categories.module';
OrganizationsModule,
UsersModule,
CategoriesModule,
TransactionsModule,
],
controllers: [AppController],
providers: [],
Expand Down
7 changes: 6 additions & 1 deletion server/src/assets/entities/asset.entity.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn, OneToMany } from 'typeorm';
import { User } from '../../users/entities/user.entity';

import { AssetType, Condition } from '../constants';
import { Transaction } from '../../transactions/entities/transaction.entity';

@Entity('assets')
export class Asset {
Expand Down Expand Up @@ -32,5 +33,9 @@ export class Asset {
quantity: number;

@ManyToOne(() => User, (user) => user.assets)
@JoinColumn({ name: 'poster_id' })
poster: User;

@OneToMany(() => Transaction, (transaction) => transaction.asset)
transactions: Transaction[];
}
7 changes: 7 additions & 0 deletions server/src/auth/get-user.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { User } from 'src/users/entities/user.entity';

export const GetUser = createParamDecorator((_data, ctx: ExecutionContext): User => {
const req = ctx.switchToHttp().getRequest();
return req.user;
});
4 changes: 2 additions & 2 deletions server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { resolve } from 'path';
import * as cookieParser from 'cookie-parser';

import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

dotenv.config({ path: __dirname + '/.env' });

Expand All @@ -16,11 +17,10 @@ async function bootstrap() {
// TODO get env related base url
origin: 'http://localhost:3000',
});

app.useGlobalPipes(new ValidationPipe());
app.useStaticAssets(resolve('./src/public'));
app.setBaseViewsDir(resolve('./src/views'));
app.setViewEngine('hbs');

app.use(cookieParser('secret_placeholder'));

await app.listen(process.env.PORT || 3001);
Expand Down
10 changes: 9 additions & 1 deletion server/src/messages/entities/message.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, CreateDateColumn } from 'typeorm';
import {
Entity,
Column,
PrimaryGeneratedColumn,
ManyToOne,
CreateDateColumn,
JoinColumn,
} from 'typeorm';
import { User } from '../../users/entities/user.entity';
// import { Transaction } from '../../transactions/entities/transaction.entity'

Expand All @@ -17,6 +24,7 @@ export class Message {
created_date: Date;

@ManyToOne(() => User, (user) => user.messages, { eager: true })
@JoinColumn()
user: User;

// TODO: uncomment the code below when transactions are set up
Expand Down
9 changes: 8 additions & 1 deletion server/src/organizations/entities/organization.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm';
import { Transaction } from '../../transactions/entities/transaction.entity';

@Entity('organizations')
export class Organization {
Expand Down Expand Up @@ -31,4 +32,10 @@ export class Organization {

@Column('int')
tax_exempt_id: number;

@OneToMany(
() => Transaction,
(transaction) => transaction.donater_organization || transaction.recipient,
)
transactions: Transaction[];
}
25 changes: 25 additions & 0 deletions server/src/transactions/dto/create-transaction.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { IsNotEmpty, IsEnum, IsOptional } from 'class-validator';
import { TransactionStatus } from '../transaction-status.enum';

import type { User } from 'src/users/entities/user.entity';
import type { Organization } from 'src/organizations/entities/organization.entity';
import type { Asset } from 'src/assets/entities/asset.entity';

export class CreateTransactionDto {
@IsNotEmpty()
donater_user: User;

@IsOptional()
donater_organization: Organization;

@IsOptional()
recipient: Organization;

// custom message for example, not necessary to code
@IsNotEmpty({ message: 'asset_id is required' })
asset: Asset;

@IsOptional()
@IsEnum(TransactionStatus)
status: TransactionStatus;
}
5 changes: 5 additions & 0 deletions server/src/transactions/dto/get-transactions-filter.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PartialType } from '@nestjs/mapped-types';

import { CreateTransactionDto } from './create-transaction.dto';

export class GetTransactionsDto extends PartialType(CreateTransactionDto) {}
5 changes: 5 additions & 0 deletions server/src/transactions/dto/update-transaction.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PickType } from '@nestjs/mapped-types';

import { CreateTransactionDto } from './create-transaction.dto';

export class UpdateTransactionDto extends PickType(CreateTransactionDto, ['status'] as const) {}
44 changes: 44 additions & 0 deletions server/src/transactions/entities/transaction.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
Column,
CreateDateColumn,
Entity,
JoinColumn,
ManyToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
import { TransactionStatus } from '../transaction-status.enum';
import { User } from '../../users/entities/user.entity';
import { Asset } from '../../assets/entities/asset.entity';
import { Organization } from '../../organizations/entities/organization.entity';

@Entity('transactions')
export class Transaction {
@PrimaryGeneratedColumn()
id: number;

@Column({
type: 'enum',
enum: TransactionStatus,
default: TransactionStatus.IN_PROGRESS,
})
status: TransactionStatus;

@CreateDateColumn()
created_date: Date;

@ManyToOne((_type) => User, (user) => user.transactions)
@JoinColumn()
donater_user: User;

@ManyToOne((_type) => Organization, (organization) => organization.transactions)
@JoinColumn()
donater_organization?: Organization;

@ManyToOne((_type) => Asset, (asset) => asset.transactions, { eager: true })
@JoinColumn()
asset: Asset;

@ManyToOne((_type) => Organization, (recipient) => recipient.transactions)
@JoinColumn()
recipient: Organization;
}
5 changes: 5 additions & 0 deletions server/src/transactions/transaction-status.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum TransactionStatus {
IN_PROGRESS = 'IN_PROGRESS',
COMPLETED = 'COMPLETED',
CANCELLED = 'CANCELLED',
}
40 changes: 40 additions & 0 deletions server/src/transactions/transactions.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Controller, Post, Body, Get, Query, Param, Delete, Patch } from '@nestjs/common';

import { TransactionsService } from './transactions.service';
import { CreateTransactionDto } from './dto/create-transaction.dto';
import { Transaction } from './entities/transaction.entity';
import { GetTransactionsDto } from './dto/get-transactions-filter.dto';
import { UpdateTransactionDto } from './dto/update-transaction.dto';

@Controller('transactions')
export class TransactionsController {
constructor(private transactionsService: TransactionsService) {}

@Post()
create(@Body() createTransactionDto: CreateTransactionDto): Promise<Transaction> {
return this.transactionsService.createTransaction(createTransactionDto);
}

@Get()
get(@Query() getTransactionsDto: GetTransactionsDto): Promise<Transaction[]> {
return this.transactionsService.getTransactions(getTransactionsDto);
}

@Get('/:id')
getTransactionById(@Param('id') id: number): Promise<Transaction> {
return this.transactionsService.getTransactionById(id);
}

@Patch('/:id')
update(
@Param('id') id: number,
@Body() updateTransactionStatusDto: UpdateTransactionDto,
): Promise<Transaction> {
return this.transactionsService.updateTransaction(id, updateTransactionStatusDto);
}

@Delete('/:id')
delete(@Param('id') id: number): Promise<void> {
return this.transactionsService.deleteTransaction(id);
}
}
13 changes: 13 additions & 0 deletions server/src/transactions/transactions.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Module } from '@nestjs/common';
import { TransactionsController } from './transactions.controller';
import { TransactionsService } from './transactions.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Transaction } from './entities/transaction.entity';

@Module({
imports: [TypeOrmModule.forFeature([Transaction])],
controllers: [TransactionsController],
providers: [TransactionsService],
exports: [TransactionsService],
})
export class TransactionsModule {}
51 changes: 51 additions & 0 deletions server/src/transactions/transactions.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { CreateTransactionDto } from './dto/create-transaction.dto';
import { Transaction } from './entities/transaction.entity';
import { GetTransactionsDto } from './dto/get-transactions-filter.dto';
import { UpdateTransactionDto } from './dto/update-transaction.dto';

@Injectable()
export class TransactionsService {
constructor(
@InjectRepository(Transaction)
private transactionsRepository: Repository<Transaction>,
) {}

async createTransaction(createTransactionDto: CreateTransactionDto): Promise<Transaction> {
return this.transactionsRepository.save(createTransactionDto);
}

async getTransactions(getTransactionsDto: GetTransactionsDto): Promise<Transaction[]> {
return this.transactionsRepository.find({ where: getTransactionsDto });
}

async getTransactionById(id: number): Promise<Transaction> {
const found = await this.transactionsRepository.findOne(id);
if (!found) {
throw new NotFoundException();
}
return found;
}

async updateTransaction(
id: number,
updateTransactionDto: UpdateTransactionDto,
): Promise<Transaction> {
const transaction = await this.getTransactionById(id);
const newTransaction = await this.transactionsRepository.save({
...transaction,
...updateTransactionDto,
});
return newTransaction;
}

async deleteTransaction(id: number): Promise<void> {
const transactionToDelete = await this.transactionsRepository.delete(id);
if (transactionToDelete.affected === 0) {
throw new NotFoundException();
}
}
}
4 changes: 4 additions & 0 deletions server/src/users/entities/user.entity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm';
import { Asset } from '../../assets/entities/asset.entity';
import { Message } from '../../messages/entities/message.entity';
import { Transaction } from '../../transactions/entities/transaction.entity';

@Entity('users')
export class User {
Expand All @@ -22,6 +23,9 @@ export class User {
@OneToMany(() => Asset, (asset) => asset.poster)
assets: Asset[];

@OneToMany(() => Transaction, (transaction) => transaction.donater_user)
transactions: Transaction[];

@OneToMany(() => Message, (message) => message.user)
messages: Message[];
}

0 comments on commit 9639696

Please sign in to comment.