Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e55cee443b | ||
|
|
c3634b3aba | ||
|
|
cd576f5378 |
Vendored
+2
@@ -0,0 +1,2 @@
|
|||||||
|
undecided:
|
||||||
|
- "@calcom/prisma"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { getUserAvailability } from "@calcom/lib/getUserAvailability";
|
import { getUserAvailabilityService } from "@calcom/lib/di/containers/get-user-availability";
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
@@ -191,8 +191,9 @@ const availabilitySchema = z
|
|||||||
async function handler(req: NextApiRequest) {
|
async function handler(req: NextApiRequest) {
|
||||||
const { isSystemWideAdmin, userId: reqUserId } = req;
|
const { isSystemWideAdmin, userId: reqUserId } = req;
|
||||||
const { username, userId, eventTypeId, dateTo, dateFrom, teamId } = availabilitySchema.parse(req.query);
|
const { username, userId, eventTypeId, dateTo, dateFrom, teamId } = availabilitySchema.parse(req.query);
|
||||||
|
const userAvailabilityService = getUserAvailabilityService()
|
||||||
if (!teamId)
|
if (!teamId)
|
||||||
return getUserAvailability({
|
return userAvailabilityService.getUserAvailability({
|
||||||
username,
|
username,
|
||||||
dateFrom,
|
dateFrom,
|
||||||
dateTo,
|
dateTo,
|
||||||
@@ -230,7 +231,7 @@ async function handler(req: NextApiRequest) {
|
|||||||
const availabilities = members.map(async (user) => {
|
const availabilities = members.map(async (user) => {
|
||||||
return {
|
return {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
availability: await getUserAvailability({
|
availability: await userAvailabilityService.getUserAvailability({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
dateFrom,
|
dateFrom,
|
||||||
dateTo,
|
dateTo,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
"@axiomhq/winston": "^1.2.0",
|
"@axiomhq/winston": "^1.2.0",
|
||||||
"@calcom/platform-constants": "*",
|
"@calcom/platform-constants": "*",
|
||||||
"@calcom/platform-enums": "*",
|
"@calcom/platform-enums": "*",
|
||||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.276",
|
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.283",
|
||||||
"@calcom/platform-types": "*",
|
"@calcom/platform-types": "*",
|
||||||
"@calcom/platform-utils": "*",
|
"@calcom/platform-utils": "*",
|
||||||
"@calcom/prisma": "*",
|
"@calcom/prisma": "*",
|
||||||
|
|||||||
+4
-1
@@ -290,7 +290,10 @@ describe("Event types Endpoints", () => {
|
|||||||
expect(responseBookingFields).toBeDefined();
|
expect(responseBookingFields).toBeDefined();
|
||||||
// note(Lauris): response bookingFields are already existing default bookingFields + the new one
|
// note(Lauris): response bookingFields are already existing default bookingFields + the new one
|
||||||
const responseBookingField = responseBookingFields.find((field) => field.name === bookingFieldName);
|
const responseBookingField = responseBookingFields.find((field) => field.name === bookingFieldName);
|
||||||
expect(responseBookingField).toEqual(bookingFields[0]);
|
const fields = responseBookingField
|
||||||
|
//@ts-ignore
|
||||||
|
delete fields.labelAsSafeHtml
|
||||||
|
expect(fields).toEqual(bookingFields[0]);
|
||||||
eventType.bookingFields = responseBookingFields;
|
eventType.bookingFields = responseBookingFields;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { CacheService } from "@/lib/services/cache.service";
|
|||||||
import { CheckBookingLimitsService } from "@/lib/services/check-booking-limits.service";
|
import { CheckBookingLimitsService } from "@/lib/services/check-booking-limits.service";
|
||||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||||
import { Module } from "@nestjs/common";
|
import { Module } from "@nestjs/common";
|
||||||
|
import { UserAvailabilityService } from "@/lib/services/user-availability.service";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [PrismaModule],
|
imports: [PrismaModule],
|
||||||
@@ -28,6 +29,7 @@ import { Module } from "@nestjs/common";
|
|||||||
CheckBookingLimitsService,
|
CheckBookingLimitsService,
|
||||||
CacheService,
|
CacheService,
|
||||||
AvailableSlotsService,
|
AvailableSlotsService,
|
||||||
|
UserAvailabilityService
|
||||||
],
|
],
|
||||||
exports: [AvailableSlotsService],
|
exports: [AvailableSlotsService],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { CheckBookingLimitsService } from "@/lib/services/check-booking-limits.s
|
|||||||
import { Injectable } from "@nestjs/common";
|
import { Injectable } from "@nestjs/common";
|
||||||
|
|
||||||
import { AvailableSlotsService as BaseAvailableSlotsService } from "@calcom/platform-libraries/slots";
|
import { AvailableSlotsService as BaseAvailableSlotsService } from "@calcom/platform-libraries/slots";
|
||||||
|
import { UserAvailabilityService } from "./user-availability.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AvailableSlotsService extends BaseAvailableSlotsService {
|
export class AvailableSlotsService extends BaseAvailableSlotsService {
|
||||||
@@ -37,6 +38,7 @@ export class AvailableSlotsService extends BaseAvailableSlotsService {
|
|||||||
userRepo: userRepository,
|
userRepo: userRepository,
|
||||||
checkBookingLimitsService: new CheckBookingLimitsService(bookingRepository) as any,
|
checkBookingLimitsService: new CheckBookingLimitsService(bookingRepository) as any,
|
||||||
cacheService: new CacheService(featuresRepository),
|
cacheService: new CacheService(featuresRepository),
|
||||||
|
userAvailabilityService: new UserAvailabilityService(oooRepoDependency, bookingRepository, eventTypeRepository)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { PrismaBookingRepository } from "@/lib/repositories/prisma-booking.repository";
|
||||||
|
import { PrismaEventTypeRepository } from "@/lib/repositories/prisma-event-type.repository";
|
||||||
|
|
||||||
|
import { PrismaOOORepository } from "@/lib/repositories/prisma-ooo.repository";
|
||||||
|
|
||||||
|
import { Injectable } from "@nestjs/common";
|
||||||
|
|
||||||
|
import { UserAvailabilityService as BaseUserAvailabilityService } from "@calcom/platform-libraries/schedules";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserAvailabilityService extends BaseUserAvailabilityService {
|
||||||
|
constructor(
|
||||||
|
oooRepoDependency: PrismaOOORepository,
|
||||||
|
bookingRepository: PrismaBookingRepository,
|
||||||
|
eventTypeRepository: PrismaEventTypeRepository,
|
||||||
|
|
||||||
|
|
||||||
|
) {
|
||||||
|
super({
|
||||||
|
oooRepo: oooRepoDependency,
|
||||||
|
|
||||||
|
bookingRepo: bookingRepository,
|
||||||
|
|
||||||
|
eventTypeRepo: eventTypeRepository,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -403,6 +403,10 @@ export class BillingService implements OnModuleDestroy {
|
|||||||
fromReschedule?: string | null;
|
fromReschedule?: string | null;
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
if (this.configService.get("e2e")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
const { uid, startTime, fromReschedule } = booking;
|
const { uid, startTime, fromReschedule } = booking;
|
||||||
|
|
||||||
const delay = startTime.getTime() - Date.now();
|
const delay = startTime.getTime() - Date.now();
|
||||||
@@ -427,6 +431,9 @@ export class BillingService implements OnModuleDestroy {
|
|||||||
* Removing an attendee from a booking does not cancel the usage increment job.
|
* Removing an attendee from a booking does not cancel the usage increment job.
|
||||||
*/
|
*/
|
||||||
async cancelUsageByBookingUid(bookingUid: string) {
|
async cancelUsageByBookingUid(bookingUid: string) {
|
||||||
|
if (this.configService.get("e2e")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
const job = await this.billingQueue.getJob(`increment-${bookingUid}`);
|
const job = await this.billingQueue.getJob(`increment-${bookingUid}`);
|
||||||
if (job) {
|
if (job) {
|
||||||
await job.remove();
|
await job.remove();
|
||||||
@@ -458,6 +465,7 @@ export class BillingService implements OnModuleDestroy {
|
|||||||
|
|
||||||
async onModuleDestroy() {
|
async onModuleDestroy() {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
await this.billingQueue.close();
|
await this.billingQueue.close();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.error(err);
|
this.logger.error(err);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { checkForConflicts } from "@calcom/features/bookings/lib/conflictChecker
|
|||||||
import { buildDateRanges } from "@calcom/lib/date-ranges";
|
import { buildDateRanges } from "@calcom/lib/date-ranges";
|
||||||
import { ErrorCode } from "@calcom/lib/errorCodes";
|
import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||||
import { getBusyTimesForLimitChecks } from "@calcom/lib/getBusyTimes";
|
import { getBusyTimesForLimitChecks } from "@calcom/lib/getBusyTimes";
|
||||||
import { getUsersAvailability } from "@calcom/lib/getUserAvailability";
|
import { getUserAvailabilityService } from "@calcom/lib/di/containers/get-user-availability";
|
||||||
import { parseBookingLimit } from "@calcom/lib/intervalLimits/isBookingLimits";
|
import { parseBookingLimit } from "@calcom/lib/intervalLimits/isBookingLimits";
|
||||||
import { parseDurationLimit } from "@calcom/lib/intervalLimits/isDurationLimits";
|
import { parseDurationLimit } from "@calcom/lib/intervalLimits/isDurationLimits";
|
||||||
import { getPiiFreeUser } from "@calcom/lib/piiFreeData";
|
import { getPiiFreeUser } from "@calcom/lib/piiFreeData";
|
||||||
@@ -62,6 +62,7 @@ const _ensureAvailableUsers = async (
|
|||||||
shouldServeCache?: boolean
|
shouldServeCache?: boolean
|
||||||
// ReturnType hint of at least one IsFixedAwareUser, as it's made sure at least one entry exists
|
// ReturnType hint of at least one IsFixedAwareUser, as it's made sure at least one entry exists
|
||||||
): Promise<[IsFixedAwareUser, ...IsFixedAwareUser[]]> => {
|
): Promise<[IsFixedAwareUser, ...IsFixedAwareUser[]]> => {
|
||||||
|
const userAvailabilityService = getUserAvailabilityService()
|
||||||
const availableUsers: IsFixedAwareUser[] = [];
|
const availableUsers: IsFixedAwareUser[] = [];
|
||||||
|
|
||||||
const startDateTimeUtc = getDateTimeInUtc(input.dateFrom, input.timeZone);
|
const startDateTimeUtc = getDateTimeInUtc(input.dateFrom, input.timeZone);
|
||||||
@@ -86,7 +87,7 @@ const _ensureAvailableUsers = async (
|
|||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const usersAvailability = await getUsersAvailability({
|
const usersAvailability = await userAvailabilityService.getUsersAvailability({
|
||||||
users: eventType.users,
|
users: eventType.users,
|
||||||
query: {
|
query: {
|
||||||
...input,
|
...input,
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export default function InsightsPage() {
|
|||||||
|
|
||||||
## Step 4: Create tRPC Handler
|
## Step 4: Create tRPC Handler
|
||||||
|
|
||||||
Add the tRPC endpoint in the insights router using the `createInsightsBookingService()` helper:
|
Add the tRPC endpoint in the insights router using the `getInsightsBookingService()` DI container function:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// packages/features/insights/server/trpc-router.ts
|
// packages/features/insights/server/trpc-router.ts
|
||||||
@@ -118,6 +118,7 @@ export const insightsRouter = router({
|
|||||||
myNewChartData: userBelongsToTeamProcedure
|
myNewChartData: userBelongsToTeamProcedure
|
||||||
.input(bookingRepositoryBaseInputSchema)
|
.input(bookingRepositoryBaseInputSchema)
|
||||||
.query(async ({ ctx, input }) => {
|
.query(async ({ ctx, input }) => {
|
||||||
|
// `createInsightsBookingService` is defined at the root level in this file
|
||||||
const insightsBookingService = createInsightsBookingService(ctx, input);
|
const insightsBookingService = createInsightsBookingService(ctx, input);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -129,13 +130,13 @@ export const insightsRouter = router({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Step 5: Add Service Method to InsightsBookingService
|
## Step 5: Add Service Method to InsightsBookingBaseService
|
||||||
|
|
||||||
Add your new method to the `InsightsBookingService` class:
|
Add your new method to the `InsightsBookingBaseService` class:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// packages/lib/server/service/insightsBooking.ts
|
// packages/lib/server/service/InsightsBookingBaseService.ts
|
||||||
export class InsightsBookingService {
|
export class InsightsBookingBaseService {
|
||||||
// ... existing methods
|
// ... existing methods
|
||||||
|
|
||||||
async getMyNewChartData() {
|
async getMyNewChartData() {
|
||||||
@@ -168,7 +169,7 @@ export class InsightsBookingService {
|
|||||||
|
|
||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
1. **Use `createInsightsBookingService()`**: Always use the helper function for consistent service creation
|
1. **Use `getInsightsBookingService()`**: Always use the DI container function for consistent service creation
|
||||||
2. **Raw SQL for Performance**: Use `$queryRaw` for complex aggregations and better performance
|
2. **Raw SQL for Performance**: Use `$queryRaw` for complex aggregations and better performance
|
||||||
3. **Base Conditions**: Always use `await this.getBaseConditions()` for proper filtering and permissions
|
3. **Base Conditions**: Always use `await this.getBaseConditions()` for proper filtering and permissions
|
||||||
4. **Error Handling**: Wrap service calls in try-catch blocks with `TRPCError`
|
4. **Error Handling**: Wrap service calls in try-catch blocks with `TRPCError`
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import {
|
|||||||
routingRepositoryBaseInputSchema,
|
routingRepositoryBaseInputSchema,
|
||||||
bookingRepositoryBaseInputSchema,
|
bookingRepositoryBaseInputSchema,
|
||||||
} from "@calcom/features/insights/server/raw-data.schema";
|
} from "@calcom/features/insights/server/raw-data.schema";
|
||||||
|
import { getInsightsBookingService } from "@calcom/lib/di/containers/insights-booking";
|
||||||
import { getInsightsRoutingService } from "@calcom/lib/di/containers/insights-routing";
|
import { getInsightsRoutingService } from "@calcom/lib/di/containers/insights-routing";
|
||||||
import { InsightsBookingService } from "@calcom/lib/server/service/insightsBooking";
|
|
||||||
import type { readonlyPrisma } from "@calcom/prisma";
|
import type { readonlyPrisma } from "@calcom/prisma";
|
||||||
import { BookingStatus } from "@calcom/prisma/enums";
|
import { BookingStatus } from "@calcom/prisma/enums";
|
||||||
import authedProcedure from "@calcom/trpc/server/procedures/authedProcedure";
|
import authedProcedure from "@calcom/trpc/server/procedures/authedProcedure";
|
||||||
@@ -316,14 +316,13 @@ const BATCH_SIZE = 1000; // Adjust based on your needs
|
|||||||
* Helper function to create InsightsBookingService with standardized parameters
|
* Helper function to create InsightsBookingService with standardized parameters
|
||||||
*/
|
*/
|
||||||
function createInsightsBookingService(
|
function createInsightsBookingService(
|
||||||
ctx: { insightsDb: typeof readonlyPrisma; user: { id: number; organizationId: number | null } },
|
ctx: { user: { id: number; organizationId: number | null } },
|
||||||
input: z.infer<typeof bookingRepositoryBaseInputSchema>,
|
input: z.infer<typeof bookingRepositoryBaseInputSchema>,
|
||||||
dateTarget: "createdAt" | "startTime" = "createdAt"
|
dateTarget: "createdAt" | "startTime" = "createdAt"
|
||||||
) {
|
) {
|
||||||
const { scope, selectedTeamId, startDate, endDate, columnFilters } = input;
|
const { scope, selectedTeamId, startDate, endDate, columnFilters } = input;
|
||||||
|
|
||||||
return new InsightsBookingService({
|
return getInsightsBookingService({
|
||||||
prisma: ctx.insightsDb,
|
|
||||||
options: {
|
options: {
|
||||||
scope,
|
scope,
|
||||||
userId: ctx.user.id,
|
userId: ctx.user.id,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { scheduleRepositoryModule } from "../modules/schedule";
|
|||||||
import { selectedSlotsRepositoryModule } from "../modules/selectedSlots";
|
import { selectedSlotsRepositoryModule } from "../modules/selectedSlots";
|
||||||
import { teamRepositoryModule } from "../modules/team";
|
import { teamRepositoryModule } from "../modules/team";
|
||||||
import { userRepositoryModule } from "../modules/user";
|
import { userRepositoryModule } from "../modules/user";
|
||||||
|
import { getUserAvailabilityModule } from "../modules/get-user-availability";
|
||||||
|
|
||||||
const container = createContainer();
|
const container = createContainer();
|
||||||
container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
|
container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
|
||||||
@@ -31,7 +32,7 @@ container.load(DI_TOKENS.FEATURES_REPOSITORY_MODULE, featuresRepositoryModule);
|
|||||||
container.load(DI_TOKENS.CACHE_SERVICE_MODULE, cacheModule);
|
container.load(DI_TOKENS.CACHE_SERVICE_MODULE, cacheModule);
|
||||||
container.load(DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE_MODULE, checkBookingLimitsModule);
|
container.load(DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE_MODULE, checkBookingLimitsModule);
|
||||||
container.load(DI_TOKENS.AVAILABLE_SLOTS_SERVICE_MODULE, availableSlotsModule);
|
container.load(DI_TOKENS.AVAILABLE_SLOTS_SERVICE_MODULE, availableSlotsModule);
|
||||||
|
container.load(DI_TOKENS.GET_USER_AVAILABILITY_SERVICE_MODULE, getUserAvailabilityModule)
|
||||||
export function getAvailableSlotsService() {
|
export function getAvailableSlotsService() {
|
||||||
return container.get<AvailableSlotsService>(DI_TOKENS.AVAILABLE_SLOTS_SERVICE);
|
return container.get<AvailableSlotsService>(DI_TOKENS.AVAILABLE_SLOTS_SERVICE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { createContainer } from "@evyweb/ioctopus";
|
||||||
|
|
||||||
|
import { DI_TOKENS } from "@calcom/lib/di/tokens";
|
||||||
|
import { prismaModule } from "@calcom/prisma/prisma.module";
|
||||||
|
|
||||||
|
import { getUserAvailabilityModule } from "../modules/get-user-availability";
|
||||||
|
import { bookingRepositoryModule } from "../modules/booking";
|
||||||
|
|
||||||
|
import { eventTypeRepositoryModule } from "../modules/eventType";
|
||||||
|
|
||||||
|
import { oooRepositoryModule } from "../modules/ooo";
|
||||||
|
import { UserAvailabilityService } from "../../getUserAvailability";
|
||||||
|
|
||||||
|
const container = createContainer();
|
||||||
|
container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
|
||||||
|
container.load(DI_TOKENS.OOO_REPOSITORY_MODULE, oooRepositoryModule);
|
||||||
|
container.load(DI_TOKENS.BOOKING_REPOSITORY_MODULE, bookingRepositoryModule);
|
||||||
|
container.load(DI_TOKENS.EVENT_TYPE_REPOSITORY_MODULE, eventTypeRepositoryModule);
|
||||||
|
container.load(DI_TOKENS.GET_USER_AVAILABILITY_SERVICE_MODULE, getUserAvailabilityModule);
|
||||||
|
|
||||||
|
export function getUserAvailabilityService() {
|
||||||
|
return container.get<UserAvailabilityService>(DI_TOKENS.GET_USER_AVAILABILITY_SERVICE);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { createContainer } from "@evyweb/ioctopus";
|
||||||
|
|
||||||
|
import { DI_TOKENS } from "@calcom/lib/di/tokens";
|
||||||
|
import type {
|
||||||
|
InsightsBookingServicePublicOptions,
|
||||||
|
InsightsBookingServiceFilterOptions,
|
||||||
|
InsightsBookingBaseService,
|
||||||
|
} from "@calcom/lib/server/service/InsightsBookingBaseService";
|
||||||
|
import type { InsightsBookingService } from "@calcom/lib/server/service/InsightsBookingDIService";
|
||||||
|
import { prismaModule } from "@calcom/prisma/prisma.module";
|
||||||
|
|
||||||
|
import { insightsBookingModule } from "../modules/insights-booking";
|
||||||
|
|
||||||
|
export function getInsightsBookingService({
|
||||||
|
options,
|
||||||
|
filters,
|
||||||
|
}: {
|
||||||
|
options: InsightsBookingServicePublicOptions;
|
||||||
|
filters?: InsightsBookingServiceFilterOptions;
|
||||||
|
}): InsightsBookingBaseService {
|
||||||
|
const container = createContainer();
|
||||||
|
container.load(DI_TOKENS.READ_ONLY_PRISMA_CLIENT, prismaModule);
|
||||||
|
container.load(DI_TOKENS.INSIGHTS_BOOKING_SERVICE_MODULE, insightsBookingModule);
|
||||||
|
|
||||||
|
const diService = container.get<InsightsBookingService>(DI_TOKENS.INSIGHTS_BOOKING_SERVICE);
|
||||||
|
return diService.create({ options, filters });
|
||||||
|
}
|
||||||
@@ -17,4 +17,5 @@ availableSlotsModule.bind(DI_TOKENS.AVAILABLE_SLOTS_SERVICE).toClass(AvailableSl
|
|||||||
routingFormResponseRepo: DI_TOKENS.ROUTING_FORM_RESPONSE_REPOSITORY,
|
routingFormResponseRepo: DI_TOKENS.ROUTING_FORM_RESPONSE_REPOSITORY,
|
||||||
cacheService: DI_TOKENS.CACHE_SERVICE,
|
cacheService: DI_TOKENS.CACHE_SERVICE,
|
||||||
checkBookingLimitsService: DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE,
|
checkBookingLimitsService: DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE,
|
||||||
|
userAvailabilityService: DI_TOKENS.GET_USER_AVAILABILITY_SERVICE
|
||||||
} satisfies Record<keyof IAvailableSlotsService, symbol>);
|
} satisfies Record<keyof IAvailableSlotsService, symbol>);
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { createModule } from "@evyweb/ioctopus";
|
||||||
|
|
||||||
|
import { DI_TOKENS } from "../tokens";
|
||||||
|
import { IUserAvailabilityService, UserAvailabilityService } from "../../getUserAvailability";
|
||||||
|
|
||||||
|
export const getUserAvailabilityModule = createModule();
|
||||||
|
getUserAvailabilityModule.bind(DI_TOKENS.GET_USER_AVAILABILITY_SERVICE).toClass(UserAvailabilityService, {
|
||||||
|
oooRepo: DI_TOKENS.OOO_REPOSITORY,
|
||||||
|
bookingRepo: DI_TOKENS.BOOKING_REPOSITORY,
|
||||||
|
eventTypeRepo: DI_TOKENS.EVENT_TYPE_REPOSITORY,
|
||||||
|
} satisfies Record<keyof IUserAvailabilityService, symbol>);
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { createModule } from "@evyweb/ioctopus";
|
||||||
|
|
||||||
|
import type { IInsightsBookingService } from "@calcom/lib/server/service/InsightsBookingDIService";
|
||||||
|
import { InsightsBookingService } from "@calcom/lib/server/service/InsightsBookingDIService";
|
||||||
|
|
||||||
|
import { DI_TOKENS } from "../tokens";
|
||||||
|
|
||||||
|
export const insightsBookingModule = createModule();
|
||||||
|
insightsBookingModule.bind(DI_TOKENS.INSIGHTS_BOOKING_SERVICE).toClass(InsightsBookingService, {
|
||||||
|
prisma: DI_TOKENS.READ_ONLY_PRISMA_CLIENT,
|
||||||
|
} satisfies Record<keyof IInsightsBookingService, symbol>);
|
||||||
@@ -22,6 +22,8 @@ export const DI_TOKENS = {
|
|||||||
AVAILABLE_SLOTS_SERVICE_MODULE: Symbol("AvailableSlotsModule"),
|
AVAILABLE_SLOTS_SERVICE_MODULE: Symbol("AvailableSlotsModule"),
|
||||||
INSIGHTS_ROUTING_SERVICE: Symbol("InsightsRoutingService"),
|
INSIGHTS_ROUTING_SERVICE: Symbol("InsightsRoutingService"),
|
||||||
INSIGHTS_ROUTING_SERVICE_MODULE: Symbol("InsightsRoutingServiceModule"),
|
INSIGHTS_ROUTING_SERVICE_MODULE: Symbol("InsightsRoutingServiceModule"),
|
||||||
|
INSIGHTS_BOOKING_SERVICE: Symbol("InsightsBookingService"),
|
||||||
|
INSIGHTS_BOOKING_SERVICE_MODULE: Symbol("InsightsBookingServiceModule"),
|
||||||
FEATURES_REPOSITORY: Symbol("FeaturesRepository"),
|
FEATURES_REPOSITORY: Symbol("FeaturesRepository"),
|
||||||
FEATURES_REPOSITORY_MODULE: Symbol("FeaturesRepositoryModule"),
|
FEATURES_REPOSITORY_MODULE: Symbol("FeaturesRepositoryModule"),
|
||||||
CACHE_SERVICE: Symbol("CacheService"),
|
CACHE_SERVICE: Symbol("CacheService"),
|
||||||
@@ -30,4 +32,6 @@ export const DI_TOKENS = {
|
|||||||
CHECK_BOOKING_LIMITS_SERVICE_MODULE: Symbol("CheckBookingLimitsServiceModule"),
|
CHECK_BOOKING_LIMITS_SERVICE_MODULE: Symbol("CheckBookingLimitsServiceModule"),
|
||||||
CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE: Symbol("CheckBookingAndDurationLimitsService"),
|
CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE: Symbol("CheckBookingAndDurationLimitsService"),
|
||||||
CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE_MODULE: Symbol("CheckBookingAndDurationLimitsServiceModule"),
|
CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE_MODULE: Symbol("CheckBookingAndDurationLimitsServiceModule"),
|
||||||
|
GET_USER_AVAILABILITY_SERVICE: Symbol("GetUserAvailabilityService"),
|
||||||
|
GET_USER_AVAILABILITY_SERVICE_MODULE: Symbol("GetUserAvailabilityModule"),
|
||||||
};
|
};
|
||||||
|
|||||||
+468
-609
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
|||||||
import type { Dayjs } from "@calcom/dayjs";
|
import type { Dayjs } from "@calcom/dayjs";
|
||||||
import dayjs from "@calcom/dayjs";
|
import dayjs from "@calcom/dayjs";
|
||||||
import { getCheckBookingLimitsService } from "@calcom/lib/di/containers/booking-limits";
|
import { getCheckBookingLimitsService } from "@calcom/lib/di/containers/booking-limits";
|
||||||
|
import { getUserAvailabilityService } from "@calcom/lib/di/containers/get-user-availability";
|
||||||
import { getStartEndDateforLimitCheck } from "@calcom/lib/getBusyTimes";
|
import { getStartEndDateforLimitCheck } from "@calcom/lib/getBusyTimes";
|
||||||
import type { EventType } from "@calcom/lib/getUserAvailability";
|
import type { EventType } from "@calcom/lib/getUserAvailability";
|
||||||
import { getPeriodStartDatesBetween } from "@calcom/lib/getUserAvailability";
|
|
||||||
import { withReporting } from "@calcom/lib/sentryWrapper";
|
import { withReporting } from "@calcom/lib/sentryWrapper";
|
||||||
import { performance } from "@calcom/lib/server/perfObserver";
|
import { performance } from "@calcom/lib/server/perfObserver";
|
||||||
import { getTotalBookingDuration } from "@calcom/lib/server/queries/booking";
|
import { getTotalBookingDuration } from "@calcom/lib/server/queries/booking";
|
||||||
@@ -86,6 +86,7 @@ const _getBusyTimesFromBookingLimits = async (params: {
|
|||||||
includeManagedEvents?: boolean;
|
includeManagedEvents?: boolean;
|
||||||
timeZone?: string | null;
|
timeZone?: string | null;
|
||||||
}) => {
|
}) => {
|
||||||
|
const userAvailabilityService = getUserAvailabilityService();
|
||||||
const {
|
const {
|
||||||
bookings,
|
bookings,
|
||||||
bookingLimits,
|
bookingLimits,
|
||||||
@@ -105,7 +106,7 @@ const _getBusyTimesFromBookingLimits = async (params: {
|
|||||||
if (!limit) continue;
|
if (!limit) continue;
|
||||||
|
|
||||||
const unit = intervalLimitKeyToUnit(key);
|
const unit = intervalLimitKeyToUnit(key);
|
||||||
const periodStartDates = getPeriodStartDatesBetween(dateFrom, dateTo, unit);
|
const periodStartDates = userAvailabilityService.getPeriodStartDatesBetween(dateFrom, dateTo, unit);
|
||||||
|
|
||||||
for (const periodStart of periodStartDates) {
|
for (const periodStart of periodStartDates) {
|
||||||
if (limitManager.isAlreadyBusy(periodStart, unit)) continue;
|
if (limitManager.isAlreadyBusy(periodStart, unit)) continue;
|
||||||
@@ -162,12 +163,14 @@ const _getBusyTimesFromDurationLimits = async (
|
|||||||
timeZone: string,
|
timeZone: string,
|
||||||
rescheduleUid?: string
|
rescheduleUid?: string
|
||||||
) => {
|
) => {
|
||||||
|
const userAvailabilityService = getUserAvailabilityService();
|
||||||
|
|
||||||
for (const key of descendingLimitKeys) {
|
for (const key of descendingLimitKeys) {
|
||||||
const limit = durationLimits?.[key];
|
const limit = durationLimits?.[key];
|
||||||
if (!limit) continue;
|
if (!limit) continue;
|
||||||
|
|
||||||
const unit = intervalLimitKeyToUnit(key);
|
const unit = intervalLimitKeyToUnit(key);
|
||||||
const periodStartDates = getPeriodStartDatesBetween(dateFrom, dateTo, unit);
|
const periodStartDates = userAvailabilityService.getPeriodStartDatesBetween(dateFrom, dateTo, unit);
|
||||||
|
|
||||||
for (const periodStart of periodStartDates) {
|
for (const periodStart of periodStartDates) {
|
||||||
if (limitManager.isAlreadyBusy(periodStart, unit)) continue;
|
if (limitManager.isAlreadyBusy(periodStart, unit)) continue;
|
||||||
|
|||||||
+22
-15
@@ -1,12 +1,13 @@
|
|||||||
import { createInstance } from "i18next";
|
import { createInstance } from "i18next";
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const { i18n } = require("@calcom/config/next-i18next.config");
|
|
||||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
|
|
||||||
import { fetchWithTimeout } from "../fetchWithTimeout";
|
import { fetchWithTimeout } from "../fetchWithTimeout";
|
||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
const { i18n } = require("@calcom/config/next-i18next.config");
|
||||||
|
|
||||||
const translationCache = new Map<string, Record<string, string>>();
|
const translationCache = new Map<string, Record<string, string>>();
|
||||||
const i18nInstanceCache = new Map<string, any>();
|
const i18nInstanceCache = new Map<string, any>();
|
||||||
const SUPPORTED_NAMESPACES = ["common"];
|
const SUPPORTED_NAMESPACES = ["common"];
|
||||||
@@ -28,22 +29,28 @@ export async function loadTranslations(_locale: string, _ns: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const url = `${WEBAPP_URL}/static/locales/${locale}/${ns}.json`;
|
const url = `${WEBAPP_URL}/static/locales/${locale}/${ns}.json`;
|
||||||
const response = await fetchWithTimeout(
|
try {
|
||||||
url,
|
const response = await fetchWithTimeout(
|
||||||
{
|
url,
|
||||||
cache: process.env.NODE_ENV === "production" ? "force-cache" : "no-store",
|
{
|
||||||
},
|
cache: process.env.NODE_ENV === "production" ? "force-cache" : "no-store",
|
||||||
3000
|
},
|
||||||
);
|
3000
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
logger.error(`Failed to fetch translations: ${response.status}`);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const translations = await response.json();
|
||||||
|
translationCache.set(cacheKey, translations);
|
||||||
|
return translations;
|
||||||
|
} catch (err) {
|
||||||
|
console.error("loadTranslations Error:", err);
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
logger.error(`Failed to fetch translations: ${response.status}`);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const translations = await response.json();
|
|
||||||
translationCache.set(cacheKey, translations);
|
|
||||||
return translations;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -869,4 +869,26 @@ export class BookingRepository {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findAcceptedBookingByEventTypeId({eventTypeId, dateFrom, dateTo}: {eventTypeId?: number, dateFrom: string, dateTo: string}) {
|
||||||
|
return this.prismaClient.booking.findMany({
|
||||||
|
where: {
|
||||||
|
eventTypeId,
|
||||||
|
startTime: {
|
||||||
|
gte: dateFrom,
|
||||||
|
lte: dateTo,
|
||||||
|
},
|
||||||
|
status: BookingStatus.ACCEPTED,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
uid: true,
|
||||||
|
startTime: true,
|
||||||
|
attendees: {
|
||||||
|
select: {
|
||||||
|
email: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1299,4 +1299,93 @@ export class EventTypeRepository {
|
|||||||
}) {
|
}) {
|
||||||
return user.allSelectedCalendars.filter((calendar) => calendar.eventTypeId === eventTypeId);
|
return user.allSelectedCalendars.filter((calendar) => calendar.eventTypeId === eventTypeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findByIdForUserAvailability({ id }: { id: number }) {
|
||||||
|
const eventType = await this.prismaClient.eventType.findUnique({
|
||||||
|
where: { id },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
seatsPerTimeSlot: true,
|
||||||
|
bookingLimits: true,
|
||||||
|
useEventLevelSelectedCalendars: true,
|
||||||
|
parent: {
|
||||||
|
select: {
|
||||||
|
team: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
bookingLimits: true,
|
||||||
|
includeManagedEventsInLimits: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
team: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
bookingLimits: true,
|
||||||
|
includeManagedEventsInLimits: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hosts: {
|
||||||
|
select: {
|
||||||
|
user: {
|
||||||
|
select: {
|
||||||
|
email: true,
|
||||||
|
id: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
schedule: {
|
||||||
|
select: {
|
||||||
|
availability: {
|
||||||
|
select: {
|
||||||
|
date: true,
|
||||||
|
startTime: true,
|
||||||
|
endTime: true,
|
||||||
|
days: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
timeZone: true,
|
||||||
|
id: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
durationLimits: true,
|
||||||
|
assignAllTeamMembers: true,
|
||||||
|
schedulingType: true,
|
||||||
|
timeZone: true,
|
||||||
|
length: true,
|
||||||
|
metadata: true,
|
||||||
|
schedule: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
availability: {
|
||||||
|
select: {
|
||||||
|
days: true,
|
||||||
|
date: true,
|
||||||
|
startTime: true,
|
||||||
|
endTime: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
timeZone: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
availability: {
|
||||||
|
select: {
|
||||||
|
startTime: true,
|
||||||
|
endTime: true,
|
||||||
|
days: true,
|
||||||
|
date: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!eventType) {
|
||||||
|
return eventType;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...eventType,
|
||||||
|
metadata: EventTypeMetaDataSchema.parse(eventType.metadata),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,4 +79,71 @@ export class PrismaOOORepository {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findUserOOODays({userId, dateTo, dateFrom}: {userId: number, dateTo: string, dateFrom: string}) {
|
||||||
|
return this.prismaClient.outOfOfficeEntry.findMany({
|
||||||
|
where: {
|
||||||
|
userId,
|
||||||
|
OR: [
|
||||||
|
// outside of range
|
||||||
|
// (start <= 'dateTo' AND end >= 'dateFrom')
|
||||||
|
{
|
||||||
|
start: {
|
||||||
|
lte: dateTo,
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
gte: dateFrom,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// start is between dateFrom and dateTo but end is outside of range
|
||||||
|
// (start <= 'dateTo' AND end >= 'dateTo')
|
||||||
|
{
|
||||||
|
start: {
|
||||||
|
lte: dateTo,
|
||||||
|
},
|
||||||
|
|
||||||
|
end: {
|
||||||
|
gte: dateTo,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// end is between dateFrom and dateTo but start is outside of range
|
||||||
|
// (start <= 'dateFrom' OR end <= 'dateTo')
|
||||||
|
{
|
||||||
|
start: {
|
||||||
|
lte: dateFrom,
|
||||||
|
},
|
||||||
|
|
||||||
|
end: {
|
||||||
|
lte: dateTo,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
start: true,
|
||||||
|
end: true,
|
||||||
|
user: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
toUser: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
username: true,
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
reason: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
emoji: true,
|
||||||
|
reason: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -135,7 +135,7 @@ const NOTHING_CONDITION = Prisma.sql`1=0`;
|
|||||||
|
|
||||||
const bookingDataKeys = new Set(Object.keys(bookingDataSchema.shape));
|
const bookingDataKeys = new Set(Object.keys(bookingDataSchema.shape));
|
||||||
|
|
||||||
export class InsightsBookingService {
|
export class InsightsBookingBaseService {
|
||||||
private prisma: typeof readonlyPrisma;
|
private prisma: typeof readonlyPrisma;
|
||||||
private options: InsightsBookingServiceOptions | null;
|
private options: InsightsBookingServiceOptions | null;
|
||||||
private filters: InsightsBookingServiceFilterOptions | null;
|
private filters: InsightsBookingServiceFilterOptions | null;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import type { readonlyPrisma } from "@calcom/prisma";
|
||||||
|
|
||||||
|
import {
|
||||||
|
InsightsBookingBaseService,
|
||||||
|
type InsightsBookingServicePublicOptions,
|
||||||
|
type InsightsBookingServiceFilterOptions,
|
||||||
|
} from "./InsightsBookingBaseService";
|
||||||
|
|
||||||
|
export interface IInsightsBookingService {
|
||||||
|
prisma: typeof readonlyPrisma;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InsightsBookingService {
|
||||||
|
constructor(private readonly dependencies: IInsightsBookingService) {}
|
||||||
|
|
||||||
|
create({
|
||||||
|
options,
|
||||||
|
filters,
|
||||||
|
}: {
|
||||||
|
options: InsightsBookingServicePublicOptions;
|
||||||
|
filters?: InsightsBookingServiceFilterOptions;
|
||||||
|
}): InsightsBookingBaseService {
|
||||||
|
return new InsightsBookingBaseService({
|
||||||
|
prisma: this.dependencies.prisma,
|
||||||
|
options,
|
||||||
|
filters,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -6,7 +6,7 @@ import { ColumnFilterType } from "@calcom/features/data-table/lib/types";
|
|||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import { BookingStatus, MembershipRole } from "@calcom/prisma/enums";
|
import { BookingStatus, MembershipRole } from "@calcom/prisma/enums";
|
||||||
|
|
||||||
import { InsightsBookingService } from "../../service/insightsBooking";
|
import { InsightsBookingBaseService as InsightsBookingService } from "../InsightsBookingBaseService";
|
||||||
|
|
||||||
const NOTHING_CONDITION = Prisma.sql`1=0`;
|
const NOTHING_CONDITION = Prisma.sql`1=0`;
|
||||||
|
|
||||||
@@ -4,3 +4,4 @@ export {
|
|||||||
} from "@calcom/lib/server/repository/schedule";
|
} from "@calcom/lib/server/repository/schedule";
|
||||||
|
|
||||||
export { updateSchedule, type UpdateScheduleResponse } from "@calcom/lib/schedules/updateSchedule";
|
export { updateSchedule, type UpdateScheduleResponse } from "@calcom/lib/schedules/updateSchedule";
|
||||||
|
export {UserAvailabilityService} from "@calcom/lib/getUserAvailability"
|
||||||
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
import { getUserAvailability } from "@calcom/lib/getUserAvailability";
|
import { getUserAvailabilityService } from "@calcom/lib/di/containers/get-user-availability";
|
||||||
|
|
||||||
import type { TrpcSessionUser } from "../../../types";
|
import type { TrpcSessionUser } from "../../../types";
|
||||||
import type { TUserInputSchema } from "./user.schema";
|
import type { TUserInputSchema } from "./user.schema";
|
||||||
@@ -11,7 +11,8 @@ type UserOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const userHandler = async ({ input }: UserOptions) => {
|
export const userHandler = async ({ input }: UserOptions) => {
|
||||||
return getUserAvailability(
|
const userAvailabilityService = getUserAvailabilityService()
|
||||||
|
return userAvailabilityService.getUserAvailability(
|
||||||
{ returnDateOverrides: true, bypassBusyCalendarTimes: false, ...input },
|
{ returnDateOverrides: true, bypassBusyCalendarTimes: false, ...input },
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ import type {
|
|||||||
CurrentSeats,
|
CurrentSeats,
|
||||||
EventType,
|
EventType,
|
||||||
GetAvailabilityUser,
|
GetAvailabilityUser,
|
||||||
|
UserAvailabilityService,
|
||||||
IFromUser,
|
IFromUser,
|
||||||
IToUser,
|
IToUser,
|
||||||
} from "@calcom/lib/getUserAvailability";
|
} from "@calcom/lib/getUserAvailability";
|
||||||
import { getPeriodStartDatesBetween, getUsersAvailability } from "@calcom/lib/getUserAvailability";
|
|
||||||
import { descendingLimitKeys, intervalLimitKeyToUnit } from "@calcom/lib/intervalLimits/intervalLimit";
|
import { descendingLimitKeys, intervalLimitKeyToUnit } from "@calcom/lib/intervalLimits/intervalLimit";
|
||||||
import type { IntervalLimit } from "@calcom/lib/intervalLimits/intervalLimitSchema";
|
import type { IntervalLimit } from "@calcom/lib/intervalLimits/intervalLimitSchema";
|
||||||
import { parseBookingLimit } from "@calcom/lib/intervalLimits/isBookingLimits";
|
import { parseBookingLimit } from "@calcom/lib/intervalLimits/isBookingLimits";
|
||||||
@@ -101,6 +101,7 @@ export interface IAvailableSlotsService {
|
|||||||
routingFormResponseRepo: RoutingFormResponseRepository;
|
routingFormResponseRepo: RoutingFormResponseRepository;
|
||||||
cacheService: CacheService;
|
cacheService: CacheService;
|
||||||
checkBookingLimitsService: CheckBookingLimitsService;
|
checkBookingLimitsService: CheckBookingLimitsService;
|
||||||
|
userAvailabilityService: UserAvailabilityService
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AvailableSlotsService {
|
export class AvailableSlotsService {
|
||||||
@@ -357,7 +358,7 @@ export class AvailableSlotsService {
|
|||||||
if (!limit) continue;
|
if (!limit) continue;
|
||||||
|
|
||||||
const unit = intervalLimitKeyToUnit(key);
|
const unit = intervalLimitKeyToUnit(key);
|
||||||
const periodStartDates = getPeriodStartDatesBetween(dateFrom, dateTo, unit, timeZone);
|
const periodStartDates = this.dependencies.userAvailabilityService.getPeriodStartDatesBetween(dateFrom, dateTo, unit, timeZone);
|
||||||
|
|
||||||
for (const periodStart of periodStartDates) {
|
for (const periodStart of periodStartDates) {
|
||||||
if (globalLimitManager.isAlreadyBusy(periodStart, unit, timeZone)) continue;
|
if (globalLimitManager.isAlreadyBusy(periodStart, unit, timeZone)) continue;
|
||||||
@@ -392,7 +393,7 @@ export class AvailableSlotsService {
|
|||||||
if (!limit) continue;
|
if (!limit) continue;
|
||||||
|
|
||||||
const unit = intervalLimitKeyToUnit(key);
|
const unit = intervalLimitKeyToUnit(key);
|
||||||
const periodStartDates = getPeriodStartDatesBetween(dateFrom, dateTo, unit, timeZone);
|
const periodStartDates = this.dependencies.userAvailabilityService.getPeriodStartDatesBetween(dateFrom, dateTo, unit, timeZone);
|
||||||
|
|
||||||
for (const periodStart of periodStartDates) {
|
for (const periodStart of periodStartDates) {
|
||||||
if (limitManager.isAlreadyBusy(periodStart, unit, timeZone)) continue;
|
if (limitManager.isAlreadyBusy(periodStart, unit, timeZone)) continue;
|
||||||
@@ -443,7 +444,7 @@ export class AvailableSlotsService {
|
|||||||
if (!limit) continue;
|
if (!limit) continue;
|
||||||
|
|
||||||
const unit = intervalLimitKeyToUnit(key);
|
const unit = intervalLimitKeyToUnit(key);
|
||||||
const periodStartDates = getPeriodStartDatesBetween(dateFrom, dateTo, unit, timeZone);
|
const periodStartDates = this.dependencies.userAvailabilityService.getPeriodStartDatesBetween(dateFrom, dateTo, unit, timeZone);
|
||||||
|
|
||||||
for (const periodStart of periodStartDates) {
|
for (const periodStart of periodStartDates) {
|
||||||
if (limitManager.isAlreadyBusy(periodStart, unit, timeZone)) continue;
|
if (limitManager.isAlreadyBusy(periodStart, unit, timeZone)) continue;
|
||||||
@@ -543,7 +544,7 @@ export class AvailableSlotsService {
|
|||||||
if (!limit) continue;
|
if (!limit) continue;
|
||||||
|
|
||||||
const unit = intervalLimitKeyToUnit(key);
|
const unit = intervalLimitKeyToUnit(key);
|
||||||
const periodStartDates = getPeriodStartDatesBetween(dateFrom, dateTo, unit, timeZone);
|
const periodStartDates = this.dependencies.userAvailabilityService.getPeriodStartDatesBetween(dateFrom, dateTo, unit, timeZone);
|
||||||
|
|
||||||
for (const periodStart of periodStartDates) {
|
for (const periodStart of periodStartDates) {
|
||||||
if (globalLimitManager.isAlreadyBusy(periodStart, unit, timeZone)) continue;
|
if (globalLimitManager.isAlreadyBusy(periodStart, unit, timeZone)) continue;
|
||||||
@@ -591,7 +592,7 @@ export class AvailableSlotsService {
|
|||||||
if (!limit) continue;
|
if (!limit) continue;
|
||||||
|
|
||||||
const unit = intervalLimitKeyToUnit(key);
|
const unit = intervalLimitKeyToUnit(key);
|
||||||
const periodStartDates = getPeriodStartDatesBetween(dateFrom, dateTo, unit, timeZone);
|
const periodStartDates = this.dependencies.userAvailabilityService.getPeriodStartDatesBetween(dateFrom, dateTo, unit, timeZone);
|
||||||
|
|
||||||
for (const periodStart of periodStartDates) {
|
for (const periodStart of periodStartDates) {
|
||||||
if (limitManager.isAlreadyBusy(periodStart, unit, timeZone)) continue;
|
if (limitManager.isAlreadyBusy(periodStart, unit, timeZone)) continue;
|
||||||
@@ -818,7 +819,7 @@ export class AvailableSlotsService {
|
|||||||
const users = enrichUsersWithData();
|
const users = enrichUsersWithData();
|
||||||
|
|
||||||
// TODO: DI getUsersAvailability
|
// TODO: DI getUsersAvailability
|
||||||
const premappedUsersAvailability = await getUsersAvailability({
|
const premappedUsersAvailability = await this.dependencies.userAvailabilityService.getUsersAvailability({
|
||||||
users,
|
users,
|
||||||
query: {
|
query: {
|
||||||
dateFrom: startTime.format(),
|
dateFrom: startTime.format(),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { enrichUserWithDelegationCredentialsIncludeServiceAccountKey } from "@calcom/lib/delegationCredential/server";
|
import { enrichUserWithDelegationCredentialsIncludeServiceAccountKey } from "@calcom/lib/delegationCredential/server";
|
||||||
import { getUserAvailability } from "@calcom/lib/getUserAvailability";
|
import { getUserAvailabilityService } from "@calcom/lib/di/containers/get-user-availability";
|
||||||
import { isTeamMember } from "@calcom/lib/server/queries/teams";
|
import { isTeamMember } from "@calcom/lib/server/queries/teams";
|
||||||
import { MembershipRepository } from "@calcom/lib/server/repository/membership";
|
import { MembershipRepository } from "@calcom/lib/server/repository/membership";
|
||||||
import type { TrpcSessionUser } from "@calcom/trpc/server/types";
|
import type { TrpcSessionUser } from "@calcom/trpc/server/types";
|
||||||
@@ -16,6 +16,7 @@ type GetMemberAvailabilityOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getMemberAvailabilityHandler = async ({ ctx, input }: GetMemberAvailabilityOptions) => {
|
export const getMemberAvailabilityHandler = async ({ ctx, input }: GetMemberAvailabilityOptions) => {
|
||||||
|
const userAvailabilityService = getUserAvailabilityService()
|
||||||
const team = await isTeamMember(ctx.user?.id, input.teamId);
|
const team = await isTeamMember(ctx.user?.id, input.teamId);
|
||||||
if (!team) throw new TRPCError({ code: "UNAUTHORIZED" });
|
if (!team) throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ export const getMemberAvailabilityHandler = async ({ ctx, input }: GetMemberAvai
|
|||||||
});
|
});
|
||||||
|
|
||||||
// get availability for this member
|
// get availability for this member
|
||||||
return await getUserAvailability(
|
return await userAvailabilityService.getUserAvailability(
|
||||||
{
|
{
|
||||||
username: username,
|
username: username,
|
||||||
dateFrom: input.dateFrom,
|
dateFrom: input.dateFrom,
|
||||||
|
|||||||
@@ -2500,7 +2500,7 @@ __metadata:
|
|||||||
"@axiomhq/winston": ^1.2.0
|
"@axiomhq/winston": ^1.2.0
|
||||||
"@calcom/platform-constants": "*"
|
"@calcom/platform-constants": "*"
|
||||||
"@calcom/platform-enums": "*"
|
"@calcom/platform-enums": "*"
|
||||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.276"
|
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.283"
|
||||||
"@calcom/platform-types": "*"
|
"@calcom/platform-types": "*"
|
||||||
"@calcom/platform-utils": "*"
|
"@calcom/platform-utils": "*"
|
||||||
"@calcom/prisma": "*"
|
"@calcom/prisma": "*"
|
||||||
@@ -3556,13 +3556,13 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@calcom/platform-libraries@npm:@calcom/platform-libraries@0.0.276":
|
"@calcom/platform-libraries@npm:@calcom/platform-libraries@0.0.283":
|
||||||
version: 0.0.276
|
version: 0.0.283
|
||||||
resolution: "@calcom/platform-libraries@npm:0.0.276"
|
resolution: "@calcom/platform-libraries@npm:0.0.283"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@calcom/features": "*"
|
"@calcom/features": "*"
|
||||||
"@calcom/lib": "*"
|
"@calcom/lib": "*"
|
||||||
checksum: 4effc186c0301ec35496ebffbe32280f26261667b60057d18207b30636b038cdcc3783b95390eecc8460f3203d0cfe5d732e3b3f89031ff064b1a556321779a8
|
checksum: 7d741bd13ac050f8552855658b2348cba0999529c12ca6741e5f802a7bc9ce4e29c9ac69a17306c42beb392f17acb7b5f8a0554b8d2ea9b5fc6d963950d0fca8
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user