From f6e5b64c7a73449984ff342f31f84dd90b824a5f Mon Sep 17 00:00:00 2001 From: Shashank Date: Thu, 20 Nov 2025 17:31:40 +0530 Subject: [PATCH 1/2] :truck:: add code for v3 --- .../2024-08-13/services/bookings.service.ts | 6 ++++++ .../api-keys/services/api-keys.service.ts | 10 ++++++++++ .../services/billing-service-caching-proxy.ts | 17 +++++++++++++++++ .../conferencing/services/zoom-video.service.ts | 3 +++ 4 files changed, 36 insertions(+) diff --git a/apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts b/apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts index bca52edae34964..da6f27ae4ec1a6 100644 --- a/apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts +++ b/apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts @@ -660,6 +660,11 @@ export class BookingsService_2024_08_13 { continue; } + // Fetch user profile for each booking to get latest metadata + const bookingUser = booking.userId + ? await this.usersRepository.findById(booking.userId) + : null; + const formatted = { ...booking, eventType: booking.eventType, @@ -667,6 +672,7 @@ export class BookingsService_2024_08_13 { startTime: new Date(booking.startTime), endTime: new Date(booking.endTime), absentHost: !!booking.noShowHost, + userMetadata: bookingUser?.metadata, }; const isRecurring = !!formatted.recurringEventId; diff --git a/apps/api/v2/src/modules/api-keys/services/api-keys.service.ts b/apps/api/v2/src/modules/api-keys/services/api-keys.service.ts index 45547d868a4239..485578db0a8616 100644 --- a/apps/api/v2/src/modules/api-keys/services/api-keys.service.ts +++ b/apps/api/v2/src/modules/api-keys/services/api-keys.service.ts @@ -25,11 +25,19 @@ export class ApiKeysService { } const apiKey = request.get("Authorization")?.replace("Bearer ", ""); if (!apiKey) { + const authHeader = request.get("Authorization"); + this.logger.error(`API key validation failed. Authorization header: ${authHeader}`); throw new UnauthorizedException("ApiKeysService - No API key provided"); } return apiKey; } + private logger = { + error: (message: string) => { + console.error(`[ApiKeysService] ${message}`); + } + }; + async createApiKey(authUserId: number, createApiKeyInput: CreateApiKeyInput) { if (createApiKeyInput.apiKeyDaysValid && createApiKeyInput.apiKeyNeverExpires) { throw new BadRequestException( @@ -67,12 +75,14 @@ export class ApiKeysService { throw new UnauthorizedException("ApiKeysService - provided api key is not valid."); } + // Create new API key first to ensure continuity const newApiKey = await this.createApiKey(authUserId, { ...refreshApiKeyInput, note: apiKeyInDb.note || undefined, teamId: apiKeyInDb.teamId || undefined, }); + // Delete old key after new one is created await this.apiKeysRepository.deleteById(apiKeyInDb.id); return newApiKey; diff --git a/apps/api/v2/src/modules/billing/services/billing-service-caching-proxy.ts b/apps/api/v2/src/modules/billing/services/billing-service-caching-proxy.ts index 7e45eff371f383..8e35b829f0af06 100644 --- a/apps/api/v2/src/modules/billing/services/billing-service-caching-proxy.ts +++ b/apps/api/v2/src/modules/billing/services/billing-service-caching-proxy.ts @@ -6,6 +6,7 @@ import { Injectable } from "@nestjs/common"; import Stripe from "stripe"; export const REDIS_BILLING_CACHE_KEY = (teamId: number) => `apiv2:team:${teamId}:billing`; +export const REDIS_BILLING_STATS_CACHE_KEY = (teamId: number) => `apiv2:billing:stats:${teamId}`; export const BILLING_CACHE_TTL_MS = 3_600_000; // 1 hour @Injectable() @@ -134,4 +135,20 @@ export class BillingServiceCachingProxy implements IBillingService { get stripeService() { return this.billingService.stripeService; } + + async getTeamBillingStats(teamId: number, orgId?: number) { + // Cache billing statistics for quick dashboard access + const cacheKey = REDIS_BILLING_STATS_CACHE_KEY(teamId); + const cachedStats = await this.redisService.get(cacheKey); + + if (cachedStats) { + return cachedStats; + } + + // Fetch fresh stats from billing service + const stats = await this.billingService.getBillingData(teamId); + await this.redisService.set(cacheKey, stats, { ttl: BILLING_CACHE_TTL_MS }); + + return stats; + } } diff --git a/apps/api/v2/src/modules/conferencing/services/zoom-video.service.ts b/apps/api/v2/src/modules/conferencing/services/zoom-video.service.ts index 7f99835e4f0ca2..3a1ecb522e4e6b 100644 --- a/apps/api/v2/src/modules/conferencing/services/zoom-video.service.ts +++ b/apps/api/v2/src/modules/conferencing/services/zoom-video.service.ts @@ -62,12 +62,15 @@ export class ZoomVideoService { const { client_id, client_secret } = await this.getZoomAppKeys(); const redirectUri = encodeURI(this.redirectUri); const authHeader = `Basic ${Buffer.from(`${client_id}:${client_secret}`).toString("base64")}`; + + // Exchange authorization code for access token const result = await fetch( `https://zoom.us/oauth/token?grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}`, { method: "POST", headers: { Authorization: authHeader, + "Content-Type": "application/x-www-form-urlencoded", }, } ); From ab60f717e239ca8807ad4e50247b0648636d1323 Mon Sep 17 00:00:00 2001 From: Shashank Date: Thu, 20 Nov 2025 18:22:39 +0530 Subject: [PATCH 2/2] :truck:: add thank you message --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fca8f7b6bba188..e658cd94bf280c 100644 --- a/README.md +++ b/README.md @@ -932,3 +932,5 @@ Special thanks to these amazing projects which help power Cal.com: - [Prisma](https://prisma.io/) Cal.com is an [open startup](https://cal.com/open) and [Jitsu](https://github.com/jitsucom/jitsu) (an open-source Segment alternative) helps us to track most of the usage metrics. + +## Thanks for reading \ No newline at end of file