@@ -3,8 +3,6 @@ import dayjs from "@calcom/dayjs";
33import { readonlyPrisma as prisma } from "@calcom/prisma" ;
44import { Prisma } from "@calcom/prisma/client" ;
55
6- import type { RawDataInput } from "./raw-data.schema" ;
7-
86type TimeViewType = "week" | "month" | "year" | "day" ;
97
108type StatusAggregate = {
@@ -456,298 +454,6 @@ class EventsInsights {
456454 }
457455 }
458456
459- static getCsvData = async (
460- props : RawDataInput & {
461- organizationId : number | null ;
462- isOrgAdminOrOwner : boolean | null ;
463- }
464- ) => {
465- // Obtain the where conditional
466- const whereConditional = await this . obtainWhereConditionalForDownload ( props ) ;
467- const limit = props . limit ?? 100 ; // Default batch size
468- const offset = props . offset ?? 0 ;
469-
470- const totalCountPromise = prisma . bookingTimeStatusDenormalized . count ( {
471- where : whereConditional ,
472- } ) ;
473-
474- const csvDataPromise = prisma . bookingTimeStatusDenormalized . findMany ( {
475- select : {
476- id : true ,
477- uid : true ,
478- title : true ,
479- createdAt : true ,
480- timeStatus : true ,
481- eventTypeId : true ,
482- eventLength : true ,
483- startTime : true ,
484- endTime : true ,
485- paid : true ,
486- userEmail : true ,
487- userUsername : true ,
488- rating : true ,
489- ratingFeedback : true ,
490- noShowHost : true ,
491- } ,
492- where : whereConditional ,
493- skip : offset ,
494- take : limit ,
495- } ) ;
496-
497- const [ totalCount , csvData ] = await Promise . all ( [ totalCountPromise , csvDataPromise ] ) ;
498-
499- const uids = csvData . filter ( ( b ) => b . uid !== null ) . map ( ( b ) => b . uid as string ) ;
500-
501- if ( uids . length === 0 ) {
502- return { data : csvData , total : totalCount } ;
503- }
504-
505- const bookings = await prisma . booking . findMany ( {
506- where : {
507- uid : {
508- in : uids ,
509- } ,
510- } ,
511- select : {
512- uid : true ,
513- attendees : {
514- select : {
515- name : true ,
516- email : true ,
517- noShow : true ,
518- } ,
519- } ,
520- seatsReferences : {
521- select : {
522- attendee : {
523- select : {
524- name : true ,
525- email : true ,
526- noShow : true ,
527- } ,
528- } ,
529- } ,
530- } ,
531- } ,
532- } ) ;
533-
534- const bookingMap = new Map (
535- bookings . map ( ( booking ) => {
536- const attendeeList =
537- booking . seatsReferences . length > 0
538- ? booking . seatsReferences . map ( ( ref ) => ref . attendee )
539- : booking . attendees ;
540-
541- // List all no-show guests (name and email)
542- const noShowGuests =
543- attendeeList
544- . filter ( ( attendee ) => attendee ?. noShow )
545- . map ( ( attendee ) => ( attendee ? `${ attendee . name } (${ attendee . email } )` : null ) )
546- . filter ( Boolean ) // remove null values
547- . join ( "; " ) || null ;
548- const noShowGuestsCount = attendeeList . filter ( ( attendee ) => attendee ?. noShow ) . length ;
549-
550- const formattedAttendees = attendeeList
551- . map ( ( attendee ) => ( attendee ? `${ attendee . name } (${ attendee . email } )` : null ) )
552- . filter ( Boolean ) ;
553-
554- return [ booking . uid , { attendeeList : formattedAttendees , noShowGuests, noShowGuestsCount } ] ;
555- } )
556- ) ;
557-
558- const maxAttendees = Math . max (
559- ...Array . from ( bookingMap . values ( ) ) . map ( ( data ) => data . attendeeList . length ) ,
560- 0
561- ) ;
562-
563- const finalBookingMap = new Map (
564- Array . from ( bookingMap . entries ( ) ) . map ( ( [ uid , data ] ) => {
565- const attendeeFields : Record < string , string | null > = { } ;
566-
567- for ( let i = 1 ; i <= maxAttendees ; i ++ ) {
568- attendeeFields [ `attendee${ i } ` ] = data . attendeeList [ i - 1 ] || null ;
569- }
570-
571- return [
572- uid ,
573- {
574- noShowGuests : data . noShowGuests ,
575- noShowGuestsCount : data . noShowGuestsCount ,
576- ...attendeeFields ,
577- } ,
578- ] ;
579- } )
580- ) ;
581-
582- const data = csvData . map ( ( bookingTimeStatus ) => {
583- if ( ! bookingTimeStatus . uid ) {
584- // should not be reached because we filtered above
585- const nullAttendeeFields : Record < string , null > = { } ;
586- for ( let i = 1 ; i <= maxAttendees ; i ++ ) {
587- nullAttendeeFields [ `attendee${ i } ` ] = null ;
588- }
589-
590- return {
591- ...bookingTimeStatus ,
592- noShowGuests : null ,
593- ...nullAttendeeFields ,
594- } ;
595- }
596-
597- const attendeeData = finalBookingMap . get ( bookingTimeStatus . uid ) ;
598-
599- if ( ! attendeeData ) {
600- const nullAttendeeFields : Record < string , null > = { } ;
601- for ( let i = 1 ; i <= maxAttendees ; i ++ ) {
602- nullAttendeeFields [ `attendee${ i } ` ] = null ;
603- }
604-
605- return {
606- ...bookingTimeStatus ,
607- noShowGuests : null ,
608- ...nullAttendeeFields ,
609- } ;
610- }
611-
612- return {
613- ...bookingTimeStatus ,
614- noShowGuests : attendeeData . noShowGuests ,
615- noShowGuestsCount : attendeeData . noShowGuestsCount ,
616- ...Object . fromEntries ( Object . entries ( attendeeData ) . filter ( ( [ key ] ) => key . startsWith ( "attendee" ) ) ) ,
617- } ;
618- } ) ;
619-
620- return { data, total : totalCount } ;
621- } ;
622-
623- /*
624- * This is meant to be used for all functions inside insights router,
625- * but it's currently used only for CSV download.
626- * Ideally we should have a view that have all of this data
627- * The order where will be from the most specific to the least specific
628- * starting from the top will be:
629- * - memberUserId
630- * - eventTypeId
631- * - userId
632- * - teamId
633- * Generics will be:
634- * - isAll
635- * - startDate
636- * - endDate
637- * @param props
638- * @returns
639- */
640- static obtainWhereConditionalForDownload = async (
641- props : RawDataInput & { organizationId : number | null ; isOrgAdminOrOwner : boolean | null }
642- ) => {
643- const {
644- startDate,
645- endDate,
646- teamId,
647- userId,
648- memberUserId,
649- isAll,
650- eventTypeId,
651- organizationId,
652- isOrgAdminOrOwner,
653- } = props ;
654-
655- // Obtain the where conditional
656- let whereConditional : Prisma . BookingTimeStatusDenormalizedWhereInput = { } ;
657-
658- if ( startDate && endDate ) {
659- whereConditional . createdAt = {
660- gte : dayjs ( startDate ) . toISOString ( ) ,
661- lte : dayjs ( endDate ) . toISOString ( ) ,
662- } ;
663- }
664-
665- if ( eventTypeId ) {
666- whereConditional [ "eventTypeId" ] = eventTypeId ;
667- }
668- if ( memberUserId ) {
669- whereConditional [ "userId" ] = memberUserId ;
670- }
671- if ( userId ) {
672- whereConditional [ "teamId" ] = null ;
673- whereConditional [ "userId" ] = userId ;
674- }
675-
676- if ( isAll && isOrgAdminOrOwner && organizationId ) {
677- const teamsFromOrg = await prisma . team . findMany ( {
678- where : {
679- parentId : organizationId ,
680- } ,
681- select : {
682- id : true ,
683- } ,
684- } ) ;
685- if ( teamsFromOrg . length === 0 ) {
686- return { } ;
687- }
688- const teamIds : number [ ] = [ organizationId , ...teamsFromOrg . map ( ( t ) => t . id ) ] ;
689- const usersFromOrg = await prisma . membership . findMany ( {
690- where : {
691- teamId : {
692- in : teamIds ,
693- } ,
694- accepted : true ,
695- } ,
696- select : {
697- userId : true ,
698- } ,
699- } ) ;
700- const userIdsFromOrg = usersFromOrg . map ( ( u ) => u . userId ) ;
701- whereConditional = {
702- ...whereConditional ,
703- OR : [
704- {
705- userId : {
706- in : userIdsFromOrg ,
707- } ,
708- isTeamBooking : false ,
709- } ,
710- {
711- teamId : {
712- in : teamIds ,
713- } ,
714- isTeamBooking : true ,
715- } ,
716- ] ,
717- } ;
718- }
719-
720- if ( teamId && ! isAll ) {
721- const usersFromTeam = await prisma . membership . findMany ( {
722- where : {
723- teamId : teamId ,
724- accepted : true ,
725- } ,
726- select : {
727- userId : true ,
728- } ,
729- } ) ;
730- const userIdsFromTeam = usersFromTeam . map ( ( u ) => u . userId ) ;
731- whereConditional = {
732- ...whereConditional ,
733- OR : [
734- {
735- teamId,
736- isTeamBooking : true ,
737- } ,
738- {
739- userId : {
740- in : userIdsFromTeam ,
741- } ,
742- isTeamBooking : false ,
743- } ,
744- ] ,
745- } ;
746- }
747-
748- return whereConditional ;
749- } ;
750-
751457 static userIsOwnerAdminOfTeam = async ( {
752458 sessionUserId,
753459 teamId,
0 commit comments