diff --git a/packages/graphql/api/base.ts b/packages/graphql/api/base.ts index f2531bd..1b7992c 100644 --- a/packages/graphql/api/base.ts +++ b/packages/graphql/api/base.ts @@ -1,15 +1,39 @@ -type CustomerProfile = { +/* eslint-disable canonical/id-match */ +import { getClientWithToken } from '../apollo/client'; +import * as GQL from '../types'; + +const ERRORS = { + MISSING_TELEGRAM_ID: 'Missing telegram id', + NOT_FOUND_CUSTOMER: 'Customer not found', +}; + +type UserProfile = { telegramId: number; }; export class BaseService { - protected customer: CustomerProfile; + protected _user: UserProfile; - constructor(customer: CustomerProfile) { - if (!customer?.telegramId) { - throw new Error('Invalid customer profile: telegramId required'); + constructor(user: UserProfile) { + if (!user?.telegramId) { + throw new Error(ERRORS.MISSING_TELEGRAM_ID); } - this.customer = customer; + this._user = user; + } + + protected async _getUser() { + const { query } = await getClientWithToken(); + + const result = await query({ + query: GQL.GetCustomerDocument, + variables: this._user, + }); + + const customer = result.data.customers.at(0); + + if (!customer) throw new Error(ERRORS.NOT_FOUND_CUSTOMER); + + return { customer }; } } diff --git a/packages/graphql/api/customers.ts b/packages/graphql/api/customers.ts index b65cb42..91c45c7 100644 --- a/packages/graphql/api/customers.ts +++ b/packages/graphql/api/customers.ts @@ -39,7 +39,7 @@ export class CustomersService extends BaseService { const result = await query({ query: GQL.GetClientsDocument, variables: { - telegramId: variables?.telegramId || this.customer.telegramId, + telegramId: variables?.telegramId || this._user.telegramId, }, }); @@ -65,7 +65,7 @@ export class CustomersService extends BaseService { const result = await query({ query: GQL.GetMastersDocument, variables: { - telegramId: variables?.telegramId || this.customer.telegramId, + telegramId: variables?.telegramId || this._user.telegramId, }, }); @@ -75,9 +75,8 @@ export class CustomersService extends BaseService { async updateCustomer( variables: Omit, 'documentId'>, ) { - const { customer } = await this.getCustomer(this.customer); + const { customer } = await this._getUser(); - if (!customer) throw new Error('Customer not found'); const { mutate } = await getClientWithToken(); const mutationResult = await mutate({ diff --git a/packages/graphql/api/orders.ts b/packages/graphql/api/orders.ts index 044ec11..0ae89e8 100644 --- a/packages/graphql/api/orders.ts +++ b/packages/graphql/api/orders.ts @@ -1,7 +1,6 @@ import { getClientWithToken } from '../apollo/client'; import * as GQL from '../types'; import { BaseService } from './base'; -import { CustomersService } from './customers'; import { ServicesService } from './services'; import { type VariablesOf } from '@graphql-typed-document-node/core'; import { isCustomerMaster } from '@repo/utils/customer'; @@ -16,12 +15,13 @@ const ERRORS = { MISSING_SERVICES: 'Missing services', MISSING_SLOT: 'Missing slot id', MISSING_START_TIME: 'Missing time start', - MISSING_USER: 'User not found', NO_PERMISSION: 'No permission', }; export class OrdersService extends BaseService { async createOrder(variables: VariablesOf) { + const { customer } = await this._getUser(); + // Проверки на существование обязательных полей для предотвращения ошибок типов if (!variables.input.slot) throw new Error(ERRORS.MISSING_SLOT); if (!variables.input.services?.length) throw new Error(ERRORS.MISSING_SERVICES); @@ -29,15 +29,12 @@ export class OrdersService extends BaseService { if (!variables.input.datetime_start) throw new Error(ERRORS.MISSING_START_TIME); if (!variables.input.client) throw new Error(ERRORS.MISSING_CLIENT); - const customersService = new CustomersService(this.customer); - const servicesService = new ServicesService(this.customer); - - const { customer } = await customersService.getCustomer(this.customer); - if (!customer) throw new Error(ERRORS.MISSING_USER); + const servicesService = new ServicesService(this._user); const { service } = await servicesService.getService({ documentId: variables.input.services[0], }); + if (!service?.duration) throw new Error(ERRORS.INVALID_SERVICE_DURATION); const datetimeEnd = dayjs(variables.input.datetime_start) @@ -89,10 +86,7 @@ export class OrdersService extends BaseService { } async updateOrder(variables: VariablesOf) { - const customersService = new CustomersService(this.customer); - const { customer } = await customersService.getCustomer(this.customer); - - if (!customer) throw new Error(ERRORS.MISSING_USER); + const { customer } = await this._getUser(); const { query } = await getClientWithToken(); diff --git a/packages/graphql/api/services.ts b/packages/graphql/api/services.ts index b63d6bb..63adec9 100644 --- a/packages/graphql/api/services.ts +++ b/packages/graphql/api/services.ts @@ -1,14 +1,15 @@ import { getClientWithToken } from '../apollo/client'; import * as GQL from '../types'; import { BaseService } from './base'; -import { CustomersService } from './customers'; import { type VariablesOf } from '@graphql-typed-document-node/core'; +const ERRORS = { + NO_PERMISSION: 'No permission', +}; + export class ServicesService extends BaseService { async createService(variables: VariablesOf) { - const customerService = new CustomersService(this.customer); - - const { customer } = await customerService.getCustomer(this.customer); + const { customer } = await this._getUser(); const { mutate } = await getClientWithToken(); @@ -70,12 +71,10 @@ export class ServicesService extends BaseService { private async checkPermission( variables: Pick, 'documentId'>, ) { - const customerService = new CustomersService(this.customer); - - const { customer } = await customerService.getCustomer(this.customer); + const { customer } = await this._getUser(); const { service } = await this.getService({ documentId: variables.documentId }); - if (service?.master?.documentId !== customer?.documentId) throw new Error('No permission'); + if (service?.master?.documentId !== customer?.documentId) throw new Error(ERRORS.NO_PERMISSION); } } diff --git a/packages/graphql/api/slots.ts b/packages/graphql/api/slots.ts index e051c68..3ba9837 100644 --- a/packages/graphql/api/slots.ts +++ b/packages/graphql/api/slots.ts @@ -1,17 +1,21 @@ import { getClientWithToken } from '../apollo/client'; import * as GQL from '../types'; import { BaseService } from './base'; -import { CustomersService } from './customers'; import { ServicesService } from './services'; import { type VariablesOf } from '@graphql-typed-document-node/core'; import { getMinutes } from '@repo/utils/datetime-format'; import dayjs from 'dayjs'; +const ERRORS = { + MISSING_DATE: 'Missing date', + MISSING_SERVICE: 'Missing service', + MISSING_SERVICE_ID: 'Missing service id', + NO_PERMISSION: 'No permission', +}; + export class SlotsService extends BaseService { async createSlot(variables: VariablesOf) { - const customerService = new CustomersService(this.customer); - - const { customer } = await customerService.getCustomer(this.customer); + const { customer } = await this._getUser(); const { mutate } = await getClientWithToken(); @@ -33,6 +37,8 @@ export class SlotsService extends BaseService { } async deleteSlot(variables: VariablesOf) { + await this.checkPermission(variables); + const { mutate } = await getClientWithToken(); const mutationResult = await mutate({ @@ -50,8 +56,8 @@ export class SlotsService extends BaseService { variables: VariablesOf, context: { service: GQL.ServiceFiltersInput }, ) { - if (!variables.filters?.datetime_start) throw new Error('Missing date'); - if (!context?.service?.documentId?.eq) throw new Error('Missing service id'); + if (!variables.filters?.datetime_start) throw new Error(ERRORS.MISSING_DATE); + if (!context?.service?.documentId?.eq) throw new Error(ERRORS.MISSING_SERVICE_ID); const { query } = await getClientWithToken(); @@ -67,13 +73,13 @@ export class SlotsService extends BaseService { if (getSlotsResult.error) throw new Error(getSlotsResult.error.message); - const servicesService = new ServicesService(this.customer); + const servicesService = new ServicesService(this._user); const { service } = await servicesService.getService({ documentId: context.service.documentId.eq, }); - if (!service) throw new Error('Service not found'); + if (!service) throw new Error(ERRORS.MISSING_SERVICE); const serviceDuration = getMinutes(service.duration); @@ -135,6 +141,8 @@ export class SlotsService extends BaseService { } async updateSlot(variables: VariablesOf) { + await this.checkPermission(variables); + const { mutate } = await getClientWithToken(); const mutationResult = await mutate({ @@ -147,4 +155,14 @@ export class SlotsService extends BaseService { return mutationResult.data; } + + private async checkPermission( + variables: Pick, 'documentId'>, + ) { + const { customer } = await this._getUser(); + + const { slot } = await this.getSlot({ documentId: variables.documentId }); + + if (slot?.master?.documentId !== customer?.documentId) throw new Error(ERRORS.NO_PERMISSION); + } }