From aff778693e54777e5674dd6835bd69226ff80685 Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 2 Jun 2023 01:03:59 +0300 Subject: [PATCH 1/5] refactor: add pagination & void --- src/handlers/account/index.ts | 48 +++++++------- src/handlers/account/types.ts | 6 +- src/handlers/auth/middleware.ts | 4 +- src/handlers/permission/index.ts | 28 ++++----- src/handlers/privilege/index.ts | 44 ++++++------- src/handlers/roles/index.ts | 42 ++++++------- src/handlers/tariff/index.ts | 60 +++++++++++------- src/handlers/tariff/types.ts | 11 ++++ src/swagger/tariff/models.ts | 62 +++++++++++++++++++ src/types/messages/pagination.type.ts | 4 ++ .../determine-pagination-parameters.test.ts} | 4 +- .../determine-pagination-parameters.ts} | 2 +- 12 files changed, 203 insertions(+), 112 deletions(-) create mode 100644 src/types/messages/pagination.type.ts rename src/{handlers/account/helpers.test.ts => utils/determine-pagination-parameters.test.ts} (83%) rename src/{handlers/account/helpers.ts => utils/determine-pagination-parameters.ts} (88%) diff --git a/src/handlers/account/index.ts b/src/handlers/account/index.ts index 6b11672..09ed02a 100644 --- a/src/handlers/account/index.ts +++ b/src/handlers/account/index.ts @@ -6,7 +6,7 @@ import { PermissionModule } from "@/services/permission/permission.module"; import { getUser } from "@/clients/auth"; import { validateEmptyFields } from "@/utils/validate-empty-fields"; -import { determinePaginationParameters } from "./helpers"; +import { determinePaginationParameters } from "@/utils/determine-pagination-parameters"; import type { FastifyReply, FastifyRequest } from "fastify"; import type { Account } from "@/types/models/account.type"; @@ -27,21 +27,21 @@ export const getAccounts = async (request: GetAccountsRequest): Promise { if (!Types.ObjectId.isValid(request.user.id)) { - reply.status(400); + void reply.status(400); return new Error("invalid user id"); } const account = await AccountModel.findOne({ userId: request.user.id }).lean(); if (account) { - reply.status(409); + void reply.status(409); return new Error("account already exist"); } const user = await getUser({ id: request.user.id }); if (!user) { - reply.status(404); + void reply.status(404); return new Error("user not found"); } @@ -56,19 +56,19 @@ export const getAccountByID = async (request: GetAccountRequest, reply: FastifyR const [getAccountRequestParams, error] = validateEmptyFields(request.params || {}, ["userId"]); if (error) { - reply.status(400); + void reply.status(400); throw error; } if (!Types.ObjectId.isValid(getAccountRequestParams.userId)) { - reply.status(400); + void reply.status(400); throw new Error("invalid user id"); } const account = await AccountModel.findOne({ userId: getAccountRequestParams.userId }).lean(); if (!account) { - reply.status(404); + void reply.status(404); throw new Error("account not found"); } @@ -77,14 +77,14 @@ export const getAccountByID = async (request: GetAccountRequest, reply: FastifyR export const getAccount = async (request: GetAccountRequest, reply: FastifyReply): Promise => { if (!Types.ObjectId.isValid(request.user.id)) { - reply.status(400); + void reply.status(400); throw new Error("invalid user id"); } const account = await AccountModel.findOne({ userId: request.user.id }).lean(); if (!account) { - reply.status(404); + void reply.status(404); throw new Error("account not found"); } @@ -95,14 +95,14 @@ export const setAccountRole = async (request: SetAccountRoleRequest, reply: Fast const [setAccountRoleBody, error] = validateEmptyFields(request.body || {}, ["userId", "role"]); if (error) { - reply.status(400); + void reply.status(400); return error; } const role = await RoleModel.findOne({ name: setAccountRoleBody.role }).lean(); if (!role) { - reply.status(404); + void reply.status(404); return new Error("role not found"); } @@ -112,7 +112,7 @@ export const setAccountRole = async (request: SetAccountRoleRequest, reply: Fast ); if (!account) { - reply.status(404); + void reply.status(404); return new Error("account not found"); } @@ -121,7 +121,7 @@ export const setAccountRole = async (request: SetAccountRoleRequest, reply: Fast export const removeAccount = async (request: FastifyRequest, reply: FastifyReply): Promise => { if (!Types.ObjectId.isValid(request.user.id)) { - reply.status(400); + void reply.status(400); throw new Error("invalid user id"); } @@ -131,7 +131,7 @@ export const removeAccount = async (request: FastifyRequest, reply: FastifyReply ).lean(); if (!account) { - reply.status(404); + void reply.status(404); throw new Error("account not found"); } @@ -142,19 +142,19 @@ export const removeAccountById = async (request: GetAccountRequest, reply: Fasti const [{ userId }, error] = validateEmptyFields(request.params || {}, ["userId"]); if (error) { - reply.status(400); + void reply.status(400); throw error; } if (!Types.ObjectId.isValid(userId)) { - reply.status(400); + void reply.status(400); throw new Error("invalid user id"); } const account = await AccountModel.findOne({ userId: request.user.id }); if (!account) { - reply.status(404); + void reply.status(404); throw new Error("account not found"); } @@ -171,14 +171,14 @@ export const removeAccountById = async (request: GetAccountRequest, reply: Fasti export const deleteAccount = async (request: FastifyRequest, reply: FastifyReply): Promise => { if (!Types.ObjectId.isValid(request.user.id)) { - reply.status(400); + void reply.status(400); throw new Error("invalid user id"); } const account = await AccountModel.findByIdAndDelete({ userId: request.user.id }).lean(); if (!account) { - reply.status(404); + void reply.status(404); throw new Error("account not found"); } @@ -189,19 +189,19 @@ export const deleteAccountById = async (request: GetAccountRequest, reply: Fasti const [{ userId }, error] = validateEmptyFields(request.params || {}, ["userId"]); if (error) { - reply.status(400); + void reply.status(400); throw error; } if (!Types.ObjectId.isValid(userId)) { - reply.status(400); + void reply.status(400); throw new Error("invalid user id"); } const account = await AccountModel.findByIdAndDelete({ userId: request.user.id }).lean(); if (!account) { - reply.status(404); + void reply.status(404); throw new Error("account not found"); } @@ -216,7 +216,7 @@ export const deleteAccountById = async (request: GetAccountRequest, reply: Fasti export const restoreAccount = async (request: FastifyRequest, reply: FastifyReply): Promise => { if (!Types.ObjectId.isValid(request.user.id)) { - reply.status(400); + void reply.status(400); throw new Error("invalid user id"); } @@ -226,7 +226,7 @@ export const restoreAccount = async (request: FastifyRequest, reply: FastifyRepl ).lean(); if (!account) { - reply.status(404); + void reply.status(404); throw new Error("account not found"); } diff --git a/src/handlers/account/types.ts b/src/handlers/account/types.ts index d6a83ed..d4429f8 100644 --- a/src/handlers/account/types.ts +++ b/src/handlers/account/types.ts @@ -1,5 +1,6 @@ import type { FastifyRequest } from "fastify"; import type { Account } from "@/types/models/account.type"; +import type { PaginationParams } from "@/types/messages/pagination.type"; export type GetAccountRequest = FastifyRequest<{ Params?: { @@ -22,8 +23,3 @@ export type GetAccountsResponse = { accounts: Account[]; totalPages: number; }; - -export type PaginationParams = { - page?: number; - limit?: number; -}; diff --git a/src/handlers/auth/middleware.ts b/src/handlers/auth/middleware.ts index 8c5033c..bd520fc 100644 --- a/src/handlers/auth/middleware.ts +++ b/src/handlers/auth/middleware.ts @@ -7,13 +7,13 @@ export const verifyUser = async (request: FastifyRequest, reply: FastifyReply, d const { id } = await request.jwtVerify<{ id?: string }>(); if (!id) { - reply.status(401); + void reply.status(401); return reply.send("user id is empty"); } request.user = { id }; } catch (nativeError) { - reply.status(401); + void reply.status(401); console.info("---------------------------verifyUser error------------------------------", nativeError); return reply.send(nativeError); } diff --git a/src/handlers/permission/index.ts b/src/handlers/permission/index.ts index aa5b925..6e19e06 100644 --- a/src/handlers/permission/index.ts +++ b/src/handlers/permission/index.ts @@ -18,12 +18,12 @@ export const getPermissionById = async ( const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params || {}, ["permissionId"]); if (validateParamsError) { - reply.status(400); + void reply.status(400); throw validateParamsError; } if (!Types.ObjectId.isValid(permissionId)) { - reply.status(400); + void reply.status(400); throw new Error("invalid permission id"); } @@ -33,7 +33,7 @@ export const getPermissionById = async ( }); if (!permission) { - reply.status(404); + void reply.status(404); throw new Error("permission not found"); } @@ -44,7 +44,7 @@ export const createPermission = async (request: CreatePermissionRequest, reply: const [permission, error] = validateEmptyFields(request.body || {}, ["name", "description"]); if (error) { - reply.status(400); + void reply.status(400); throw error; } @@ -61,17 +61,17 @@ export const updatePermission = async ( const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params || {}, ["permissionId"]); if (validateBodyError) { - reply.status(400); + void reply.status(400); throw validateBodyError; } if (validateParamsError) { - reply.status(400); + void reply.status(400); throw validateParamsError; } if (!Types.ObjectId.isValid(permissionId)) { - reply.status(400); + void reply.status(400); throw new Error("invalid permission id"); } @@ -83,7 +83,7 @@ export const updatePermission = async ( }); if (!findedPermission) { - reply.status(404); + void reply.status(404); throw new Error("permission not found"); } @@ -97,12 +97,12 @@ export const removePermission = async ( const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params || {}, ["permissionId"]); if (validateParamsError) { - reply.status(400); + void reply.status(400); throw validateParamsError; } if (!Types.ObjectId.isValid(permissionId)) { - reply.status(400); + void reply.status(400); throw new Error("invalid permission id"); } @@ -120,7 +120,7 @@ export const removePermission = async ( ); if (!permission) { - reply.status(404); + void reply.status(404); throw new Error("permission not found"); } @@ -134,12 +134,12 @@ export const restorePermission = async ( const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params || {}, ["permissionId"]); if (validateParamsError) { - reply.status(400); + void reply.status(400); throw validateParamsError; } if (!Types.ObjectId.isValid(permissionId)) { - reply.status(400); + void reply.status(400); throw new Error("invalid permission id"); } @@ -158,7 +158,7 @@ export const restorePermission = async ( ); if (!permission) { - reply.status(404); + void reply.status(404); throw new Error("permission not found"); } diff --git a/src/handlers/privilege/index.ts b/src/handlers/privilege/index.ts index 9365ec3..93d898f 100644 --- a/src/handlers/privilege/index.ts +++ b/src/handlers/privilege/index.ts @@ -18,12 +18,12 @@ export const registerPrivilegies = async (request: RegisterPrivilegiesRequest, r const [requestBody, errorEmpty] = validateEmptyFields(request.body ?? {}, ["privilegies"]); if (errorEmpty) { - reply.status(400); + void reply.status(400); return errorEmpty; } if (!requestBody.privilegies.length) { - reply.status(400); + void reply.status(400); return new Error("empty privilege array"); } @@ -31,7 +31,7 @@ export const registerPrivilegies = async (request: RegisterPrivilegiesRequest, r const errorInvalid = validatePrivilege(rawPrivilege); if (errorInvalid) { - reply.status(400); + void reply.status(400); return errorInvalid; } } @@ -69,21 +69,21 @@ export const registerPrivilege = async (request: RegisterPrivilegeRequest, reply ); if (errorEmpty) { - reply.status(400); + void reply.status(400); return errorEmpty; } const errorInvalid = validatePrivilege(requestBody); if (errorInvalid) { - reply.status(400); + void reply.status(400); return errorInvalid; } const privilege = await PrivilegeModel.findOne({ privilegeId: requestBody.privilegeId }).lean(); if (privilege) { - reply.status(409); + void reply.status(409); return new Error("privilege already exist"); } @@ -116,7 +116,7 @@ export const getServicePrivilegies = async (request: GetServicePrivilegiesReques const [requestParams, error] = validateEmptyFields(request.params ?? {}, ["serviceKey"]); if (error) { - reply.status(400); + void reply.status(400); return error; } @@ -127,19 +127,19 @@ export const getPrivilege = async (request: GetPrivilegeRequest, reply: FastifyR const [requestParams, error] = validateEmptyFields(request.params ?? {}, ["privilegeId"]); if (error) { - reply.status(400); + void reply.status(400); return error; } if (!Types.ObjectId.isValid(requestParams.privilegeId)) { - reply.status(400); + void reply.status(400); return new Error("invalid id"); } const privilege = await PrivilegeModel.findOne({ privilegeId: requestParams.privilegeId, isDeleted: false }).lean(); if (!privilege) { - reply.status(404); + void reply.status(404); return new Error("privilege not found"); } @@ -154,21 +154,21 @@ export const replacePrivilege = async (request: RegisterPrivilegeRequest, reply: ); if (errorEmpty) { - reply.status(400); + void reply.status(400); return errorEmpty; } const errorInvalid = validatePrivilege(requestBody); if (errorInvalid) { - reply.status(400); + void reply.status(400); return errorInvalid; } const privilege = await PrivilegeModel.findOne({ privilegeId: requestBody.privilegeId }); if (!privilege) { - reply.status(404); + void reply.status(404); return new Error("privilege not found"); } @@ -190,12 +190,12 @@ export const removePrivilege = async (request: RemovePrivilegeRequest, reply: Fa const [{ privilegeId }, error] = validateEmptyFields(request.body ?? {}, ["privilegeId"]); if (error) { - reply.status(400); + void reply.status(400); return error; } if (!Types.ObjectId.isValid(privilegeId)) { - reply.status(400); + void reply.status(400); return new Error("invalid id"); } @@ -205,7 +205,7 @@ export const removePrivilege = async (request: RemovePrivilegeRequest, reply: Fa ); if (!privilege) { - reply.status(404); + void reply.status(404); return new Error("privilege not found"); } @@ -216,12 +216,12 @@ export const replacePrivilegies = async (request: RegisterPrivilegiesRequest, re const [requestBody, errorEmpty] = validateEmptyFields(request.body ?? {}, ["privilegies"]); if (errorEmpty) { - reply.status(400); + void reply.status(400); return errorEmpty; } if (!requestBody.privilegies.length) { - reply.status(400); + void reply.status(400); return new Error("empty privilege array"); } @@ -229,7 +229,7 @@ export const replacePrivilegies = async (request: RegisterPrivilegiesRequest, re const errorInvalid = validatePrivilege(rawPrivilege); if (errorInvalid) { - reply.status(400); + void reply.status(400); return errorInvalid; } } @@ -260,19 +260,19 @@ export const restorePrivilege = async (request: RemovePrivilegeRequest, reply: F const [{ privilegeId }, error] = validateEmptyFields(request.body ?? {}, ["privilegeId"]); if (error) { - reply.status(400); + void reply.status(400); return error; } if (!Types.ObjectId.isValid(privilegeId)) { - reply.status(400); + void reply.status(400); return new Error("invalid id"); } const privilege = await PrivilegeModel.findOneAndUpdate({ privilegeId }, { $set: { isDeleted: false } }); if (!privilege) { - reply.status(404); + void reply.status(404); return new Error("privilege not found"); } diff --git a/src/handlers/roles/index.ts b/src/handlers/roles/index.ts index def0c9d..dda804e 100644 --- a/src/handlers/roles/index.ts +++ b/src/handlers/roles/index.ts @@ -14,14 +14,14 @@ export const createRole = async (request: CreateRoleRequest, reply: FastifyReply const [createRoleRequest, error] = validateEmptyFields(request.body, ["name", "permissions"]); if (error || !createRoleRequest) { - reply.status(400); + void reply.status(400); return error; } const isRoleExist = await RoleModel.exists({ name: createRoleRequest.name }).lean(); if (isRoleExist) { - reply.status(409); + void reply.status(409); return new Error("role already exist"); } @@ -34,14 +34,14 @@ export const deleteRole = async (request: RemoveRoleRequest, reply: FastifyReply const { id } = request.body || {}; if (!id || !Types.ObjectId.isValid(id)) { - reply.status(400); + void reply.status(400); return new Error("wrong id"); } const deletedRole = await RoleModel.findByIdAndDelete(id); if (!deletedRole) { - reply.status(404); + void reply.status(404); return new Error("role not found"); } @@ -52,18 +52,18 @@ export const removeRole = async (request: RemoveRoleRequest, reply: FastifyReply const { id } = request.body || {}; if (!id || !Types.ObjectId.isValid(id)) { - reply.status(400); + void reply.status(400); return new Error("wrong id"); } const role = await RoleModel.findById(id); if (!role) { - reply.status(404); + void reply.status(404); return new Error("role by id not found"); } if (role.isDeleted) { - reply.status(409); + void reply.status(409); return new Error("role already deleted"); } @@ -76,7 +76,7 @@ export const getRole = async (request: GetRoleRequest, reply: FastifyReply) => { const { query } = request.params || {}; if (!query) { - reply.status(400); + void reply.status(400); return new Error("query is empty"); } @@ -84,7 +84,7 @@ export const getRole = async (request: GetRoleRequest, reply: FastifyReply) => { const role = await RoleModel.findOne({ _id: new Types.ObjectId(query), isDeleted: false }).lean(); if (!role) { - reply.status(404); + void reply.status(404); return new Error("role not found"); } @@ -94,7 +94,7 @@ export const getRole = async (request: GetRoleRequest, reply: FastifyReply) => { const role = await RoleModel.findOne({ name: query, isDeleted: false }).lean(); if (!role) { - reply.status(404); + void reply.status(404); return new Error("role not found"); } @@ -106,11 +106,11 @@ export const replaceRole = async (request: UpdateRoleRequest, reply: FastifyRepl const { query } = request.params || {}; if (error || !replaceRoleRequest) { - reply.status(400); + void reply.status(400); return error; } if (!query) { - reply.status(400); + void reply.status(400); return new Error("either name or id must be filled"); } @@ -118,7 +118,7 @@ export const replaceRole = async (request: UpdateRoleRequest, reply: FastifyRepl const role = RoleModel.findById(query); if (!role) { - reply.status(404); + void reply.status(404); return new Error("role by id not found"); } @@ -134,7 +134,7 @@ export const replaceRole = async (request: UpdateRoleRequest, reply: FastifyRepl const role = await RoleModel.findOne({ name: query }); if (!role) { - reply.status(404); + void reply.status(404); return new Error("role not found"); } @@ -151,11 +151,11 @@ export const updateRole = async (request: UpdateRoleRequest, reply: FastifyReply const { query } = request.params; if (!query) { - reply.status(400); + void reply.status(400); return new Error("query is empty"); } if (!request.body?.name && !request.body?.permissions) { - reply.status(400); + void reply.status(400); return new Error("either name or permissions must be filled"); } @@ -163,7 +163,7 @@ export const updateRole = async (request: UpdateRoleRequest, reply: FastifyReply const role = await RoleModel.findById(query); if (!role) { - reply.status(404); + void reply.status(404); return new Error("role by id not found"); } @@ -181,7 +181,7 @@ export const updateRole = async (request: UpdateRoleRequest, reply: FastifyReply const role = await RoleModel.findOne({ name: query }); if (!role) { - reply.status(404); + void reply.status(404); return new Error("role not found"); } @@ -200,18 +200,18 @@ export const restoreRole = async (request: RemoveRoleRequest, reply: FastifyRepl const { id } = request.body || {}; if (!id || !Types.ObjectId.isValid(id)) { - reply.status(400); + void reply.status(400); return new Error("wrong id"); } const role = await RoleModel.findById(id); if (!role) { - reply.status(404); + void reply.status(404); return new Error("role by id not found"); } if (!role.isDeleted) { - reply.status(409); + void reply.status(409); return new Error("role not removed"); } diff --git a/src/handlers/tariff/index.ts b/src/handlers/tariff/index.ts index e03ccc0..a01d30a 100644 --- a/src/handlers/tariff/index.ts +++ b/src/handlers/tariff/index.ts @@ -4,33 +4,51 @@ import { TariffModel } from "@/models/tariff.model"; import { PrivilegeModel } from "@/models/privilege.model"; import { validateEmptyFields } from "@/utils/validate-empty-fields"; +import { determinePaginationParameters } from "@/utils/determine-pagination-parameters"; import { validateTariff } from "./helpers"; import type { FastifyReply } from "fastify"; - import type { Privilege } from "@/types/models/privilege.type"; import type { Eloquent } from "@/types/models/eloquent.type"; -import type { CreateTariffRequest, GetTariffRequest, ReplaceTariffRequest, RemoveTariffRequest } from "./types"; +import type { + CreateTariffRequest, + GetTariffRequest, + ReplaceTariffRequest, + RemoveTariffRequest, + GetTariffsResponse, + GetTariffsRequest, +} from "./types"; -export const getTariffs = async () => TariffModel.find({}).lean(); +export const getTariffs = async (request: GetTariffsRequest): Promise => { + const { page, limit } = determinePaginationParameters(request?.query ?? {}); + + const tariffsCount = await TariffModel.countDocuments(); + + const totalPages = Math.ceil(tariffsCount / limit); + const offset = (page - 1) * limit; + + const tariffs = await TariffModel.find({}).sort({ createdAt: "desc" }).skip(offset).limit(limit).lean(); + + return { tariffs, totalPages }; +}; export const getTariff = async (request: GetTariffRequest, reply: FastifyReply) => { const [requestParams, error] = validateEmptyFields(request.params ?? {}, ["id"]); if (error) { - reply.status(400); + void reply.status(400); return error; } if (!Types.ObjectId.isValid(requestParams.id)) { - reply.status(400); + void reply.status(400); return new Error("invalid id"); } const tariff = await TariffModel.findById(requestParams.id).lean(); if (!tariff) { - reply.status(404); + void reply.status(404); return new Error("tariff not found"); } @@ -41,13 +59,13 @@ export const createTariff = async (request: CreateTariffRequest, reply: FastifyR const [requestBody, error] = validateTariff(request.body); if (error) { - reply.status(400); + void reply.status(400); return error; } for (const privilege of requestBody.privilegies) { if (!Types.ObjectId.isValid(privilege.privilegeId)) { - reply.status(404); + void reply.status(404); return new Error(`privilege id <${privilege.privilegeId}> invalid`); } } @@ -82,25 +100,25 @@ export const replaceTariff = async (request: ReplaceTariffRequest, reply: Fastif const [requestBody, error] = validateTariff(request.body ?? {}); if (error) { - reply.status(400); + void reply.status(400); return error; } if (!Types.ObjectId.isValid(request.params?.id || "")) { - reply.status(400); + void reply.status(400); return new Error("invalid id"); } const tariff = await TariffModel.findById(request.params?.id); if (!tariff) { - reply.status(404); + void reply.status(404); return new Error("tariff not found"); } for (const privilege of requestBody.privilegies) { if (!Types.ObjectId.isValid(privilege.privilegeId)) { - reply.status(404); + void reply.status(404); return new Error(`privilege id <${privilege.privilegeId}> invalid`); } } @@ -133,12 +151,12 @@ export const removeTariff = async (request: RemoveTariffRequest, reply: FastifyR const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]); if (error) { - reply.status(400); + void reply.status(400); return error; } if (!Types.ObjectId.isValid(id)) { - reply.status(400); + void reply.status(400); return new Error("invalid id"); } @@ -147,7 +165,7 @@ export const removeTariff = async (request: RemoveTariffRequest, reply: FastifyR }).lean(); if (!tariff) { - reply.status(404); + void reply.status(404); return new Error("tariff not found"); } @@ -158,19 +176,19 @@ export const deleteTariff = async (request: RemoveTariffRequest, reply: FastifyR const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]); if (error) { - reply.status(400); + void reply.status(400); return error; } if (!Types.ObjectId.isValid(id)) { - reply.status(400); + void reply.status(400); return new Error("invalid id"); } const tariff = await TariffModel.findByIdAndDelete(id).lean(); if (!tariff) { - reply.status(404); + void reply.status(404); return new Error("tariff not found"); } @@ -181,19 +199,19 @@ export const restoreTariff = async (request: RemoveTariffRequest, reply: Fastify const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]); if (error) { - reply.status(400); + void reply.status(400); return error; } if (!Types.ObjectId.isValid(id)) { - reply.status(400); + void reply.status(400); return new Error("invalid id"); } const tariff = await TariffModel.findByIdAndUpdate(id, { $set: { isDeleted: false } }).lean(); if (!tariff) { - reply.status(404); + void reply.status(404); return new Error("tariff not found"); } diff --git a/src/handlers/tariff/types.ts b/src/handlers/tariff/types.ts index df92479..ab48dba 100644 --- a/src/handlers/tariff/types.ts +++ b/src/handlers/tariff/types.ts @@ -1,5 +1,7 @@ import type { FastifyRequest } from "fastify"; import type { TariffMessage } from "@/types/messages/tariff-message.type"; +import type { Tariff } from "@/types/models/tariff.type"; +import type { PaginationParams } from "@/types/messages/pagination.type"; export type GetTariffRequest = FastifyRequest<{ Params?: { @@ -21,3 +23,12 @@ export type ReplaceTariffRequest = FastifyRequest<{ Body?: TariffMessage; Params?: { id?: string }; }>; + +export type GetTariffsRequest = FastifyRequest<{ + Querystring?: PaginationParams; +}>; + +export type GetTariffsResponse = { + tariffs: Tariff[]; + totalPages: number; +}; diff --git a/src/swagger/tariff/models.ts b/src/swagger/tariff/models.ts index 5614015..5297456 100644 --- a/src/swagger/tariff/models.ts +++ b/src/swagger/tariff/models.ts @@ -82,3 +82,65 @@ export const tariff: SwaggerMessage = { }, ], }; + +export const tariffs: SwaggerMessage = { + description: "Список тарифов", + type: "object", + required: ["tariffs", "totalPages"], + properties: { + tariffs: { + type: "array", + description: "Массив тарифов", + items: tariff, + }, + totalPages: { type: "number" }, + }, + examples: [ + { + totalPages: 10, + tariffs: [ + { + name: "Использование сервисов", + price: 14000, + isCustom: false, + privilegies: [ + { + name: "name", + privilegeId: "507f1f77bcf86cd799439011", + serviceKey: "docx-templater-service", + description: "Количество попыток использования", + type: "count", + value: "200", + price: 12300, + amount: 300, + }, + ], + isDeleted: false, + createdAt: "2017-07-21T17:32:28Z", + updatedAt: "2017-07-21T17:32:28Z", + }, + { + name: "user", + price: 14000, + isCustom: false, + privilegies: [ + { + name: "507f1f77bcf86cd799439011", + privilegeId: "507f1f77bcf86cd799439011", + serviceKey: "docx-templater-service", + description: "Количество попыток использования", + type: "count", + value: "200", + price: 12300, + amount: 100, + }, + ], + isDeleted: true, + createdAt: "2017-07-21T17:32:28Z", + updatedAt: "2019-04-14T15:32:15Z", + deletedAt: "2021-08-17T13:23:44Z", + }, + ], + }, + ], +}; diff --git a/src/types/messages/pagination.type.ts b/src/types/messages/pagination.type.ts new file mode 100644 index 0000000..1790080 --- /dev/null +++ b/src/types/messages/pagination.type.ts @@ -0,0 +1,4 @@ +export type PaginationParams = { + page?: number; + limit?: number; +}; diff --git a/src/handlers/account/helpers.test.ts b/src/utils/determine-pagination-parameters.test.ts similarity index 83% rename from src/handlers/account/helpers.test.ts rename to src/utils/determine-pagination-parameters.test.ts index a1224f5..607d47e 100644 --- a/src/handlers/account/helpers.test.ts +++ b/src/utils/determine-pagination-parameters.test.ts @@ -1,6 +1,6 @@ -import { determinePaginationParameters } from "./helpers"; +import { determinePaginationParameters } from "./determine-pagination-parameters"; -import type { PaginationParams } from "./types"; +import type { PaginationParams } from "@/types/messages/pagination.type"; describe("determinePaginationParameters", () => { const testCases: Array<{ diff --git a/src/handlers/account/helpers.ts b/src/utils/determine-pagination-parameters.ts similarity index 88% rename from src/handlers/account/helpers.ts rename to src/utils/determine-pagination-parameters.ts index 9590b6f..528b528 100644 --- a/src/handlers/account/helpers.ts +++ b/src/utils/determine-pagination-parameters.ts @@ -1,5 +1,5 @@ import type { ObjectWithRequiredFields } from "@/types/object-with-required-fields"; -import type { PaginationParams } from "./types"; +import type { PaginationParams } from "@/types/messages/pagination.type"; const DEFAULT_PAGE = 1; const DEFAULT_LIMIT = 100; From fe7e7a12a0c22936fa87c1321cb6054d3c9bbc97 Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 2 Jun 2023 01:06:29 +0300 Subject: [PATCH 2/5] refactor: await --- src/handlers/auth/middleware.ts | 3 --- src/handlers/roles/index.ts | 6 +++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/handlers/auth/middleware.ts b/src/handlers/auth/middleware.ts index bd520fc..a6ffdfb 100644 --- a/src/handlers/auth/middleware.ts +++ b/src/handlers/auth/middleware.ts @@ -1,8 +1,6 @@ import type { FastifyRequest, FastifyReply, HookHandlerDoneFunction as Done } from "fastify"; export const verifyUser = async (request: FastifyRequest, reply: FastifyReply, done: Done) => { - console.info("---------------------------verifyUser------------------------------"); - try { const { id } = await request.jwtVerify<{ id?: string }>(); @@ -14,7 +12,6 @@ export const verifyUser = async (request: FastifyRequest, reply: FastifyReply, d request.user = { id }; } catch (nativeError) { void reply.status(401); - console.info("---------------------------verifyUser error------------------------------", nativeError); return reply.send(nativeError); } diff --git a/src/handlers/roles/index.ts b/src/handlers/roles/index.ts index dda804e..88ca6f9 100644 --- a/src/handlers/roles/index.ts +++ b/src/handlers/roles/index.ts @@ -62,6 +62,7 @@ export const removeRole = async (request: RemoveRoleRequest, reply: FastifyReply void reply.status(404); return new Error("role by id not found"); } + if (role.isDeleted) { void reply.status(409); return new Error("role already deleted"); @@ -109,13 +110,14 @@ export const replaceRole = async (request: UpdateRoleRequest, reply: FastifyRepl void reply.status(400); return error; } + if (!query) { void reply.status(400); return new Error("either name or id must be filled"); } if (Types.ObjectId.isValid(query)) { - const role = RoleModel.findById(query); + const role = await RoleModel.findById(query); if (!role) { void reply.status(404); @@ -154,6 +156,7 @@ export const updateRole = async (request: UpdateRoleRequest, reply: FastifyReply void reply.status(400); return new Error("query is empty"); } + if (!request.body?.name && !request.body?.permissions) { void reply.status(400); return new Error("either name or permissions must be filled"); @@ -210,6 +213,7 @@ export const restoreRole = async (request: RemoveRoleRequest, reply: FastifyRepl void reply.status(404); return new Error("role by id not found"); } + if (!role.isDeleted) { void reply.status(409); return new Error("role not removed"); From c4d35c1d76eb6e9026efc1495632bbf22319f2c3 Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 2 Jun 2023 01:19:03 +0300 Subject: [PATCH 3/5] feat: tariff pagination --- src/handlers/account/index.ts | 8 ++++---- src/handlers/permission/index.ts | 12 ++++++------ src/handlers/roles/index.ts | 2 +- src/swagger/tariff/index.ts | 3 ++- src/swagger/tariff/inputs.ts | 14 ++++++++++++++ src/swagger/tariff/responses.ts | 8 ++------ 6 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/handlers/account/index.ts b/src/handlers/account/index.ts index 09ed02a..342dce7 100644 --- a/src/handlers/account/index.ts +++ b/src/handlers/account/index.ts @@ -13,7 +13,7 @@ import type { Account } from "@/types/models/account.type"; import type { GetAccountRequest, SetAccountRoleRequest, GetAccountsRequest, GetAccountsResponse } from "./types"; export const getAccounts = async (request: GetAccountsRequest): Promise => { - const { page, limit } = determinePaginationParameters(request?.query || {}); + const { page, limit } = determinePaginationParameters(request?.query ?? {}); const accountsCount = await AccountModel.countDocuments(); @@ -53,7 +53,7 @@ export const createAccount = async (request: FastifyRequest, reply: FastifyReply }; export const getAccountByID = async (request: GetAccountRequest, reply: FastifyReply): Promise => { - const [getAccountRequestParams, error] = validateEmptyFields(request.params || {}, ["userId"]); + const [getAccountRequestParams, error] = validateEmptyFields(request.params ?? {}, ["userId"]); if (error) { void reply.status(400); @@ -139,7 +139,7 @@ export const removeAccount = async (request: FastifyRequest, reply: FastifyReply }; export const removeAccountById = async (request: GetAccountRequest, reply: FastifyReply): Promise => { - const [{ userId }, error] = validateEmptyFields(request.params || {}, ["userId"]); + const [{ userId }, error] = validateEmptyFields(request.params ?? {}, ["userId"]); if (error) { void reply.status(400); @@ -186,7 +186,7 @@ export const deleteAccount = async (request: FastifyRequest, reply: FastifyReply }; export const deleteAccountById = async (request: GetAccountRequest, reply: FastifyReply): Promise => { - const [{ userId }, error] = validateEmptyFields(request.params || {}, ["userId"]); + const [{ userId }, error] = validateEmptyFields(request.params ?? {}, ["userId"]); if (error) { void reply.status(400); diff --git a/src/handlers/permission/index.ts b/src/handlers/permission/index.ts index 6e19e06..ed4c2b1 100644 --- a/src/handlers/permission/index.ts +++ b/src/handlers/permission/index.ts @@ -15,7 +15,7 @@ export const getPermissionById = async ( request: GetPermissionByIdRequest, reply: FastifyReply ): Promise => { - const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params || {}, ["permissionId"]); + const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params ?? {}, ["permissionId"]); if (validateParamsError) { void reply.status(400); @@ -41,7 +41,7 @@ export const getPermissionById = async ( }; export const createPermission = async (request: CreatePermissionRequest, reply: FastifyReply): Promise => { - const [permission, error] = validateEmptyFields(request.body || {}, ["name", "description"]); + const [permission, error] = validateEmptyFields(request.body ?? {}, ["name", "description"]); if (error) { void reply.status(400); @@ -57,8 +57,8 @@ export const updatePermission = async ( request: UpdatePermissionRequest, reply: FastifyReply ): Promise => { - const [permission, validateBodyError] = validateEmptyFields(request.body || {}, ["name", "description"]); - const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params || {}, ["permissionId"]); + const [permission, validateBodyError] = validateEmptyFields(request.body ?? {}, ["name", "description"]); + const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params ?? {}, ["permissionId"]); if (validateBodyError) { void reply.status(400); @@ -94,7 +94,7 @@ export const removePermission = async ( request: GetPermissionByIdRequest, reply: FastifyReply ): Promise => { - const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params || {}, ["permissionId"]); + const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params ?? {}, ["permissionId"]); if (validateParamsError) { void reply.status(400); @@ -131,7 +131,7 @@ export const restorePermission = async ( request: GetPermissionByIdRequest, reply: FastifyReply ): Promise => { - const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params || {}, ["permissionId"]); + const [{ permissionId }, validateParamsError] = validateEmptyFields(request.params ?? {}, ["permissionId"]); if (validateParamsError) { void reply.status(400); diff --git a/src/handlers/roles/index.ts b/src/handlers/roles/index.ts index 88ca6f9..dd10181 100644 --- a/src/handlers/roles/index.ts +++ b/src/handlers/roles/index.ts @@ -103,7 +103,7 @@ export const getRole = async (request: GetRoleRequest, reply: FastifyReply) => { }; export const replaceRole = async (request: UpdateRoleRequest, reply: FastifyReply) => { - const [replaceRoleRequest, error] = validateEmptyFields(request.body || {}, ["name", "permissions"]); + const [replaceRoleRequest, error] = validateEmptyFields(request.body ?? {}, ["name", "permissions"]); const { query } = request.params || {}; if (error || !replaceRoleRequest) { diff --git a/src/swagger/tariff/index.ts b/src/swagger/tariff/index.ts index d869b8e..5fce6ba 100644 --- a/src/swagger/tariff/index.ts +++ b/src/swagger/tariff/index.ts @@ -1,4 +1,4 @@ -import { getTariffParams, tariffBody, replaceTariffParams } from "./inputs"; +import { getTariffParams, tariffBody, replaceTariffParams, getTariffsQuerystring } from "./inputs"; import { getTariffReponse, getTariffsReponse, @@ -19,6 +19,7 @@ export const getTariffSchema: SwaggerSchema = { export const getTariffsSchema: SwaggerSchema = { summary: "Получение списка тарифов", tags: ["tariff"], + querystring: getTariffsQuerystring, response: getTariffsReponse, }; diff --git a/src/swagger/tariff/inputs.ts b/src/swagger/tariff/inputs.ts index 23baeb2..1c2b5db 100644 --- a/src/swagger/tariff/inputs.ts +++ b/src/swagger/tariff/inputs.ts @@ -12,6 +12,20 @@ export const getTariffParams: SwaggerMessage = { examples: [{ id: "507f1f77bcf86cd799439011" }], }; +export const getTariffsQuerystring: SwaggerMessage = { + type: "object", + properties: { + page: { + type: "number", + description: "номер страницы", + }, + limit: { + type: "number", + description: "Лимит количества аккаунтов (больше 100 не обрабатывается)", + }, + }, +}; + export const tariffBody: SwaggerMessage = { type: "object", description: "Тариф", diff --git a/src/swagger/tariff/responses.ts b/src/swagger/tariff/responses.ts index 6339706..d8e4a7b 100644 --- a/src/swagger/tariff/responses.ts +++ b/src/swagger/tariff/responses.ts @@ -1,6 +1,6 @@ import { swaggerError } from "@/utils/swagger-error"; -import { tariff } from "./models"; +import { tariff, tariffs } from "./models"; import type { SwaggerMessage } from "@/types/swagger.type"; @@ -11,11 +11,7 @@ export const getTariffReponse: Record = { }; export const getTariffsReponse: Record = { - 200: { - type: "array", - description: "Массив тарифов", - items: tariff, - }, + 200: tariffs, }; export const createTariffReponse: Record = { From 8ecd0e8982b13bbb2c5a31c80225be2ceeba408d Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 11 Jun 2023 14:30:46 +0300 Subject: [PATCH 4/5] feat: optional tariff price --- src/handlers/tariff/helpers.ts | 8 ++------ src/models/tariff.model.ts | 2 +- src/swagger/tariff/inputs.ts | 2 +- src/types/models/tariff.type.ts | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/handlers/tariff/helpers.ts b/src/handlers/tariff/helpers.ts index 191f6bc..489f3e3 100644 --- a/src/handlers/tariff/helpers.ts +++ b/src/handlers/tariff/helpers.ts @@ -4,17 +4,13 @@ import type { TariffMessage } from "@/types/messages/tariff-message.type"; import type { ObjectWithRequiredFields } from "@/types/object-with-required-fields"; export const validateTariff = (tariff?: TariffMessage): [ObjectWithRequiredFields, Error | null] => { - const [validatedTariff, errorEmpty] = validateEmptyFields( - tariff ?? {}, - ["isCustom", "name", "price", "privilegies"], - false - ); + const [validatedTariff, errorEmpty] = validateEmptyFields(tariff ?? {}, ["isCustom", "name", "privilegies"], false); if (errorEmpty) { return [validatedTariff, errorEmpty]; } - if (isNaN(Number(validatedTariff.price))) { + if (validatedTariff.price && isNaN(Number(validatedTariff.price))) { return [validatedTariff, new Error("invalid 'price' value")]; } diff --git a/src/models/tariff.model.ts b/src/models/tariff.model.ts index 2cefdfd..ee68878 100644 --- a/src/models/tariff.model.ts +++ b/src/models/tariff.model.ts @@ -12,7 +12,7 @@ const schema: SchemaDefinition = { }, price: { type: Number, - required: true, + required: false, }, isCustom: { type: Boolean, diff --git a/src/swagger/tariff/inputs.ts b/src/swagger/tariff/inputs.ts index 1c2b5db..bf68031 100644 --- a/src/swagger/tariff/inputs.ts +++ b/src/swagger/tariff/inputs.ts @@ -29,7 +29,7 @@ export const getTariffsQuerystring: SwaggerMessage = { export const tariffBody: SwaggerMessage = { type: "object", description: "Тариф", - required: ["name", "price", "isCustom", "privilegies"], + required: ["name", "isCustom", "privilegies"], properties: { name: { type: "string" }, price: { type: "number" }, diff --git a/src/types/models/tariff.type.ts b/src/types/models/tariff.type.ts index 871937e..3477f88 100644 --- a/src/types/models/tariff.type.ts +++ b/src/types/models/tariff.type.ts @@ -3,7 +3,7 @@ import type { Eloquent } from "./eloquent.type"; export type Tariff = Eloquent & { name: string; - price: number; + price?: number; isCustom: boolean; privilegies: Array>; }; From 8ded0f2265ade930525a1d8ee5c1909b67c6bb13 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Tue, 13 Jun 2023 15:02:26 +0000 Subject: [PATCH 5/5] Update file index.ts --- src/handlers/tariff/index.ts | 431 +++++++++++++++++------------------ 1 file changed, 212 insertions(+), 219 deletions(-) diff --git a/src/handlers/tariff/index.ts b/src/handlers/tariff/index.ts index a01d30a..34c3cc8 100644 --- a/src/handlers/tariff/index.ts +++ b/src/handlers/tariff/index.ts @@ -1,219 +1,212 @@ -import { Types } from "mongoose"; - -import { TariffModel } from "@/models/tariff.model"; -import { PrivilegeModel } from "@/models/privilege.model"; - -import { validateEmptyFields } from "@/utils/validate-empty-fields"; -import { determinePaginationParameters } from "@/utils/determine-pagination-parameters"; -import { validateTariff } from "./helpers"; - -import type { FastifyReply } from "fastify"; -import type { Privilege } from "@/types/models/privilege.type"; -import type { Eloquent } from "@/types/models/eloquent.type"; -import type { - CreateTariffRequest, - GetTariffRequest, - ReplaceTariffRequest, - RemoveTariffRequest, - GetTariffsResponse, - GetTariffsRequest, -} from "./types"; - -export const getTariffs = async (request: GetTariffsRequest): Promise => { - const { page, limit } = determinePaginationParameters(request?.query ?? {}); - - const tariffsCount = await TariffModel.countDocuments(); - - const totalPages = Math.ceil(tariffsCount / limit); - const offset = (page - 1) * limit; - - const tariffs = await TariffModel.find({}).sort({ createdAt: "desc" }).skip(offset).limit(limit).lean(); - - return { tariffs, totalPages }; -}; - -export const getTariff = async (request: GetTariffRequest, reply: FastifyReply) => { - const [requestParams, error] = validateEmptyFields(request.params ?? {}, ["id"]); - - if (error) { - void reply.status(400); - return error; - } - - if (!Types.ObjectId.isValid(requestParams.id)) { - void reply.status(400); - return new Error("invalid id"); - } - - const tariff = await TariffModel.findById(requestParams.id).lean(); - - if (!tariff) { - void reply.status(404); - return new Error("tariff not found"); - } - - return tariff; -}; - -export const createTariff = async (request: CreateTariffRequest, reply: FastifyReply) => { - const [requestBody, error] = validateTariff(request.body); - - if (error) { - void reply.status(400); - return error; - } - - for (const privilege of requestBody.privilegies) { - if (!Types.ObjectId.isValid(privilege.privilegeId)) { - void reply.status(404); - return new Error(`privilege id <${privilege.privilegeId}> invalid`); - } - } - - const privilegeIDs = requestBody.privilegies.map(({ privilegeId }) => privilegeId); - - const privilegies = await PrivilegeModel.find({ privilegeId: privilegeIDs }).lean(); - const cleanPrivilegies = privilegies.map>((privilege) => ({ - name: privilege.name, - privilegeId: privilege.privilegeId, - serviceKey: privilege.serviceKey, - description: privilege.description, - amount: privilege.amount, - type: privilege.type, - value: privilege.value, - price: privilege.price, - })); - - const newTariff = new TariffModel({ - name: requestBody.name, - price: requestBody.price, - isCustom: requestBody.isCustom, - privilegies: cleanPrivilegies, - }); - - await newTariff.save(); - - return newTariff; -}; - -export const replaceTariff = async (request: ReplaceTariffRequest, reply: FastifyReply) => { - const [requestBody, error] = validateTariff(request.body ?? {}); - - if (error) { - void reply.status(400); - return error; - } - - if (!Types.ObjectId.isValid(request.params?.id || "")) { - void reply.status(400); - return new Error("invalid id"); - } - - const tariff = await TariffModel.findById(request.params?.id); - - if (!tariff) { - void reply.status(404); - return new Error("tariff not found"); - } - - for (const privilege of requestBody.privilegies) { - if (!Types.ObjectId.isValid(privilege.privilegeId)) { - void reply.status(404); - return new Error(`privilege id <${privilege.privilegeId}> invalid`); - } - } - - const privilegeIDs = requestBody.privilegies.map(({ privilegeId }) => privilegeId); - - const privilegies = await PrivilegeModel.find({ privilegeId: privilegeIDs }).lean(); - const cleanPrivilegies = privilegies.map>((privilege) => ({ - name: privilege.name, - privilegeId: privilege.privilegeId, - serviceKey: privilege.serviceKey, - description: privilege.description, - amount: privilege.amount, - type: privilege.type, - value: privilege.value, - price: privilege.price, - })); - - await tariff.replaceOne({ - name: requestBody.name, - price: requestBody.price, - isCustom: requestBody.isCustom, - privilegies: cleanPrivilegies, - }); - - return tariff; -}; - -export const removeTariff = async (request: RemoveTariffRequest, reply: FastifyReply) => { - const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]); - - if (error) { - void reply.status(400); - return error; - } - - if (!Types.ObjectId.isValid(id)) { - void reply.status(400); - return new Error("invalid id"); - } - - const tariff = await TariffModel.findByIdAndUpdate(id, { - $set: { isDeleted: true, deletedAt: new Date() }, - }).lean(); - - if (!tariff) { - void reply.status(404); - return new Error("tariff not found"); - } - - return tariff; -}; - -export const deleteTariff = async (request: RemoveTariffRequest, reply: FastifyReply) => { - const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]); - - if (error) { - void reply.status(400); - return error; - } - - if (!Types.ObjectId.isValid(id)) { - void reply.status(400); - return new Error("invalid id"); - } - - const tariff = await TariffModel.findByIdAndDelete(id).lean(); - - if (!tariff) { - void reply.status(404); - return new Error("tariff not found"); - } - - return tariff; -}; - -export const restoreTariff = async (request: RemoveTariffRequest, reply: FastifyReply) => { - const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]); - - if (error) { - void reply.status(400); - return error; - } - - if (!Types.ObjectId.isValid(id)) { - void reply.status(400); - return new Error("invalid id"); - } - - const tariff = await TariffModel.findByIdAndUpdate(id, { $set: { isDeleted: false } }).lean(); - - if (!tariff) { - void reply.status(404); - return new Error("tariff not found"); - } - - return tariff; -}; +import { Types } from "mongoose"; + +import { TariffModel } from "@/models/tariff.model"; +import { PrivilegeModel } from "@/models/privilege.model"; + +import { validateEmptyFields } from "@/utils/validate-empty-fields"; +import { determinePaginationParameters } from "@/utils/determine-pagination-parameters"; +import { validateTariff } from "./helpers"; + +import type { FastifyReply } from "fastify"; +import type { Privilege } from "@/types/models/privilege.type"; +import type { Eloquent } from "@/types/models/eloquent.type"; +import type { + CreateTariffRequest, + GetTariffRequest, + ReplaceTariffRequest, + RemoveTariffRequest, + GetTariffsResponse, + GetTariffsRequest, +} from "./types"; + +export const getTariffs = async (request: GetTariffsRequest): Promise => { + const { page, limit } = determinePaginationParameters(request?.query ?? {}); + + const tariffsCount = await TariffModel.countDocuments(); + + const totalPages = Math.ceil(tariffsCount / limit); + const offset = (page - 1) * limit; + + const tariffs = await TariffModel.find({}).sort({ createdAt: "desc" }).skip(offset).limit(limit).lean(); + + return { tariffs, totalPages }; +}; + +export const getTariff = async (request: GetTariffRequest, reply: FastifyReply) => { + const [requestParams, error] = validateEmptyFields(request.params ?? {}, ["id"]); + + if (error) { + void reply.status(400); + return error; + } + + if (!Types.ObjectId.isValid(requestParams.id)) { + void reply.status(400); + return new Error("invalid id"); + } + + const tariff = await TariffModel.findById(requestParams.id).lean(); + + if (!tariff) { + void reply.status(404); + return new Error("tariff not found"); + } + + return tariff; +}; + +export const createTariff = async (request: CreateTariffRequest, reply: FastifyReply) => { + const [requestBody, error] = validateTariff(request.body); + + if (error) { + void reply.status(400); + return error; + } + + const privilegeIDs = requestBody.privilegies.map(({ privilegeId }) => privilegeId); + + const privilegies = await PrivilegeModel.find({ privilegeId: privilegeIDs }).lean(); + const cleanPrivilegies = privilegies.map>((privilege) => ({ + name: privilege.name, + privilegeId: privilege.privilegeId, + serviceKey: privilege.serviceKey, + description: privilege.description, + amount: privilege.amount, + type: privilege.type, + value: privilege.value, + price: privilege.price, + })); + + const newTariff = new TariffModel({ + name: requestBody.name, + price: requestBody.price, + isCustom: requestBody.isCustom, + privilegies: cleanPrivilegies, + }); + + await newTariff.save(); + + return newTariff; +}; + +export const replaceTariff = async (request: ReplaceTariffRequest, reply: FastifyReply) => { + const [requestBody, error] = validateTariff(request.body ?? {}); + + if (error) { + void reply.status(400); + return error; + } + + if (!Types.ObjectId.isValid(request.params?.id || "")) { + void reply.status(400); + return new Error("invalid id"); + } + + const tariff = await TariffModel.findById(request.params?.id); + + if (!tariff) { + void reply.status(404); + return new Error("tariff not found"); + } + + for (const privilege of requestBody.privilegies) { + if (!Types.ObjectId.isValid(privilege.privilegeId)) { + void reply.status(404); + return new Error(`privilege id <${privilege.privilegeId}> invalid`); + } + } + + const privilegeIDs = requestBody.privilegies.map(({ privilegeId }) => privilegeId); + + const privilegies = await PrivilegeModel.find({ privilegeId: privilegeIDs }).lean(); + const cleanPrivilegies = privilegies.map>((privilege) => ({ + name: privilege.name, + privilegeId: privilege.privilegeId, + serviceKey: privilege.serviceKey, + description: privilege.description, + amount: privilege.amount, + type: privilege.type, + value: privilege.value, + price: privilege.price, + })); + + await tariff.replaceOne({ + name: requestBody.name, + price: requestBody.price, + isCustom: requestBody.isCustom, + privilegies: cleanPrivilegies, + }); + + return tariff; +}; + +export const removeTariff = async (request: RemoveTariffRequest, reply: FastifyReply) => { + const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]); + + if (error) { + void reply.status(400); + return error; + } + + if (!Types.ObjectId.isValid(id)) { + void reply.status(400); + return new Error("invalid id"); + } + + const tariff = await TariffModel.findByIdAndUpdate(id, { + $set: { isDeleted: true, deletedAt: new Date() }, + }).lean(); + + if (!tariff) { + void reply.status(404); + return new Error("tariff not found"); + } + + return tariff; +}; + +export const deleteTariff = async (request: RemoveTariffRequest, reply: FastifyReply) => { + const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]); + + if (error) { + void reply.status(400); + return error; + } + + if (!Types.ObjectId.isValid(id)) { + void reply.status(400); + return new Error("invalid id"); + } + + const tariff = await TariffModel.findByIdAndDelete(id).lean(); + + if (!tariff) { + void reply.status(404); + return new Error("tariff not found"); + } + + return tariff; +}; + +export const restoreTariff = async (request: RemoveTariffRequest, reply: FastifyReply) => { + const [{ id }, error] = validateEmptyFields(request.body ?? {}, ["id"]); + + if (error) { + void reply.status(400); + return error; + } + + if (!Types.ObjectId.isValid(id)) { + void reply.status(400); + return new Error("invalid id"); + } + + const tariff = await TariffModel.findByIdAndUpdate(id, { $set: { isDeleted: false } }).lean(); + + if (!tariff) { + void reply.status(404); + return new Error("tariff not found"); + } + + return tariff; +};