separate flight class api and transportation class api into different module
This commit is contained in:
@@ -17,6 +17,8 @@ import { CityController } from "@/modules/city/city.controller";
|
|||||||
import { CityMapper } from "@/modules/city/city.mapper";
|
import { CityMapper } from "@/modules/city/city.mapper";
|
||||||
import { CountryController } from "@/modules/country/country.controller";
|
import { CountryController } from "@/modules/country/country.controller";
|
||||||
import { CountryMapper } from "@/modules/country/country.mapper";
|
import { CountryMapper } from "@/modules/country/country.mapper";
|
||||||
|
import { FlightClassController } from "@/modules/flight-class/flight-class.controller";
|
||||||
|
import { FlightClassMapper } from "@/modules/flight-class/flight-class.mapper";
|
||||||
import { FlightController } from "@/modules/flight/flight.controller";
|
import { FlightController } from "@/modules/flight/flight.controller";
|
||||||
import { FlightMapper } from "@/modules/flight/flight.mapper";
|
import { FlightMapper } from "@/modules/flight/flight.mapper";
|
||||||
import { HotelFacilityController } from "@/modules/hotel-facility/hotel-facility.controller";
|
import { HotelFacilityController } from "@/modules/hotel-facility/hotel-facility.controller";
|
||||||
@@ -30,6 +32,8 @@ import { PackageMapper } from "@/modules/package/package.mapper";
|
|||||||
import { PartnerController } from "@/modules/partner/partner.controller";
|
import { PartnerController } from "@/modules/partner/partner.controller";
|
||||||
import { PartnerMapper } from "@/modules/partner/partner.mapper";
|
import { PartnerMapper } from "@/modules/partner/partner.mapper";
|
||||||
import { StaticController } from "@/modules/static/static.controller";
|
import { StaticController } from "@/modules/static/static.controller";
|
||||||
|
import { TransportationClassController } from "@/modules/transportation-class/transportation-class.controller";
|
||||||
|
import { TransportationClassMapper } from "@/modules/transportation-class/transportation-class.mapper";
|
||||||
import { TransportationController } from "@/modules/transportation/transportation.controller";
|
import { TransportationController } from "@/modules/transportation/transportation.controller";
|
||||||
import { TransportationMapper } from "@/modules/transportation/transportation.mapper";
|
import { TransportationMapper } from "@/modules/transportation/transportation.mapper";
|
||||||
import compression from "compression";
|
import compression from "compression";
|
||||||
@@ -71,9 +75,13 @@ export class Application {
|
|||||||
const airlineMapper = new AirlineMapper();
|
const airlineMapper = new AirlineMapper();
|
||||||
const airportMapper = new AirportMapper(cityMapper);
|
const airportMapper = new AirportMapper(cityMapper);
|
||||||
const flightMapper = new FlightMapper(airlineMapper, airportMapper);
|
const flightMapper = new FlightMapper(airlineMapper, airportMapper);
|
||||||
|
const flightClassMapper = new FlightClassMapper(flightMapper);
|
||||||
const hotelFacilityMapper = new HotelFacilityMapper();
|
const hotelFacilityMapper = new HotelFacilityMapper();
|
||||||
const hotelMapper = new HotelMapper(cityMapper, hotelFacilityMapper);
|
const hotelMapper = new HotelMapper(cityMapper, hotelFacilityMapper);
|
||||||
const transportationMapper = new TransportationMapper();
|
const transportationMapper = new TransportationMapper();
|
||||||
|
const transportationClassMapper = new TransportationClassMapper(
|
||||||
|
transportationMapper,
|
||||||
|
);
|
||||||
const packageMapper = new PackageMapper(
|
const packageMapper = new PackageMapper(
|
||||||
flightMapper,
|
flightMapper,
|
||||||
hotelMapper,
|
hotelMapper,
|
||||||
@@ -104,6 +112,9 @@ export class Application {
|
|||||||
flightMapper,
|
flightMapper,
|
||||||
this._jwtService,
|
this._jwtService,
|
||||||
).buildRouter();
|
).buildRouter();
|
||||||
|
const flightClassRouter = new FlightClassController(
|
||||||
|
flightClassMapper,
|
||||||
|
).buildRouter();
|
||||||
const hotelFacilityRouter = new HotelFacilityController(
|
const hotelFacilityRouter = new HotelFacilityController(
|
||||||
hotelFacilityMapper,
|
hotelFacilityMapper,
|
||||||
this._jwtService,
|
this._jwtService,
|
||||||
@@ -118,6 +129,9 @@ export class Application {
|
|||||||
this._fileStorage,
|
this._fileStorage,
|
||||||
this._jwtService,
|
this._jwtService,
|
||||||
).buildRouter();
|
).buildRouter();
|
||||||
|
const transportationClassRouter = new TransportationClassController(
|
||||||
|
transportationClassMapper,
|
||||||
|
).buildRouter();
|
||||||
const packageRouter = new PackageController(
|
const packageRouter = new PackageController(
|
||||||
packageMapper,
|
packageMapper,
|
||||||
this._fileStorage,
|
this._fileStorage,
|
||||||
@@ -147,9 +161,11 @@ export class Application {
|
|||||||
this._app.use("/airlines", airlineRouter);
|
this._app.use("/airlines", airlineRouter);
|
||||||
this._app.use("/airports", airportRouter);
|
this._app.use("/airports", airportRouter);
|
||||||
this._app.use("/flights", flightRouter);
|
this._app.use("/flights", flightRouter);
|
||||||
|
this._app.use("/flight-classes", flightClassRouter);
|
||||||
this._app.use("/hotel-facilities", hotelFacilityRouter);
|
this._app.use("/hotel-facilities", hotelFacilityRouter);
|
||||||
this._app.use("/hotels", hotelRouter);
|
this._app.use("/hotels", hotelRouter);
|
||||||
this._app.use("/transportations", transportationRouter);
|
this._app.use("/transportations", transportationRouter);
|
||||||
|
this._app.use("/transportation-classes", transportationClassRouter);
|
||||||
this._app.use("/packages", packageRouter);
|
this._app.use("/packages", packageRouter);
|
||||||
this._app.use("/admins", adminRouter);
|
this._app.use("/admins", adminRouter);
|
||||||
this._app.use("/partners", partnerRouter);
|
this._app.use("/partners", partnerRouter);
|
||||||
|
|||||||
57
src/modules/flight-class/flight-class.controller.ts
Normal file
57
src/modules/flight-class/flight-class.controller.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { Controller } from "@/common/controller";
|
||||||
|
import { createOrmContextMiddleware } from "@/common/middlewares/create-orm-context.middleware";
|
||||||
|
import { paginationQuerySchema } from "@/common/schemas";
|
||||||
|
import type { ListResponse } from "@/common/types";
|
||||||
|
import { FlightClass } from "@/database/entities/flight-class.entity";
|
||||||
|
import { Flight } from "@/database/entities/flight.entity";
|
||||||
|
import { orm } from "@/database/orm";
|
||||||
|
import type { FlightClassMapper } from "@/modules/flight-class/flight-class.mapper";
|
||||||
|
import type { FlightClassResponse } from "@/modules/flight-class/flight-class.types";
|
||||||
|
import { Router, type Request, type Response } from "express";
|
||||||
|
|
||||||
|
export class FlightClassController extends Controller {
|
||||||
|
public constructor(private readonly mapper: FlightClassMapper) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async list(req: Request, res: Response) {
|
||||||
|
const parseQueryResult = paginationQuerySchema.safeParse(req.query);
|
||||||
|
if (!parseQueryResult.success) {
|
||||||
|
return this.handleZodError(parseQueryResult.error, res, "query");
|
||||||
|
}
|
||||||
|
const query = parseQueryResult.data;
|
||||||
|
|
||||||
|
const count = await orm.em.count(Flight);
|
||||||
|
|
||||||
|
const flightClasses = await orm.em.find(
|
||||||
|
FlightClass,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
limit: query.per_page,
|
||||||
|
offset: (query.page - 1) * query.per_page,
|
||||||
|
orderBy: { createdAt: "DESC" },
|
||||||
|
populate: ["*"],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).json({
|
||||||
|
data: flightClasses.map(
|
||||||
|
this.mapper.mapEntityToResponse.bind(this.mapper),
|
||||||
|
),
|
||||||
|
errors: null,
|
||||||
|
meta: {
|
||||||
|
page: query.page,
|
||||||
|
per_page: query.per_page,
|
||||||
|
total_pages: Math.ceil(count / query.per_page),
|
||||||
|
total_items: count,
|
||||||
|
},
|
||||||
|
} satisfies ListResponse<FlightClassResponse>);
|
||||||
|
}
|
||||||
|
|
||||||
|
public buildRouter(): Router {
|
||||||
|
const router = Router();
|
||||||
|
router.get("/", createOrmContextMiddleware, this.list.bind(this));
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/modules/flight-class/flight-class.mapper.ts
Normal file
20
src/modules/flight-class/flight-class.mapper.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import type { FlightClass } from "@/database/entities/flight-class.entity";
|
||||||
|
import type { FlightMapper } from "@/modules/flight/flight.mapper";
|
||||||
|
import type { FlightClassResponse } from "@/modules/flight/flight.types";
|
||||||
|
|
||||||
|
export class FlightClassMapper {
|
||||||
|
public constructor(private readonly flightMapper: FlightMapper) {}
|
||||||
|
|
||||||
|
public mapEntityToResponse(flightClass: FlightClass): FlightClassResponse {
|
||||||
|
return {
|
||||||
|
id: flightClass.id,
|
||||||
|
flight: this.flightMapper.mapEntityToResponse(flightClass.flight),
|
||||||
|
class: flightClass.class,
|
||||||
|
seat_layout: flightClass.seatLayout,
|
||||||
|
baggage: flightClass.baggage,
|
||||||
|
cabin_baggage: flightClass.cabinBaggage,
|
||||||
|
created_at: flightClass.createdAt,
|
||||||
|
updated_at: flightClass.updatedAt,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/modules/flight-class/flight-class.schemas.ts
Normal file
27
src/modules/flight-class/flight-class.schemas.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const flightClassRequestSchema = z.object({
|
||||||
|
class: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
seat_layout: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(10, "Max 10 characters."),
|
||||||
|
baggage: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
cabin_baggage: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const flightClassParamsSchema = z.object({
|
||||||
|
id: z
|
||||||
|
.ulid("Must be ulid string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(30, "Max 30 characters."),
|
||||||
|
});
|
||||||
21
src/modules/flight-class/flight-class.types.ts
Normal file
21
src/modules/flight-class/flight-class.types.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import type {
|
||||||
|
flightClassParamsSchema,
|
||||||
|
flightClassRequestSchema,
|
||||||
|
} from "@/modules/flight-class/flight-class.schemas";
|
||||||
|
import type { FlightResponse } from "@/modules/flight/flight.types";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export type FlightClassRequest = z.infer<typeof flightClassRequestSchema>;
|
||||||
|
|
||||||
|
export type FlightClassQuery = z.infer<typeof flightClassParamsSchema>;
|
||||||
|
|
||||||
|
export type FlightClassResponse = {
|
||||||
|
id: string;
|
||||||
|
flight: FlightResponse;
|
||||||
|
class: string;
|
||||||
|
seat_layout: string;
|
||||||
|
baggage: number;
|
||||||
|
cabin_baggage: number;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
@@ -397,38 +397,6 @@ export class FlightController extends Controller {
|
|||||||
} satisfies SingleResponse<FlightClassResponse>);
|
} satisfies SingleResponse<FlightClassResponse>);
|
||||||
}
|
}
|
||||||
|
|
||||||
async listAllClasses(req: Request, res: Response) {
|
|
||||||
const parseQueryResult = paginationQuerySchema.safeParse(req.query);
|
|
||||||
if (!parseQueryResult.success) {
|
|
||||||
return this.handleZodError(parseQueryResult.error, res, "query");
|
|
||||||
}
|
|
||||||
const query = parseQueryResult.data;
|
|
||||||
|
|
||||||
const count = await orm.em.count(FlightClass);
|
|
||||||
|
|
||||||
const classes = await orm.em.find(
|
|
||||||
FlightClass,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
limit: query.per_page,
|
|
||||||
offset: (query.page - 1) * query.per_page,
|
|
||||||
orderBy: { createdAt: "DESC" },
|
|
||||||
populate: ["*"],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.status(200).json({
|
|
||||||
data: classes.map(this.mapper.mapClassEntityToResponse.bind(this.mapper)),
|
|
||||||
errors: null,
|
|
||||||
meta: {
|
|
||||||
page: query.page,
|
|
||||||
per_page: query.per_page,
|
|
||||||
total_pages: Math.ceil(count / query.per_page),
|
|
||||||
total_items: count,
|
|
||||||
},
|
|
||||||
} satisfies ListResponse<FlightClassResponse>);
|
|
||||||
}
|
|
||||||
|
|
||||||
async listClasses(req: Request, res: Response) {
|
async listClasses(req: Request, res: Response) {
|
||||||
const parseQueryResult = paginationQuerySchema.safeParse(req.query);
|
const parseQueryResult = paginationQuerySchema.safeParse(req.query);
|
||||||
if (!parseQueryResult.success) {
|
if (!parseQueryResult.success) {
|
||||||
@@ -686,11 +654,6 @@ export class FlightController extends Controller {
|
|||||||
isAdminMiddleware(this.jwtService, [AdminPermission.createFlightClass]),
|
isAdminMiddleware(this.jwtService, [AdminPermission.createFlightClass]),
|
||||||
this.createClass.bind(this),
|
this.createClass.bind(this),
|
||||||
);
|
);
|
||||||
router.get(
|
|
||||||
"/classes",
|
|
||||||
createOrmContextMiddleware,
|
|
||||||
this.listAllClasses.bind(this),
|
|
||||||
);
|
|
||||||
router.get(
|
router.get(
|
||||||
"/:id/classes",
|
"/:id/classes",
|
||||||
createOrmContextMiddleware,
|
createOrmContextMiddleware,
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { Controller } from "@/common/controller";
|
||||||
|
import { createOrmContextMiddleware } from "@/common/middlewares/create-orm-context.middleware";
|
||||||
|
import { paginationQuerySchema } from "@/common/schemas";
|
||||||
|
import type { ListResponse } from "@/common/types";
|
||||||
|
import { TransportationClass } from "@/database/entities/transportation-class.entity";
|
||||||
|
import { orm } from "@/database/orm";
|
||||||
|
import type { TransportationClassMapper } from "@/modules/transportation-class/transportation-class.mapper";
|
||||||
|
import type { TransportationClassResponse } from "@/modules/transportation-class/transportation-class.types";
|
||||||
|
import { Router, type Request, type Response } from "express";
|
||||||
|
|
||||||
|
export class TransportationClassController extends Controller {
|
||||||
|
public constructor(private readonly mapper: TransportationClassMapper) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async list(req: Request, res: Response) {
|
||||||
|
const parseQueryResult = paginationQuerySchema.safeParse(req.query);
|
||||||
|
if (!parseQueryResult.success) {
|
||||||
|
return this.handleZodError(parseQueryResult.error, res, "query");
|
||||||
|
}
|
||||||
|
const query = parseQueryResult.data;
|
||||||
|
|
||||||
|
const count = await orm.em.count(TransportationClass);
|
||||||
|
|
||||||
|
const transportationClasses = await orm.em.find(
|
||||||
|
TransportationClass,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
limit: query.per_page,
|
||||||
|
offset: (query.page - 1) * query.per_page,
|
||||||
|
orderBy: { createdAt: "DESC" },
|
||||||
|
populate: ["*"],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).json({
|
||||||
|
data: transportationClasses.map(
|
||||||
|
this.mapper.mapEntityToResponse.bind(this.mapper),
|
||||||
|
),
|
||||||
|
errors: null,
|
||||||
|
meta: {
|
||||||
|
page: query.page,
|
||||||
|
per_page: query.per_page,
|
||||||
|
total_pages: Math.ceil(count / query.per_page),
|
||||||
|
total_items: count,
|
||||||
|
},
|
||||||
|
} satisfies ListResponse<TransportationClassResponse>);
|
||||||
|
}
|
||||||
|
|
||||||
|
public buildRouter(): Router {
|
||||||
|
const router = Router();
|
||||||
|
router.get("/", createOrmContextMiddleware, this.list.bind(this));
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import type { TransportationClass } from "@/database/entities/transportation-class.entity";
|
||||||
|
import type { TransportationMapper } from "@/modules/transportation/transportation.mapper";
|
||||||
|
import type { TransportationClassResponse } from "@/modules/transportation/transportation.types";
|
||||||
|
|
||||||
|
export class TransportationClassMapper {
|
||||||
|
public constructor(
|
||||||
|
private readonly transportationMapper: TransportationMapper,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public mapEntityToResponse(
|
||||||
|
transportationClass: TransportationClass,
|
||||||
|
): TransportationClassResponse {
|
||||||
|
return {
|
||||||
|
id: transportationClass.id,
|
||||||
|
transportation: this.transportationMapper.mapEntityToResponse(
|
||||||
|
transportationClass.transportation,
|
||||||
|
),
|
||||||
|
class: transportationClass.class,
|
||||||
|
total_seats: transportationClass.totalSeats,
|
||||||
|
images: transportationClass.images.getItems().map((image) => image.src),
|
||||||
|
created_at: transportationClass.createdAt,
|
||||||
|
updated_at: transportationClass.updatedAt,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const transportationClassRequestSchema = z.object({
|
||||||
|
class: z
|
||||||
|
.string("Must be string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(100, "Max 100 characters."),
|
||||||
|
total_seats: z
|
||||||
|
.number("Must be number.")
|
||||||
|
.int("Must be integer.")
|
||||||
|
.positive("Must be positive."),
|
||||||
|
images: z
|
||||||
|
.array(
|
||||||
|
z.base64("Must be base64 string.").nonempty("Must not empty."),
|
||||||
|
"Must be array.",
|
||||||
|
)
|
||||||
|
.nonempty("Must not empty."),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const transportationClassParamsSchema = z.object({
|
||||||
|
id: z
|
||||||
|
.ulid("Must be ulid string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(30, "Max 30 characters."),
|
||||||
|
});
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import type {
|
||||||
|
transportationClassParamsSchema,
|
||||||
|
transportationClassRequestSchema,
|
||||||
|
} from "@/modules/transportation-class/transportation-class.schemas";
|
||||||
|
import type { TransportationResponse } from "@/modules/transportation/transportation.types";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export type TransportationClassRequest = z.infer<
|
||||||
|
typeof transportationClassRequestSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type TransportationClassParams = z.infer<
|
||||||
|
typeof transportationClassParamsSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type TransportationClassResponse = {
|
||||||
|
id: string;
|
||||||
|
transportation: TransportationResponse;
|
||||||
|
class: string;
|
||||||
|
total_seats: number;
|
||||||
|
images: string[];
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
};
|
||||||
@@ -268,38 +268,6 @@ export class TransportationController extends Controller {
|
|||||||
} satisfies SingleResponse<TransportationClassResponse>);
|
} satisfies SingleResponse<TransportationClassResponse>);
|
||||||
}
|
}
|
||||||
|
|
||||||
async listAllClasses(req: Request, res: Response) {
|
|
||||||
const parseQueryResult = paginationQuerySchema.safeParse(req.query);
|
|
||||||
if (!parseQueryResult.success) {
|
|
||||||
return this.handleZodError(parseQueryResult.error, res, "query");
|
|
||||||
}
|
|
||||||
const query = parseQueryResult.data;
|
|
||||||
|
|
||||||
const count = await orm.em.count(TransportationClass);
|
|
||||||
|
|
||||||
const classes = await orm.em.find(
|
|
||||||
TransportationClass,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
limit: query.per_page,
|
|
||||||
offset: (query.page - 1) * query.per_page,
|
|
||||||
orderBy: { createdAt: "DESC" },
|
|
||||||
populate: ["*"],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.status(200).json({
|
|
||||||
data: classes.map(this.mapper.mapClassEntityToResponse.bind(this.mapper)),
|
|
||||||
errors: null,
|
|
||||||
meta: {
|
|
||||||
page: query.page,
|
|
||||||
per_page: query.per_page,
|
|
||||||
total_pages: Math.ceil(count / query.per_page),
|
|
||||||
total_items: count,
|
|
||||||
},
|
|
||||||
} satisfies ListResponse<TransportationClassResponse>);
|
|
||||||
}
|
|
||||||
|
|
||||||
async listClasses(req: Request, res: Response) {
|
async listClasses(req: Request, res: Response) {
|
||||||
const parseQueryResult = paginationQuerySchema.safeParse(req.query);
|
const parseQueryResult = paginationQuerySchema.safeParse(req.query);
|
||||||
if (!parseQueryResult.success) {
|
if (!parseQueryResult.success) {
|
||||||
@@ -596,11 +564,6 @@ export class TransportationController extends Controller {
|
|||||||
]),
|
]),
|
||||||
this.createClass.bind(this),
|
this.createClass.bind(this),
|
||||||
);
|
);
|
||||||
router.get(
|
|
||||||
"/classes",
|
|
||||||
createOrmContextMiddleware,
|
|
||||||
this.listAllClasses.bind(this),
|
|
||||||
);
|
|
||||||
router.get(
|
router.get(
|
||||||
"/:id/classes",
|
"/:id/classes",
|
||||||
createOrmContextMiddleware,
|
createOrmContextMiddleware,
|
||||||
|
|||||||
Reference in New Issue
Block a user