Beispiel #1
0
        /// <summary>
        /// Creates a scheduled meeting for a user.
        /// </summary>
        /// <param name="userId">The user Id or email address.</param>
        /// <param name="topic">Meeting topic.</param>
        /// <param name="agenda">Meeting description.</param>
        /// <param name="start">Meeting start time.</param>
        /// <param name="duration">Meeting duration (minutes).</param>
        /// <param name="password">Password to join the meeting. Password may only contain the following characters: [a-z A-Z 0-9 @ - _ *]. Max of 10 characters.</param>
        /// <param name="settings">Meeting settings.</param>
        /// <param name="trackingFields">Tracking fields.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>
        /// The new meeting.
        /// </returns>
        /// <exception cref="System.Exception">Thrown when an exception occured while creating the meeting.</exception>
        public Task <ScheduledMeeting> CreateScheduledMeetingAsync(
            string userId,
            string topic,
            string agenda,
            DateTime start,
            int duration,
            string password          = null,
            MeetingSettings settings = null,
            IDictionary <string, string> trackingFields = null,
            CancellationToken cancellationToken         = default)
        {
            var data = new JObject()
            {
                { "type", 2 }
            };

            data.AddPropertyIfValue("topic", topic);
            data.AddPropertyIfValue("password", password);
            data.AddPropertyIfValue("agenda", agenda);
            data.AddPropertyIfValue("start_time", start.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'"));
            data.AddPropertyIfValue("duration", duration);
            data.AddPropertyIfValue("timezone", "UTC");
            data.AddPropertyIfValue("settings", settings);
            data.AddPropertyIfValue("tracking_fields", trackingFields?.Select(tf => new JObject()
            {
                { "field", tf.Key }, { "value", tf.Value }
            }));

            return(_client
                   .PostAsync($"users/{userId}/meetings")
                   .WithJsonBody(data)
                   .WithCancellationToken(cancellationToken)
                   .AsObject <ScheduledMeeting>());
        }
Beispiel #2
0
        /// <summary>
        /// Creates an instant meeting for a user.
        /// </summary>
        /// <param name="userId">The user Id or email address.</param>
        /// <param name="topic">Meeting topic.</param>
        /// <param name="agenda">Meeting description.</param>
        /// <param name="password">Password to join the meeting. Password may only contain the following characters: [a-z A-Z 0-9 @ - _ *]. Max of 10 characters.</param>
        /// <param name="settings">Meeting settings.</param>
        /// <param name="trackingFields">Tracking fields.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>
        /// The new meeting.
        /// </returns>
        /// <exception cref="System.Exception">Thrown when an exception occured while creating the meeting.</exception>
        public Task <InstantMeeting> CreateInstantMeetingAsync(
            string userId,
            string topic,
            string agenda,
            string password          = null,
            MeetingSettings settings = null,
            IDictionary <string, string> trackingFields = null,
            CancellationToken cancellationToken         = default)
        {
            var data = new JObject()
            {
                { "type", 1 }
            };

            data.AddPropertyIfValue("topic", topic);
            data.AddPropertyIfValue("password", password);
            data.AddPropertyIfValue("agenda", agenda);
            data.AddPropertyIfValue("settings", settings);
            data.AddPropertyIfValue("tracking_fields", trackingFields?.Select(tf => new JObject()
            {
                { "field", tf.Key }, { "value", tf.Value }
            }));

            return(_client
                   .PostAsync($"users/{userId}/meetings")
                   .WithJsonBody(data)
                   .WithCancellationToken(cancellationToken)
                   .AsObject <InstantMeeting>());
        }
Beispiel #3
0
        /// <summary>
        /// Creates a recurring meeting for a user.
        /// </summary>
        /// <param name="userId">The user Id or email address.</param>
        /// <param name="topic">Meeting topic.</param>
        /// <param name="agenda">Meeting description.</param>
        /// <param name="start">Meeting start time. If omitted, a 'Recurring meeting with no fixed time' will be created.</param>
        /// <param name="duration">Meeting duration (minutes).</param>
        /// <param name="recurrence">Recurrence information.</param>
        /// <param name="password">Password to join the meeting. Password may only contain the following characters: [a-z A-Z 0-9 @ - _ *]. Max of 10 characters.</param>
        /// <param name="settings">Meeting settings.</param>
        /// <param name="trackingFields">Tracking fields.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>
        /// The new meeting.
        /// </returns>
        /// <exception cref="System.Exception">Thrown when an exception occured while creating the meeting.</exception>
        public Task <RecurringMeeting> CreateRecurringMeetingAsync(
            string userId,
            string topic,
            string agenda,
            DateTime?start,
            int duration,
            RecurrenceInfo recurrence,
            string password          = null,
            MeetingSettings settings = null,
            IDictionary <string, string> trackingFields = null,
            CancellationToken cancellationToken         = default)
        {
            var data = new JObject()
            {
                // 3 = Recurring with no fixed time
                // 8 = Recurring with fixed time
                { "type", start.HasValue ? 8 : 3 }
            };

            data.AddPropertyIfValue("topic", topic);
            data.AddPropertyIfValue("password", password);
            data.AddPropertyIfValue("agenda", agenda);
            data.AddPropertyIfValue("start_time", start?.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'"));
            data.AddPropertyIfValue("duration", duration);
            data.AddPropertyIfValue("recurrence", recurrence);
            if (start.HasValue)
            {
                data.Add("timezone", "UTC");
            }
            data.AddPropertyIfValue("settings", settings);
            data.AddPropertyIfValue("tracking_fields", trackingFields?.Select(tf => new JObject()
            {
                { "field", tf.Key }, { "value", tf.Value }
            }));

            return(_client
                   .PostAsync($"users/{userId}/meetings")
                   .WithJsonBody(data)
                   .WithCancellationToken(cancellationToken)
                   .AsObject <RecurringMeeting>());
        }
Beispiel #4
0
        public async Task RunAsync(string userId, IZoomClient client, TextWriter log, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

            await log.WriteLineAsync("\n***** MEETINGS *****\n").ConfigureAwait(false);

            // GET ALL THE MEETINGS
            var paginatedScheduledMeetings = await client.Meetings.GetAllAsync(userId, MeetingListType.Scheduled, 100, null, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"There are {paginatedScheduledMeetings.TotalRecords} scheduled meetings").ConfigureAwait(false);

            var paginatedLiveMeetings = await client.Meetings.GetAllAsync(userId, MeetingListType.Live, 100, null, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"There are {paginatedLiveMeetings.TotalRecords} live meetings").ConfigureAwait(false);

            var paginatedUpcomingMeetings = await client.Meetings.GetAllAsync(userId, MeetingListType.Upcoming, 100, null, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"There are {paginatedUpcomingMeetings.TotalRecords} upcoming meetings").ConfigureAwait(false);

            // CLEANUP PREVIOUS INTEGRATION TESTS THAT MIGHT HAVE BEEN INTERRUPTED BEFORE THEY HAD TIME TO CLEANUP AFTER THEMSELVES
            var cleanUpTasks = paginatedScheduledMeetings.Records
                               .Union(paginatedLiveMeetings.Records)
                               .Where(m => m.Topic.StartsWith("ZoomNet Integration Testing:"))
                               .Select(async oldMeeting =>
            {
                await client.Meetings.DeleteAsync(oldMeeting.Id, null, false, false, cancellationToken).ConfigureAwait(false);
                await log.WriteLineAsync($"Meeting {oldMeeting.Id} deleted").ConfigureAwait(false);
                await Task.Delay(250, cancellationToken).ConfigureAwait(false);                            // Brief pause to ensure Zoom has time to catch up
            });
            await Task.WhenAll(cleanUpTasks).ConfigureAwait(false);

            var settings = new MeetingSettings()
            {
                Audio = AudioType.Telephony
            };
            var trackingFields = new Dictionary <string, string>()
            {
                { "field1", "value1" },
                { "field2", "value2" }
            };

            // Instant meeting
            var newInstantMeeting = await client.Meetings.CreateInstantMeetingAsync(userId, "ZoomNet Integration Testing: instant meeting", "The agenda", "p@ss!w0rd", settings, trackingFields, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Instant meeting {newInstantMeeting.Id} created").ConfigureAwait(false);

            await client.Meetings.EndAsync(newInstantMeeting.Id, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Instant meeting {newInstantMeeting.Id} ended").ConfigureAwait(false);

            var instantMeeting = (InstantMeeting)await client.Meetings.GetAsync(newInstantMeeting.Id, null, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Instant meeting {instantMeeting.Id} retrieved").ConfigureAwait(false);

            await client.Meetings.DeleteAsync(newInstantMeeting.Id, null, false, false, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Instant meeting {newInstantMeeting.Id} deleted").ConfigureAwait(false);

            // Scheduled meeting
            var start               = DateTime.UtcNow.AddMonths(1);
            var duration            = 30;
            var newScheduledMeeting = await client.Meetings.CreateScheduledMeetingAsync(userId, "ZoomNet Integration Testing: scheduled meeting", "The agenda", start, duration, "p@ss!w0rd", settings, trackingFields, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Scheduled meeting {newScheduledMeeting.Id} created").ConfigureAwait(false);

            var updatedSettings = new MeetingSettings()
            {
                Audio = AudioType.Voip
            };
            await client.Meetings.UpdateScheduledMeetingAsync(newScheduledMeeting.Id, topic : "ZoomNet Integration Testing: UPDATED scheduled meeting", settings : updatedSettings, cancellationToken : cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Scheduled meeting {newScheduledMeeting.Id} updated").ConfigureAwait(false);

            var scheduledMeeting = (ScheduledMeeting)await client.Meetings.GetAsync(newScheduledMeeting.Id, null, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Scheduled meeting {scheduledMeeting.Id} retrieved").ConfigureAwait(false);

            await client.Meetings.DeleteAsync(newScheduledMeeting.Id, null, false, false, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Scheduled meeting {newScheduledMeeting.Id} deleted").ConfigureAwait(false);

            // Recurring meeting
            var recurrenceInfo = new RecurrenceInfo()
            {
                EndTimes   = 2,
                WeeklyDays = new[] { DayOfWeek.Monday, DayOfWeek.Friday },
                Type       = RecurrenceType.Weekly
            };
            var newRecurringMeeting = await client.Meetings.CreateRecurringMeetingAsync(userId, "ZoomNet Integration Testing: recurring meeting", "The agenda", start, duration, recurrenceInfo, "p@ss!w0rd", settings, trackingFields, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Recurring meeting {newRecurringMeeting.Id} created").ConfigureAwait(false);

            await client.Meetings.UpdateRecurringMeetingAsync(newRecurringMeeting.Id, topic : "ZoomNet Integration Testing: UPDATED recurring meeting", cancellationToken : cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Recurring meeting {newRecurringMeeting.Id} updated").ConfigureAwait(false);

            var recurringMeeting = (RecurringMeeting)await client.Meetings.GetAsync(newRecurringMeeting.Id, null, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Recurring meeting {recurringMeeting.Id} retrieved").ConfigureAwait(false);

            var occurenceId = recurringMeeting.Occurrences[0].OccurrenceId;
            await client.Meetings.UpdateMeetingOccurrenceAsync(newRecurringMeeting.Id, occurenceId, duration : 99, cancellationToken : cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Recurring meeting {newRecurringMeeting.Id} occurence {occurenceId} updated").ConfigureAwait(false);

            await client.Meetings.DeleteAsync(newRecurringMeeting.Id, null, false, false, cancellationToken).ConfigureAwait(false);

            await log.WriteLineAsync($"Recurring meeting {newRecurringMeeting.Id} deleted").ConfigureAwait(false);
        }
        /// <summary>
        /// 创建会议房间
        /// </summary>
        /// <returns></returns>
        public ActionResult CreateMetting(int User_ID, string Subject, DateTime StartTime, DateTime EndTime, string Page_Image = "", string Password = "", int Mute_Enable_Join = 0, int Allow_Unmute_Self = 0, int Mute_All = 0, int Host_Video = 0, int Participant_Video = 0, int Play_Ivr_On_Leave = 0, int Play_Ivr_On_Join = 0)
        {
            try
            {
                if (User_ID <= 0)
                {
                    return(FailNoLogin());
                }

                string appid = CheckAPPID();

                dm_basesettingEntity dm_BasesettingEntity = dm_BaseSettingIBLL.GetEntityByCache(appid);

                dm_userEntity dm_UserEntity = dm_userIBLL.GetEntityByCache(User_ID);

                if (dm_UserEntity.isvoice != 1)
                {
                    throw new Exception("无创建直播间权限!");
                }

                MeetingSettings msettings = new MeetingSettings()
                {
                    mute_enable_join  = Mute_Enable_Join == 1,
                    allow_unmute_self = Allow_Unmute_Self == 1,
                    mute_all          = Mute_All == 1,
                    host_video        = Host_Video == 1,
                    participant_video = Participant_Video == 1,
                    enable_record     = false,
                    play_ivr_on_leave = Play_Ivr_On_Leave == 1,
                    play_ivr_on_join  = Play_Ivr_On_Join == 1,
                    live_url          = false
                };

                Dictionary <string, string> user = new Dictionary <string, string>();
                user.Add("userid", dm_UserEntity.phone);
                CreateMeeting createMeeting = new CreateMeeting()
                {
                    userid     = dm_UserEntity.phone,
                    instanceid = 1,
                    subject    = Subject,
                    type       = 0,
                    hosts      = new List <Dictionary <string, string> >()
                    {
                        user
                    },
                    settings   = msettings,
                    start_time = Time.GetTimeStamp(StartTime),
                    end_time   = Time.GetTimeStamp(EndTime),
                    password   = Password
                };

                MeetingAPI meetingAPI = new MeetingAPI()
                {
                    AppId      = dm_BasesettingEntity.meeting_appid,
                    SecretId   = dm_BasesettingEntity.meeting_secretid,
                    Secretkey  = dm_BasesettingEntity.meeting_secretkey,
                    SdkId      = dm_BasesettingEntity.meeting_sdkid,
                    Registered = 1
                };


                #region 创建用户(不管是否成功  都需要创建房间)
                MeetingUser meetingUser = new MeetingUser()
                {
                    userid     = dm_UserEntity.phone,
                    username   = dm_UserEntity.nickname,
                    email      = dm_UserEntity.phone + "@qq.com",
                    phone      = dm_UserEntity.phone,
                    avatar_url = dm_UserEntity.headpic
                };
                string userdetail = meetingAPI.GetUserDetail(dm_UserEntity.phone);
                if (userdetail.Contains("error_info"))
                {//有错误就执行创建
                    MeetingErrorResponse meetingErrorResponse = JsonConvert.JsonDeserialize <MeetingErrorResponse>(userdetail);
                    if (meetingErrorResponse.error_info.error_code == 20002)
                    {//用户已存在
                        meetingAPI.UpdateUser(meetingUser);
                    }
                    else if (meetingErrorResponse.error_info.error_code == 20001)
                    {//用户不存在
                        meetingAPI.CreateUser(meetingUser);
                    }
                }
                else
                {//执行更新
                    meetingAPI.UpdateUser(meetingUser);
                }
                #endregion

                string result = meetingAPI.CreateMeetings(createMeeting);

                if (!result.Contains("error_info"))
                {
                    CreateMeetingResponse createMeetingResponse = JsonConvert.JsonDeserialize <CreateMeetingResponse>(result);
                    if (createMeetingResponse.meeting_number > 0)
                    {
                        List <dm_meetinglistEntity> MeetingEntityList = new List <dm_meetinglistEntity>();
                        foreach (MeetingInfo item in createMeetingResponse.meeting_info_list)
                        {
                            MeetingEntityList.Add(new dm_meetinglistEntity
                            {
                                hosts        = User_ID.ToString(),
                                join_url     = item.join_url,
                                meeting_code = item.meeting_code,
                                meeting_id   = item.meeting_id,
                                start_time   = StartTime,
                                end_time     = EndTime,
                                participants = "",
                                password     = Password,
                                user_id      = User_ID,
                                subject      = item.subject,
                                createtime   = DateTime.Now,
                                settings     = "",
                                join_image   = dm_MeetingListIBLL.GeneralMeetingImage(dm_BasesettingEntity, item.join_url),
                                page_image   = Page_Image
                            });
                        }
                        if (MeetingEntityList.Count > 0)
                        {
                            dm_MeetingListIBLL.CreateMetting(MeetingEntityList);
                        }
                    }
                }
                else
                {
                    MeetingErrorResponse meetingErrorResponse = JsonConvert.JsonDeserialize <MeetingErrorResponse>(result);
                    throw new Exception(meetingErrorResponse.error_info.message);
                }

                return(Success("创建成功,请刷新直播列表!"));
            }
            catch (Exception ex)
            {
                return(FailException(ex));
            }
        }
Beispiel #6
0
        /// <summary>
        /// Update the details of a recurring meeting.
        /// </summary>
        /// <param name="meetingId">The meeting ID.</param>
        /// <param name="userId">The user Id or email address.</param>
        /// <param name="topic">Meeting topic.</param>
        /// <param name="agenda">Meeting description.</param>
        /// <param name="start">Meeting start time. If omitted, a 'Recurring meeting with no fixed time' will be created.</param>
        /// <param name="duration">Meeting duration (minutes).</param>
        /// <param name="recurrence">Recurrence information.</param>
        /// <param name="password">Password to join the meeting. Password may only contain the following characters: [a-z A-Z 0-9 @ - _ *]. Max of 10 characters.</param>
        /// <param name="settings">Meeting settings.</param>
        /// <param name="trackingFields">Tracking fields.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>
        /// The async task.
        /// </returns>
        public Task UpdateRecurringMeetingAsync(long meetingId, string userId = null, string topic = null, string agenda = null, DateTime?start = null, int?duration = null, RecurrenceInfo recurrence = null, string password = null, MeetingSettings settings = null, IDictionary <string, string> trackingFields = null, CancellationToken cancellationToken = default)
        {
            var data = new JObject();

            data.AddPropertyIfValue("topic", topic);
            data.AddPropertyIfValue("password", password);
            data.AddPropertyIfValue("agenda", agenda);
            data.AddPropertyIfValue("start_time", start?.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'"));
            data.AddPropertyIfValue("duration", duration);
            data.AddPropertyIfValue("recurrence", recurrence);
            if (start.HasValue)
            {
                data.Add("timezone", "UTC");
            }
            data.AddPropertyIfValue("settings", settings);
            data.AddPropertyIfValue("tracking_fields", trackingFields?.Select(tf => new JObject()
            {
                { "field", tf.Key }, { "value", tf.Value }
            }));

            return(_client
                   .PatchAsync($"meetings/{meetingId}")
                   .WithJsonBody(data)
                   .WithCancellationToken(cancellationToken)
                   .AsMessage());
        }
Beispiel #7
0
        /// <summary>
        /// Update the details of a meeting occurence.
        /// </summary>
        /// <param name="meetingId">The meeting ID.</param>
        /// <param name="occurrenceId">The meeting occurrence id.</param>
        /// <param name="agenda">Meeting description.</param>
        /// <param name="start">Meeting start time.</param>
        /// <param name="duration">Meeting duration (minutes).</param>
        /// <param name="settings">Meeting settings.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>
        /// The async task.
        /// </returns>
        public Task UpdateMeetingOccurrenceAsync(long meetingId, string occurrenceId, string agenda = null, DateTime?start = null, int?duration = null, MeetingSettings settings = null, CancellationToken cancellationToken = default)
        {
            var data = new JObject();

            data.AddPropertyIfValue("agenda", agenda);
            data.AddPropertyIfValue("start_time", start?.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'"));
            data.AddPropertyIfValue("duration", duration);
            if (start.HasValue)
            {
                data.Add("timezone", "UTC");
            }
            data.AddPropertyIfValue("settings", settings);

            return(_client
                   .PatchAsync($"meetings/{meetingId}")
                   .WithArgument("occurrence_id", occurrenceId)
                   .WithJsonBody(data)
                   .WithCancellationToken(cancellationToken)
                   .AsMessage());
        }
Beispiel #8
0
        /// <summary>
        /// Update the details of a recurring meeting.
        /// </summary>
        /// <param name="meetingId">The meeting ID.</param>
        /// <param name="userId">The user Id or email address.</param>
        /// <param name="topic">Meeting topic.</param>
        /// <param name="agenda">Meeting description.</param>
        /// <param name="start">Meeting start time. If omitted, a 'Recurring meeting with no fixed time' will be created.</param>
        /// <param name="duration">Meeting duration (minutes).</param>
        /// <param name="timeZone">The time zone for start time.</param>
        /// <param name="recurrence">Recurrence information.</param>
        /// <param name="password">Password to join the meeting. Password may only contain the following characters: [a-z A-Z 0-9 @ - _ *]. Max of 10 characters.</param>
        /// <param name="settings">Meeting settings.</param>
        /// <param name="trackingFields">Tracking fields.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>
        /// The async task.
        /// </returns>
        public Task UpdateRecurringMeetingAsync(long meetingId, string userId = null, string topic = null, string agenda = null, DateTime?start = null, int?duration = null, TimeZones?timeZone = null, RecurrenceInfo recurrence = null, string password = null, MeetingSettings settings = null, IDictionary <string, string> trackingFields = null, CancellationToken cancellationToken = default)
        {
            var data = new JObject();

            data.AddPropertyIfValue("schedule_for", userId);
            data.AddPropertyIfValue("topic", topic);
            data.AddPropertyIfValue("password", password);
            data.AddPropertyIfValue("agenda", agenda);
            data.AddPropertyIfValue("start_time", start.ToZoomFormat(timeZone));
            data.AddPropertyIfValue("duration", duration);
            data.AddPropertyIfValue("recurrence", recurrence);
            data.AddPropertyIfEnumValue("timezone", timeZone);
            data.AddPropertyIfValue("settings", settings);
            data.AddPropertyIfValue("tracking_fields", trackingFields?.Select(tf => new JObject()
            {
                { "field", tf.Key }, { "value", tf.Value }
            }));

            return(_client
                   .PatchAsync($"meetings/{meetingId}")
                   .WithJsonBody(data)
                   .WithCancellationToken(cancellationToken)
                   .AsMessage());
        }
Beispiel #9
0
        /// <summary>
        /// Update the details of a meeting occurence.
        /// </summary>
        /// <param name="meetingId">The meeting ID.</param>
        /// <param name="occurrenceId">The meeting occurrence id.</param>
        /// <param name="agenda">Meeting description.</param>
        /// <param name="start">Meeting start time.</param>
        /// <param name="duration">Meeting duration (minutes).</param>
        /// <param name="timeZone">The time zone for start time.</param>
        /// <param name="settings">Meeting settings.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>
        /// The async task.
        /// </returns>
        public Task UpdateMeetingOccurrenceAsync(long meetingId, string occurrenceId, string agenda = null, DateTime?start = null, int?duration = null, TimeZones?timeZone = null, MeetingSettings settings = null, CancellationToken cancellationToken = default)
        {
            var data = new JObject();

            data.AddPropertyIfValue("agenda", agenda);
            data.AddPropertyIfValue("start_time", start.ToZoomFormat(timeZone));
            data.AddPropertyIfValue("duration", duration);
            data.AddPropertyIfEnumValue("timezone", timeZone);
            data.AddPropertyIfValue("settings", settings);

            return(_client
                   .PatchAsync($"meetings/{meetingId}")
                   .WithArgument("occurrence_id", occurrenceId)
                   .WithJsonBody(data)
                   .WithCancellationToken(cancellationToken)
                   .AsMessage());
        }