들어가기
order를 확인하는 API
role에 따라 defensive를 해줘야 해서 햇갈릴 수 있으니 집중
get order와 get orders를 같이 다룬다.
import { Field, InputType, ObjectType, PickType } from '@nestjs/graphql';
import { MutationOutput } from 'src/common/dtos/output.dto';
import { Order } from '../entities/order.entity';
@InputType()
export class GetOrderInput extends PickType(Order, ['id']) {}
///Order entity의 id만 pick한다
@ObjectType()
export class GetOrderOutput extends MutationOutput {
@Field(() => Order, { nullable: true })
order?: Order;
}
///order를 return 받는다.
import { Field, InputType, ObjectType } from '@nestjs/graphql';
import { MutationOutput } from 'src/common/dtos/output.dto';
import { Order, OrderStatus } from '../entities/order.entity';
@InputType()
export class GetOrdersInput {
@Field(() => OrderStatus, { nullable: true })
status?: OrderStatus;
}
///get Orders는 status(Pending, Cooking, Cooked등으로 분류할 수 있게 설정)
@ObjectType()
export class GetOrdersOutput extends MutationOutput {
@Field(() => [Order], { nullable: true })
orders?: Order[];
}
///Order배열을 return 받는다.
@Query(() => GetOrdersOutput)
@Role(['Any'])
async getOrders(
@AuthUser() user: User,
@Args('input') getOrdersInput: GetOrdersInput,
): Promise<GetOrdersOutput> {
return this.ordersService.getOrders(user, getOrdersInput);
}
///user(loggedInUser)와 getOrdersInput을 입력받는다
///Role은 loggedInUser는 다 볼수 있게 Any로
@Query(() => GetOrderOutput)
@Role(['Any'])
async getOrder(
@AuthUser() user: User,
@Args('input') getOrderInput: GetOrderInput,
): Promise<GetOrderOutput> {
return this.ordersService.getOrder(user, getOrderInput);
}
///user(loggedInUser)와 getOrdersInput을 입력받는다
///Role은 loggedInUser는 다 볼수 있게 Any로
async getOrders(
user: User,
{ status }: GetOrdersInput,
): Promise<GetOrdersOutput> {
try {
let orders: Order[];
if (user.role === UserRole.Client) {
orders = await this.orders.find({
where: {
customer: user,
...(status && { status }),
},
});
///orders를 let으로 배열로 일단 선언해 놓는다.
///input받은 user의 role이 Client이면,
///where:{ customer이 user인 곳에서 order를 찾는다.
///이어서 status(orderStatus)를 입력 받았으면,
///그에 맞는 status의 order만 분류한다.(pending, cooking, cooked...)
} else if (user.role === UserRole.Delivery) {
orders = await this.orders.find({
where: {
driver: user,
...(status && { status }),
},
});
///input받은 user의 role이 Delivery,
///where:{ driver가 user인 곳에서 order를 찾는다.
///이어서 status(orderStatus)를 입력 받았으면,
///그에 맞는 status의 order만 분류한다.(pending, cooking, cooked...)
} else if (user.role === UserRole.Owner) {
const restaurants = await this.restaurants.find({
where: {
owner: user,
},
relations: ['orders'],
});
///loggedInUser가 owner이면, 식당을 찾는다, 그리고 relations로
///식당과 relation된 orders repository를 불러들인다.
orders = restaurants.map((restaurant) => restaurant.orders).flat(1);
///owner가 식당을 여러개 가지고 있을 수 있기때문에,
///식당 여러개의 배열, 즉, 식당배열에 각 식당에 대한 order배열..
///2차원 배열을 .flat(1) 명령어로 orders를 1차원화 시킨다.
if (status) {
orders = orders.filter((order) => order.status === status);
}
///위에서 찾은 orders에서, status가 같이 입력됬다면,
///위에서 찾은 order에서 order.status가 입력된 status와 같은
///것만 filter한다.
}
return {
ok: true,
orders,
};
///마지막으로 위애서 찾은 orders들을 return해준다.
} catch {
return {
ok: false,
error: 'Could not got orders',
};
}
}
canSeeOrder(user: User, order: Order): boolean {
let canSee = true;
if (user.role === UserRole.Client && order.customnerId !== user.id) {
canSee = false;
}
if (user.role === UserRole.Delivery && order.driverId !== user.id) {
canSee = false;
}
if (user.role === UserRole.Owner && order.restaurant.ownerId !== user.id) {
canSee = false;
}
return canSee;
}
///getOrder에서 사용하기 위해 만든 API
/// user와 order를 압력받아서 조건에 따라 true, false를 return함.
///order의 customerId, driverId, restaurant.ownerId 와 loggedInUser와
///같은 사람만 true를 return받게~
///order Entity에 customerId, driverId를 relationId로 설정해준다.
______________________________________________order.entity.ts
export class Order extends CoreEntity {
@Field(() => User, { nullable: true })
@ManyToOne(() => User, (user) => user.orders, {
onDelete: 'SET NULL',
nullable: true,
})
customer?: User;
@RelationId((order: Order) => order.customer)
customnerId: number;
@Field(() => User, { nullable: true })
@ManyToOne(() => User, (user) => user.rides, {
onDelete: 'SET NULL',
nullable: true,
})
driver?: User;
@RelationId((order: Order) => order.driver)
driverId: number;
______________________________________________________________
async getOrder(
user: User,
{ id: orderId }: GetOrderInput,
): Promise<GetOrderOutput> {
try {
const order = await this.orders.findOne(orderId, {
relations: ['restaurant'],
});
///입력받은 id로 order를 찾고, 관련된 restaurant를 불러준다.
if (!order) {
return {
ok: false,
error: 'Order not found',
};
}
if (!this.canSeeOrder(user, order)) {
return {
ok: false,
error: 'You can not see that!',
};
}
///canSeeOrder API에 user와 order를 보내주어서
///false를 받는다면 if(!this.canSeeOrder(user, order))
///return{ ok:fasle }로 error를 보낸다.
return {
ok: true,
order,
};
///canSeeOrder가 !가 아니라면, ok:true, order를 return한다.
} catch {
return {
ok: false,
error: 'Could not load order',
};
}
}
어렵지만, 힘내자!!!!!!!!!!!