From 9ac4a2f3bc1d3ef00c182804e229513fcd4b14de Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Fri, 1 Nov 2024 11:09:02 +0100 Subject: [PATCH 01/13] Adding Scheduler model --- nylas/models/scheduler.py | 410 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 nylas/models/scheduler.py diff --git a/nylas/models/scheduler.py b/nylas/models/scheduler.py new file mode 100644 index 0000000..541ef0c --- /dev/null +++ b/nylas/models/scheduler.py @@ -0,0 +1,410 @@ +from dataclasses import dataclass, field +from typing import Dict, Any, Optional, List + +from dataclasses_json import dataclass_json +from typing_extensions import TypedDict, NotRequired, Literal +from nylas.models.events import Conferencing +from nylas.models.availability import AvailabilityRules, OpenHours + +BookingType = Literal['booking', 'organizer-confirmation'] +BookingReminderType = Literal['email', 'webhook'] +BookingRecipientType = Literal['host', 'guest', 'all'] +EmailLanguage = Literal['en', 'es', 'fr', 'de', 'nl', 'sv', 'ja', 'zh'] + +@dataclass_json +@dataclass +class BookingConfirmedTemplate: + """ + Class representation of booking confirmed template settings. + + Attributes: + title: The title to replace the default 'Booking Confirmed' title. + body: The additional body to be appended after the default body. + """ + title: Optional[str] = None + body: Optional[str] = None + + +@dataclass_json +@dataclass +class EmailTemplate: + """ + Class representation of email template settings. + + Attributes: + logo: The URL to a custom logo that appears at the top of the booking email. + booking_confirmed: Configurable settings specifically for booking confirmed emails. + """ + logo: Optional[str] = None + booking_confirmed: Optional[BookingConfirmedTemplate] = None + + +@dataclass_json +@dataclass +class SchedulerSettings: + """ + Class representation of scheduler settings. + + Attributes: + additional_fields: Definitions for additional fields to be displayed in the Scheduler UI. + available_days_in_future: Number of days in the future that Scheduler is available for scheduling events. + min_booking_notice: Minimum number of minutes in the future that a user can make a new booking. + min_cancellation_notice: Minimum number of minutes before a booking can be cancelled. + cancellation_policy: A message about the cancellation policy to display when booking an event. + rescheduling_url: The URL used to reschedule bookings. + cancellation_url: The URL used to cancel bookings. + organizer_confirmation_url: The URL used to confirm or cancel pending bookings. + confirmation_redirect_url: The custom URL to redirect to once the booking is confirmed. + hide_rescheduling_options: Whether the option to reschedule an event is hidden in booking confirmations and notifications. + hide_cancellation_options: Whether the option to cancel an event is hidden in booking confirmations and notifications. + hide_additional_guests: Whether to hide the additional guests field on the scheduling page. + email_template: Configurable settings for booking emails. + """ + additional_fields: Optional[Dict[str, str]] = None + available_days_in_future: Optional[int] = None + min_booking_notice: Optional[int] = None + min_cancellation_notice: Optional[int] = None + cancellation_policy: Optional[str] = None + rescheduling_url: Optional[str] = None + cancellation_url: Optional[str] = None + organizer_confirmation_url: Optional[str] = None + confirmation_redirect_url: Optional[str] = None + hide_rescheduling_options: Optional[bool] = None + hide_cancellation_options: Optional[bool] = None + hide_additional_guests: Optional[bool] = None + email_template: Optional[EmailTemplate] = None + + +@dataclass_json +@dataclass +class BookingReminder: + """ + Class representation of a booking reminder. + + Attributes: + type: The reminder type. + minutes_before_event: The number of minutes before the event to send the reminder. + recipient: The recipient of the reminder. + email_subject: The subject of the email reminder. + """ + type: str + minutes_before_event: int + recipient: Optional[str] = None + email_subject: Optional[str] = None + + +@dataclass_json +@dataclass +class EventBooking: + """ + Class representation of an event booking. + + Attributes: + title: The title of the event. + description: The description of the event. + location: The location of the event. + timezone: The timezone for displaying times in confirmation email messages and reminders. + booking_type: The type of booking. + conferencing: Conference details for the event. + disable_emails: Whether Nylas sends email messages when an event is booked, cancelled, or rescheduled. + reminders: The list of reminders to send to participants before the event starts. + """ + title: str + description: Optional[str] = None + location: Optional[str] = None + timezone: Optional[str] = None + booking_type: Optional[BookingType] = None + conferencing: Optional[Conferencing] = None + disable_emails: Optional[bool] = None + reminders: Optional[List[BookingReminder]] = None + + +@dataclass_json +@dataclass +class Availability: + """ + Class representation of availability settings. + + Attributes: + duration_minutes: The total number of minutes the event should last. + interval_minutes: The interval between meetings in minutes. + round_to: Nylas rounds each time slot to the nearest multiple of this number of minutes. + availability_rules: Availability rules for scheduling configuration. + """ + duration_minutes: int + interval_minutes: Optional[int] = None + round_to: Optional[int] = None + availability_rules: Optional[AvailabilityRules] = None + + +@dataclass_json +@dataclass +class ParticipantBooking: + """ + Class representation of a participant booking. + + Attributes: + calendar_id: The calendar ID that the event is created in. + """ + calendar_id: str + + +@dataclass_json +@dataclass +class ParticipantAvailability: + """ + Class representation of participant availability. + + Attributes: + calendar_ids: List of calendar IDs associated with the participant's email address. + open_hours: Open hours for this participant. The endpoint searches for free time slots during these open hours. + """ + calendar_ids: List[str] + open_hours: Optional[OpenHours] = None + + +@dataclass_json +@dataclass +class ConfigParticipant: + """ + Class representation of a booking participant. + + Attributes: + email: Participant's email address. + availability: Availability data for the participant. + booking: Booking data for the participant. + name: Participant's name. + is_organizer: Whether the participant is the organizer of the event. + timezone: The participant's timezone. + """ + email: str + availability: ParticipantAvailability + booking: ParticipantBooking + name: Optional[str] = None + is_organizer: Optional[bool] = None + timezone: Optional[str] = None + + +@dataclass_json +@dataclass +class Configuration: + """ + Class representation of a scheduler configuration. + + Attributes: + participants: List of participants included in the scheduled event. + availability: Rules that determine available time slots for the event. + event_booking: Booking data for the event. + slug: Unique identifier for the Configuration object. + requires_session_auth: If true, scheduling Availability and Bookings endpoints require a valid session ID. + scheduler: Settings for the Scheduler UI. + appearance: Appearance settings for the Scheduler UI. + """ + participants: List[ConfigParticipant] + availability: Availability + event_booking: EventBooking + slug: Optional[str] = None + requires_session_auth: Optional[bool] = None + scheduler: Optional[SchedulerSettings] = None + appearance: Optional[Dict[str, str]] = None + + +class CreateConfigurationRequest(TypedDict): + participants: List[ConfigParticipant] + availability: Availability + event_booking: EventBooking + slug: NotRequired[str] + requires_session_auth: NotRequired[bool] + scheduler: NotRequired[SchedulerSettings] + appearance: NotRequired[Dict[str, str]] + + +class UpdateConfigurationRequest(TypedDict): + participants: NotRequired[List[ConfigParticipant]] + availability: NotRequired[Availability] + event_booking: NotRequired[EventBooking] + slug: NotRequired[str] + requires_session_auth: NotRequired[bool] + scheduler: NotRequired[SchedulerSettings] + appearance: NotRequired[Dict[str, str]] + + +class CreateSessionRequest(TypedDict): + configuration_id: NotRequired[str] + slug: NotRequired[str] + time_to_live: NotRequired[int] + + +@dataclass_json +@dataclass +class Session: + """ + Class representation of a session. + + Attributes: + session_id: The ID of the session. + """ + session_id: str + + +@dataclass_json +@dataclass +class BookingGuest: + """ + Class representation of a booking guest. + + Attributes: + email: The email address of the guest. + name: The name of the guest. + """ + email: str + name: str + +@dataclass_json +@dataclass +class BookingParticipant: + """ + Class representation of a booking participant. + + Attributes: + email: The email address of the participant to include in the booking. + """ + email: str + + +@dataclass_json +@dataclass +class CreateBookingRequest: + """ + Class representation of a create booking request. + + Attributes: + start_time: The event's start time, in Unix epoch format. + end_time: The event's end time, in Unix epoch format. + guest: Details about the guest that is creating the booking. + participants: List of participant email addresses from the Configuration object to include in the booking. + timezone: The guest's timezone that is used in email notifications. + email_language: The language of the guest email notifications. + additional_guests: List of additional guest email addresses to include in the booking. + additional_fields: Dictionary of additional field keys mapped to values populated by the guest in the booking form. + """ + start_time: int + end_time: int + guest: BookingGuest + participants: Optional[List[BookingParticipant]] = None + timezone: Optional[str] = None + email_language: Optional[EmailLanguage] = None + additional_guests: Optional[List[BookingGuest]] = None + additional_fields: Optional[Dict[str, str]] = None + + +@dataclass_json +@dataclass +class BookingOrganizer: + """ + Class representation of a booking organizer. + + Attributes: + email: The email address of the participant designated as the organizer of the event. + name: The name of the participant designated as the organizer of the event. + """ + email: str + name: Optional[str] = None + + +BookingStatus = Literal['pending', 'confirmed', 'cancelled'] +ConfirmBookingStatus = Literal['confirm', 'cancel'] + +@dataclass_json +@dataclass +class Booking: + """ + Class representation of a booking. + + Attributes: + booking_id: The unique ID of the booking. + event_id: The unique ID of the event associated with the booking. + title: The title of the event. + organizer: The participant designated as the organizer of the event. + status: The current status of the booking. + description: The description of the event. + """ + booking_id: str + event_id: str + title: str + organizer: BookingOrganizer + status: BookingStatus + description: Optional[str] = None + + +@dataclass_json +@dataclass +class ConfirmBookingRequest: + """ + Class representation of a confirm booking request. + + Attributes: + salt: The salt extracted from the booking reference embedded in the organizer confirmation link. + status: The action to take on the pending booking. + cancellation_reason: The reason the booking is being cancelled. + """ + salt: str + status: ConfirmBookingStatus + cancellation_reason: Optional[str] = None + +@dataclass_json +@dataclass +class DeleteBookingRequest: + """ + Class representation of a delete booking request. + + Attributes: + cancellation_reason: The reason the booking is being cancelled. + """ + cancellation_reason: Optional[str] = None + + +@dataclass_json +@dataclass +class RescheduleBookingRequest: + """ + Class representation of a reschedule booking request. + + Attributes: + start_time: The event's start time, in Unix epoch format. + end_time: The event's end time, in Unix epoch format. + """ + start_time: int + end_time: int + +@dataclass_json +@dataclass +class CreateBookingQueryParams: + """ + Class representation of query parameters for creating a booking. + + Attributes: + configuration_id: The ID of the Configuration object whose settings are used for calculating availability. If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. + slug: The slug of the Configuration object whose settings are used for calculating availability. If you're using session authentication (requires_session_auth is set to true) or using configurationId, slug is not required. + timezone: The timezone to use for the booking. If not provided, Nylas uses the timezone from the Configuration object. + """ + configuration_id: Optional[str] = None + slug: Optional[str] = None + timezone: Optional[str] = None + + +class FindBookingQueryParams: + """ + Class representation of query parameters for finding a booking. + + Attributes: + configuration_id: The ID of the Configuration object whose settings are used for calculating availability. If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. + slug: The slug of the Configuration object whose settings are used for calculating availability. If you're using session authentication (requires_session_auth is set to true) or using configurationId, slug is not required. + """ + configuration_id: Optional[str] = None + slug: Optional[str] = None + +ConfirmBookingQueryParams = FindBookingQueryParams +RescheduleBookingQueryParams = FindBookingQueryParams +DestroyBookingQueryParams = FindBookingQueryParams + \ No newline at end of file From 44d7ac21385273bd9aebd383937a166d460d7ff9 Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Fri, 1 Nov 2024 16:52:38 +0100 Subject: [PATCH 02/13] Add configurations resource --- nylas/client.py | 11 ++ nylas/models/scheduler.py | 41 ++++++-- nylas/resources/configurations.py | 161 ++++++++++++++++++++++++++++++ nylas/resources/scheduler.py | 19 ++++ 4 files changed, 224 insertions(+), 8 deletions(-) create mode 100644 nylas/resources/configurations.py create mode 100644 nylas/resources/scheduler.py diff --git a/nylas/client.py b/nylas/client.py index 00b5ad8..e729504 100644 --- a/nylas/client.py +++ b/nylas/client.py @@ -13,6 +13,7 @@ from nylas.resources.contacts import Contacts from nylas.resources.drafts import Drafts from nylas.resources.grants import Grants +from nylas.resources.scheduler import Scheduler class Client: @@ -169,3 +170,13 @@ def webhooks(self) -> Webhooks: The Webhooks API. """ return Webhooks(self.http_client) + + @property + def scheduler(self) -> Scheduler: + """ + Access the Scheduler API. + + Returns: + The Scheduler API. + """ + return Scheduler(self.http_client) diff --git a/nylas/models/scheduler.py b/nylas/models/scheduler.py index 541ef0c..5e12d81 100644 --- a/nylas/models/scheduler.py +++ b/nylas/models/scheduler.py @@ -10,6 +10,8 @@ BookingReminderType = Literal['email', 'webhook'] BookingRecipientType = Literal['host', 'guest', 'all'] EmailLanguage = Literal['en', 'es', 'fr', 'de', 'nl', 'sv', 'ja', 'zh'] +AdditionalFieldType = Literal['text', 'multi_line_text', 'email', 'phone_number', 'dropdown', 'date', 'checkbox', 'radio_button'] +AdditonalFieldOptionsType = Literal['text', 'email', 'phone_number', 'date', 'checkbox', 'radio_button'] @dataclass_json @dataclass @@ -35,9 +37,29 @@ class EmailTemplate: logo: The URL to a custom logo that appears at the top of the booking email. booking_confirmed: Configurable settings specifically for booking confirmed emails. """ - logo: Optional[str] = None + # logo: Optional[str] = None booking_confirmed: Optional[BookingConfirmedTemplate] = None +@dataclass_json +@dataclass +class AdditionalField: + """ + Class representation of an additional field. + + Atributes: + label: The text label to be displayed in the Scheduler UI. + type: The field type. Supported values are text, multi_line_text, email, phone_number, dropdown, date, checkbox, and radio_button + required: Whether the field is required to be filled out by the guest when booking an event. + pattern: A regular expression pattern that the value of the field must match. + order: The order in which the field will be displayed in the Scheduler UI. Fields with lower order values will be displayed first. + options: A list of options for the dropdown or radio_button types. This field is required for the dropdown and radio_button types. + """ + label: str + type: AdditionalFieldType + required: bool + pattern: Optional[str] = None + order: Optional[int] = None + options: Optional[AdditonalFieldOptionsType] = None @dataclass_json @dataclass @@ -60,7 +82,7 @@ class SchedulerSettings: hide_additional_guests: Whether to hide the additional guests field on the scheduling page. email_template: Configurable settings for booking emails. """ - additional_fields: Optional[Dict[str, str]] = None + additional_fields: Optional[Dict[str, AdditionalField]] = None available_days_in_future: Optional[int] = None min_booking_notice: Optional[int] = None min_cancellation_notice: Optional[int] = None @@ -160,7 +182,7 @@ class ParticipantAvailability: open_hours: Open hours for this participant. The endpoint searches for free time slots during these open hours. """ calendar_ids: List[str] - open_hours: Optional[OpenHours] = None + open_hours: Optional[List[OpenHours]] = None @dataclass_json @@ -384,8 +406,10 @@ class CreateBookingQueryParams: Class representation of query parameters for creating a booking. Attributes: - configuration_id: The ID of the Configuration object whose settings are used for calculating availability. If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. - slug: The slug of the Configuration object whose settings are used for calculating availability. If you're using session authentication (requires_session_auth is set to true) or using configurationId, slug is not required. + configuration_id: The ID of the Configuration object whose settings are used for calculating availability. + If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. + slug: The slug of the Configuration object whose settings are used for calculating availability. + If you're using session authentication (requires_session_auth is set to true) or using configurationId, slug is not required. timezone: The timezone to use for the booking. If not provided, Nylas uses the timezone from the Configuration object. """ configuration_id: Optional[str] = None @@ -398,8 +422,10 @@ class FindBookingQueryParams: Class representation of query parameters for finding a booking. Attributes: - configuration_id: The ID of the Configuration object whose settings are used for calculating availability. If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. - slug: The slug of the Configuration object whose settings are used for calculating availability. If you're using session authentication (requires_session_auth is set to true) or using configurationId, slug is not required. + configuration_id: The ID of the Configuration object whose settings are used for calculating availability. + If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. + slug: The slug of the Configuration object whose settings are used for calculating availability. + If you're using session authentication (requires_session_auth is set to true) or using configurationId, slug is not required. """ configuration_id: Optional[str] = None slug: Optional[str] = None @@ -407,4 +433,3 @@ class FindBookingQueryParams: ConfirmBookingQueryParams = FindBookingQueryParams RescheduleBookingQueryParams = FindBookingQueryParams DestroyBookingQueryParams = FindBookingQueryParams - \ No newline at end of file diff --git a/nylas/resources/configurations.py b/nylas/resources/configurations.py new file mode 100644 index 0000000..dcd1a85 --- /dev/null +++ b/nylas/resources/configurations.py @@ -0,0 +1,161 @@ +from nylas.config import RequestOverrides +from nylas.handler.api_resources import ( + ListableApiResource, + FindableApiResource, + CreatableApiResource, + UpdatableApiResource, + DestroyableApiResource, +) + +from nylas.models.scheduler import Configuration, CreateConfigurationRequest, UpdateConfigurationRequest +from nylas.models.response import Response, ListResponse +from nylas.models.list_query_params import ListQueryParams +from typing import Any + +class ListConfigurationsParams(ListQueryParams): + """ + Interface of the query parameters for listing configurations. + + Attributes: + limit: The maximum number of objects to return. + This field defaults to 50. The maximum allowed value is 200. + page_token: An identifier that specifies which page of data to return. + This value should be taken from a ListResponse object's next_cursor parameter. + identifier: The identifier of the Grant to act upon. + """ + # identifier: str + + +class Configurations( + ListableApiResource, + FindableApiResource, + CreatableApiResource, + UpdatableApiResource, + DestroyableApiResource, + ): + """ + Nylas Configuration API + + The Nylas configuration API allows you to create new configurations or manage existing ones, as well as getting + configurations details for a user. + + Nylas Scheduler stores Configuration objects in the Scheduler database and loads them as Scheduling Pages in the Scheduler UI. + """ + + def list( + self, + identifier: str, + query_params: ListConfigurationsParams = None, + overrides: RequestOverrides = None + ) -> ListResponse[Any]: + """ + Return all Configurations. + + Args: + identifier: The identifier of the Grant to act upon. + overrides: The request overrides to use for the request. + + Returns: + The list of Configurations. + """ + # import pdb; pdb.set_trace(); + res = super().list( + path=f"/v3/grants/{identifier}/scheduling/configurations", + overrides=overrides, + response_type=Configuration, + query_params=query_params, + ) + print("What's this", res) + return res + + def find( + self, + identifier: str, + config_id: str, + overrides: RequestOverrides = None + ) -> Response[Configuration]: + """ + Return a Configuration. + + Args: + identifier: The identifier of the Grant to act upon. + config_id: The identifier of the Configuration to get. + overrides: The request overrides to use for the request. + + Returns: + The Configuration object. + """ + return super().find( + path=f"/v3/grants/{identifier}/scheduling/configurations/{config_id}", + overrides=overrides, + response_type=Configuration, + ) + + def create( + self, + identifier: str, + requestBody: CreateConfigurationRequest, + overrides: RequestOverrides = None + ) -> Response[Configuration]: + """ + Create a new Configuration. + + Args: + identifier: The identifier of the Grant to act upon. + data: The data to create the Configuration with. + overrides: The request overrides to use for the request. + + Returns: + The Configuration object. + """ + return super().create( + path=f"/v3/grants/{identifier}/scheduling/configurations", + request_body=requestBody, + overrides=overrides, + response_type=Configuration, + ) + + def update( + self, + identifier: str, + config_id: str, + requestBody: UpdateConfigurationRequest, + overrides: RequestOverrides = None + ) -> Response[Configuration]: + """ + Update a Configuration. + + Args: + identifier: The identifier of the Grant to act upon. + config_id: The identifier of the Configuration to update. + data: The data to update the Configuration with. + overrides: The request overrides to use for the request. + + Returns: + The Configuration object. + """ + return super().update( + path=f"/v3/grants/{identifier}/scheduling/configurations/{config_id}", + request_body=requestBody, + overrides=overrides, + response_type=Configuration, + ) + + def destroy( + self, + identifier: str, + config_id: str, + overrides: RequestOverrides = None + ) -> None: + """ + Delete a Configuration. + + Args: + identifier: The identifier of the Grant to act upon. + config_id: The identifier of the Configuration to delete. + overrides: The request overrides to use for the request. + """ + return super().destroy( + path=f"/v3/grants/{identifier}/scheduling/configurations/{config_id}", + overrides=overrides, + ) \ No newline at end of file diff --git a/nylas/resources/scheduler.py b/nylas/resources/scheduler.py new file mode 100644 index 0000000..a9c958b --- /dev/null +++ b/nylas/resources/scheduler.py @@ -0,0 +1,19 @@ +from configurations import Configurations + +class Scheduler: + """ + Class representation of a Nylas Scheduler API. + """ + def __init__(self, http_client): + self.http_client = http_client + + @property + def configurations(self) -> Configurations: + """ + Access the Configurations API. + + Returns: + The Configurations API. + """ + return Configurations(self.http_client) + From 6b4f9b630c7289a1219cd7c34a38739f7014075c Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Mon, 4 Nov 2024 12:52:35 +0100 Subject: [PATCH 03/13] Add bookings resource --- nylas/handler/api_resources.py | 17 ++++ nylas/models/scheduler.py | 2 + nylas/resources/bookings.py | 141 +++++++++++++++++++++++++++++++++ nylas/resources/scheduler.py | 11 +++ 4 files changed, 171 insertions(+) create mode 100644 nylas/resources/bookings.py diff --git a/nylas/handler/api_resources.py b/nylas/handler/api_resources.py index ca38bce..f744419 100644 --- a/nylas/handler/api_resources.py +++ b/nylas/handler/api_resources.py @@ -73,6 +73,23 @@ def update( ) return Response.from_dict(response_json, response_type) + +class UpdatablePatchApiResource(Resource): + def patch( + self, + path, + response_type, + headers=None, + query_params=None, + request_body=None, + method="PATCH", + overrides=None, + ): + response_json = self._http_client._execute( + method, path, headers, query_params, request_body, overrides=overrides + ) + + return Response.from_dict(response_json, response_type) class DestroyableApiResource(Resource): diff --git a/nylas/models/scheduler.py b/nylas/models/scheduler.py index 5e12d81..5fcf28c 100644 --- a/nylas/models/scheduler.py +++ b/nylas/models/scheduler.py @@ -426,9 +426,11 @@ class FindBookingQueryParams: If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. slug: The slug of the Configuration object whose settings are used for calculating availability. If you're using session authentication (requires_session_auth is set to true) or using configurationId, slug is not required. + client_id: The client ID that was used to create the Configuration object. client_id is required only if using slug. """ configuration_id: Optional[str] = None slug: Optional[str] = None + client_id: Optional[str] = None ConfirmBookingQueryParams = FindBookingQueryParams RescheduleBookingQueryParams = FindBookingQueryParams diff --git a/nylas/resources/bookings.py b/nylas/resources/bookings.py new file mode 100644 index 0000000..db5613d --- /dev/null +++ b/nylas/resources/bookings.py @@ -0,0 +1,141 @@ +from nylas.config import RequestOverrides +from nylas.handler.api_resources import ( + ListableApiResource, + FindableApiResource, + CreatableApiResource, + UpdatableApiResource, + UpdatablePatchApiResource, + DestroyableApiResource, +) +from nylas.models.scheduler import Booking, CreateBookingRequest, CreateBookingQueryParams, ConfirmBookingRequest, DestroyBookingQueryParams +from nylas.models.response import Response + +class Bookings( + ListableApiResource, + FindableApiResource, + CreatableApiResource, + UpdatableApiResource, + UpdatablePatchApiResource, + DestroyableApiResource, +): + """ + Nylas Bookings API + + The Nylas Bookings API allows you to create new bookings or manage existing ones, as well as getting + bookings details for a user. + + A booking can be accessed by one, or several people, and can contain events. + """ + + def find( + self, identifier: str, booking_id: str, overrides: RequestOverrides = None + ) -> Response[Booking]: + """ + Return a Booking. + + Args: + identifier: The identifier of the Grant to act upon. + booking_id: The identifier of the Booking to get. + overrides: The request overrides to use for the request. + + Returns: + The Booking. + """ + + return super().find( + path=f"/v3/grants/{identifier}/bookings/{booking_id}", + response_type=Booking, + overrides=overrides, + ) + + def create( + self, + request_body: CreateBookingRequest, + query_params: CreateBookingQueryParams = None, + overrides: RequestOverrides = None, + ) -> Response[Booking]: + """ + Create a Booking. + + Args: + request_body: The values to create booking with. + overrides: The request overrides to use for the request. + query_params: The query parameters to include in the request. + overrides: The request overrides to use for the request. + + Returns: + The created Booking. + """ + + return super().create( + path=f"/v3/scheduling/bookings", + request_body=request_body, + query_params=query_params, + response_type=Booking, + overrides=overrides, + ) + + def confirm( + self, booking_id: str, request_body:ConfirmBookingRequest, overrides: RequestOverrides = None + ) -> Response[Booking]: + """ + Confirm a Booking. + + Args: + booking_id: The identifier of the Booking to confirm. + request_body: The values to confirm booking with. + overrides: The request overrides to use for the request. + + Returns: + The confirmed Booking. + """ + + return super().update( + path=f"/v3/scheduling/bookings/{booking_id}", + request_body=request_body, + response_type=Booking, + overrides=overrides, + ) + + def reschedule( + self, booking_id: str, request_body:CreateBookingRequest, overrides: RequestOverrides = None + ) -> Response[Booking]: + """ + Reschedule a Booking. + + Args: + booking_id: The identifier of the Booking to reschedule. + request_body: The values to reschedule booking with. + overrides: The request overrides to use for the request. + + Returns: + The rescheduled Booking. + """ + + return super().patch( + path=f"/v3/scheduling/bookings/{booking_id}", + request_body=request_body, + response_type=Booking, + overrides=overrides, + ) + + def destroy( + self, booking_id: str, query_params: DestroyBookingQueryParams = None ,overrides: RequestOverrides = None + ) -> Response[None]: + """ + Delete a Booking. + + Args: + booking_id: The identifier of the Booking to delete. + query_params: The query parameters to include in the request. + overrides: The request overrides to use for the request. + + Returns: + None. + """ + + return super().destroy( + path=f"/v3/scheduling/bookings/{booking_id}", + query_params=query_params, + overrides=overrides, + ) \ No newline at end of file diff --git a/nylas/resources/scheduler.py b/nylas/resources/scheduler.py index a9c958b..f217ecb 100644 --- a/nylas/resources/scheduler.py +++ b/nylas/resources/scheduler.py @@ -1,4 +1,5 @@ from configurations import Configurations +from bookings import Bookings class Scheduler: """ @@ -16,4 +17,14 @@ def configurations(self) -> Configurations: The Configurations API. """ return Configurations(self.http_client) + + @property + def bookings(self) -> Bookings: + """ + Access the Bookings API. + + Returns: + The Bookings API. + """ + return Bookings(self.http_client) From 2b24744e0e655c3ceb0fe826be32b724c0a5483a Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Mon, 4 Nov 2024 14:27:16 +0100 Subject: [PATCH 04/13] Add sessions resources --- nylas/resources/bookings.py | 6 +-- nylas/resources/configurations.py | 4 +- nylas/resources/scheduler.py | 11 ++++++ nylas/resources/sessions.py | 61 +++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 nylas/resources/sessions.py diff --git a/nylas/resources/bookings.py b/nylas/resources/bookings.py index db5613d..e7a31f0 100644 --- a/nylas/resources/bookings.py +++ b/nylas/resources/bookings.py @@ -8,10 +8,10 @@ DestroyableApiResource, ) from nylas.models.scheduler import Booking, CreateBookingRequest, CreateBookingQueryParams, ConfirmBookingRequest, DestroyBookingQueryParams -from nylas.models.response import Response +from nylas.models.response import Response, DeleteResponse class Bookings( - ListableApiResource, + ListableApiResource, FindableApiResource, CreatableApiResource, UpdatableApiResource, @@ -121,7 +121,7 @@ def reschedule( def destroy( self, booking_id: str, query_params: DestroyBookingQueryParams = None ,overrides: RequestOverrides = None - ) -> Response[None]: + ) -> DeleteResponse: """ Delete a Booking. diff --git a/nylas/resources/configurations.py b/nylas/resources/configurations.py index dcd1a85..d2e25da 100644 --- a/nylas/resources/configurations.py +++ b/nylas/resources/configurations.py @@ -8,7 +8,7 @@ ) from nylas.models.scheduler import Configuration, CreateConfigurationRequest, UpdateConfigurationRequest -from nylas.models.response import Response, ListResponse +from nylas.models.response import Response, ListResponse, DeleteResponse from nylas.models.list_query_params import ListQueryParams from typing import Any @@ -146,7 +146,7 @@ def destroy( identifier: str, config_id: str, overrides: RequestOverrides = None - ) -> None: + ) -> DeleteResponse: """ Delete a Configuration. diff --git a/nylas/resources/scheduler.py b/nylas/resources/scheduler.py index f217ecb..3b7a195 100644 --- a/nylas/resources/scheduler.py +++ b/nylas/resources/scheduler.py @@ -1,5 +1,6 @@ from configurations import Configurations from bookings import Bookings +from sessions import Sessions class Scheduler: """ @@ -27,4 +28,14 @@ def bookings(self) -> Bookings: The Bookings API. """ return Bookings(self.http_client) + + @property + def sessions(self) -> Sessions: + """ + Access the Sessions API. + + Returns: + The Sessions API. + """ + return Sessions(self.http_client) diff --git a/nylas/resources/sessions.py b/nylas/resources/sessions.py new file mode 100644 index 0000000..2759303 --- /dev/null +++ b/nylas/resources/sessions.py @@ -0,0 +1,61 @@ +from nylas.config import RequestOverrides +from nylas.handler.api_resources import ( + CreatableApiResource, + DestroyableApiResource, +) +from nylas.models.response import Response, DeleteResponse +from nylas.models.scheduler import Session, CreateSessionRequest + +class Sessions( + CreatableApiResource, + DestroyableApiResource +): + """ + Nylas Sessions API + + The Nylas Sessions API allows you to create new sessions or manage existing ones. + """ + + def create( + self, + request_body: CreateSessionRequest, + overrides: RequestOverrides = None, + ) -> Response[Session]: + """ + Create a Session. + + Args: + request_body: The request body to create the Session. + overrides: The request overrides to use for the request. + + Returns: + The Session. + """ + + return super().create( + path=f"/v3/scheduling/sessions", + request_body=request_body, + response_type=Session, + overrides=overrides, + ) + + def destroy( + self, + session_id: str, + overrides: RequestOverrides = None, + ) -> DeleteResponse: + """ + Destroy a Session. + + Args: + session_id: The identifier of the Session to destroy. + overrides: The request overrides to use for the request. + + Returns: + None. + """ + + return super().destroy( + path=f"/v3/scheduling/sessions{session_id}", + overrides=overrides, + ) \ No newline at end of file From 5fe327e916bdd3439385988540309b0a4d64822d Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Mon, 4 Nov 2024 15:09:22 +0100 Subject: [PATCH 05/13] Add unit test for configurations resources --- tests/resources/test_configurations.py | 224 +++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 tests/resources/test_configurations.py diff --git a/tests/resources/test_configurations.py b/tests/resources/test_configurations.py new file mode 100644 index 0000000..5b16d08 --- /dev/null +++ b/tests/resources/test_configurations.py @@ -0,0 +1,224 @@ +from nylas.resources.configurations import Configurations + +from nylas.models.scheduler import Configuration + +class TestConfiguration: + def test_configuration_deserialization(self): + configuration_json = { + "id": "abc-123-configuration-id", + "slug": None, + "participants": [ + { + "email": "test@nylas.com", + "is_organizer": True, + "name": "Test", + "availability": { + "calendar_ids": [ + "primary" + ], + "open_hours": [ + { + "days": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "exdates": None, + "timezone": "", + "start": "09:00", + "end": "17:00" + } + ] + }, + "booking": { + "calendar_id": "primary" + }, + "timezone": "" + } + ], + "requires_session_auth": False, + "availability": { + "duration_minutes": 30, + "interval_minutes": 15, + "round_to": 15, + "availability_rules": { + "availability_method": "collective", + "buffer": { + "before": 60, + "after": 0 + }, + "default_open_hours": [ + { + "days": [ + 0, + 1, + 2, + 5, + 6 + ], + "exdates": None, + "timezone": "", + "start": "09:00", + "end": "18:00" + } + ], + "round_robin_group_id": "" + } + }, + "event_booking": { + "title": "Updated Title", + "timezone": "utc", + "description": "", + "location": "none", + "booking_type": "booking", + "conferencing": { + "provider": "Microsoft Teams", + "autocreate": { + "conf_grant_id": "", + "conf_settings": None + } + }, + "hide_participants": None, + "disable_emails": None + }, + "scheduler": { + "available_days_in_future": 7, + "min_cancellation_notice": 60, + "min_booking_notice": 120, + "confirmation_redirect_url": "", + "hide_rescheduling_options": False, + "hide_cancellation_options": False, + "hide_additional_guests": True, + "cancellation_policy": "", + "email_template": { + "booking_confirmed": {} + } + }, + "appearance": { + "submit_button_label": "submit", + "thank_you_message": "thank you for your business. your booking was successful." + } + } + + configuration = Configuration.from_dict(configuration_json) + + assert configuration.id == "abc-123-configuration-id" + assert configuration.slug == None + assert configuration.participants[0].email == "test@nylas.com" + assert configuration.participants[0].is_organizer == True + assert configuration.participants[0].name == "Test" + assert configuration.participants[0].availability.calendar_ids == ["primary"] + assert configuration.participants[0].availability.open_hours[0].days == [0, 1, 2, 3, 4, 5, 6] + assert configuration.participants[0].availability.open_hours[0].exdates == None + assert configuration.participants[0].availability.open_hours[0].timezone == "" + assert configuration.participants[0].booking.calendar_id == "primary" + assert configuration.participants[0].timezone == "" + assert configuration.requires_session_auth == False + assert configuration.availability.duration_minutes == 30 + assert configuration.availability.interval_minutes == 15 + assert configuration.availability.round_to == 15 + assert configuration.availability.availability_rules.availability_method == "collective" + assert configuration.availability.availability_rules.buffer.before == 60 + assert configuration.availability.availability_rules.buffer.after == 0 + assert configuration.availability.availability_rules.default_open_hours[0].days == [0, 1, 2, 5, 6] + assert configuration.availability.availability_rules.default_open_hours[0].exdates == None + assert configuration.availability.availability_rules.default_open_hours[0].timezone == "" + assert configuration.availability.availability_rules.default_open_hours[0].start == "09:00" + assert configuration.availability.availability_rules.default_open_hours[0].end == "18:00" + assert configuration.availability.availability_rules.round_robin_group_id == "" + assert configuration.event_booking.title == "Updated Title" + assert configuration.event_booking.timezone == "utc" + assert configuration.event_booking.description == "" + assert configuration.event_booking.location == "none" + assert configuration.event_booking.booking_type == "booking" + assert configuration.event_booking.conferencing.provider == "Microsoft Teams" + assert configuration.scheduler.available_days_in_future == 7 + assert configuration.scheduler.min_cancellation_notice == 60 + assert configuration.scheduler.min_booking_notice == 120 + assert configuration.scheduler.appearance.submit_button_label == "submit" + + def test_list_configurations(self, http_client_list_response): + configurations = Configurations(http_client_list_response) + configurations.list(identifier="grant-123") + + http_client_list_response._execute.assert_called_once_with( + method="GET", + path="/v3/grants/grant-123/scheduling/configurations", + query_params=None, + request_body=None, + overrides=None, + ) + + def test_find_configuration(self, http_client_response): + configurations = Configurations(http_client_response) + configurations.find(identifier="grant-123", config_id="config-123") + + http_client_response._execute.assert_called_once_with( + method="GET", + path="/v3/grants/grant-123/scheduling/configurations/config-123", + overrides=None, + ) + + def test_create_configuration(self, http_client_response): + configurations = Configurations(http_client_response) + request_body = { + "requires_session_auth": False, + "participants": [ + { + "name": "Test", + "email": "test@nylas.com", + "is_organizer": True, + "availability": { + "calendar_ids": [ + "primary" + ] + }, + "booking": { + "calendar_id": "primary" + } + } + ], + "availability": { + "duration_minutes": 30 + }, + "event_booking": { + "title": "My test event" + } + } + configurations.create(identifier="grant-123", request_body=request_body) + http_client_response._execute.assert_called_once_with( + method="POST", + path="/v3/grants/grant-123/scheduling/configurations", + request_body=request_body, + overrides=None, + ) + + def test_update_configuration(self, http_client_response): + configurations = Configurations(http_client_response) + request_body = { + "event_booking": { + "title": "My test event" + } + } + configurations.update(identifier="grant-123", config_id="config-123", request_body=request_body) + + http_client_response._execute.assert_called_once_with( + method="PUT", + path="/v3/grants/grant-123/scheduling/configurations/config-123", + request_body=request_body, + overrides=None, + ) + + def test_delete_configuration(self, http_client_response): + configurations = Configurations(http_client_response) + configurations.destroy(identifier="grant-123", config_id="config-123") + + http_client_response._execute.assert_called_once_with( + method="DELETE", + path="/v3/grants/grant-123/scheduling/configurations/config-123", + overrides=None, + ) \ No newline at end of file From a20b3469c5265b508f76b9d34ff6a5b5debf573c Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Mon, 4 Nov 2024 16:08:49 +0100 Subject: [PATCH 06/13] Add unit test for sessions resources --- tests/resources/test_sessions.py | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/resources/test_sessions.py diff --git a/tests/resources/test_sessions.py b/tests/resources/test_sessions.py new file mode 100644 index 0000000..9bbab9a --- /dev/null +++ b/tests/resources/test_sessions.py @@ -0,0 +1,40 @@ +from nylas.resources.scheduler import Sessions + +from nylas.models.scheduler import Session + +class TestSession: + def test_session_deserialization(self): + session_json = { + "id": "session-id", + } + + session = Session.from_dict(session_json) + + assert session.id == "session-id" + + def test_create_session(self, http_client_response): + sessions = Sessions(http_client_response) + request_body = { + "configuration_id": "configuration-123", + "time_to_live": 30 + } + + sessions.create(request_body) + + http_client_response._execute.assert_called_once_with( + "POST", + "/v3/scheduling/sessions", + request_body, + overrides=None, + ) + + def test_destroy_session(self, http_client_response): + sessions = Sessions(http_client_response) + + sessions.destroy(session_id="session-123") + + http_client_response._execute.assert_called_once_with( + "DELETE", + "/v3/scheduling/sessions/session-123", + overrides=None, + ) \ No newline at end of file From c2262e60a37ca9fea987d9db9ca374de48e2ce2f Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Mon, 4 Nov 2024 16:45:13 +0100 Subject: [PATCH 07/13] Add unit test for bookingss resources --- nylas/resources/bookings.py | 44 +++++++++++-- tests/resources/test_bookings.py | 106 +++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 tests/resources/test_bookings.py diff --git a/nylas/resources/bookings.py b/nylas/resources/bookings.py index e7a31f0..491646c 100644 --- a/nylas/resources/bookings.py +++ b/nylas/resources/bookings.py @@ -7,7 +7,17 @@ UpdatablePatchApiResource, DestroyableApiResource, ) -from nylas.models.scheduler import Booking, CreateBookingRequest, CreateBookingQueryParams, ConfirmBookingRequest, DestroyBookingQueryParams +from nylas.models.scheduler import ( + Booking, + CreateBookingRequest, + CreateBookingQueryParams, + ConfirmBookingRequest, + FindBookingQueryParams, + DeleteBookingRequest, + RescheduleBookingQueryParams, + DestroyBookingQueryParams, + ConfirmBookingQueryParams +) from nylas.models.response import Response, DeleteResponse class Bookings( @@ -28,7 +38,10 @@ class Bookings( """ def find( - self, identifier: str, booking_id: str, overrides: RequestOverrides = None + self, + booking_id: str, + query_params: FindBookingQueryParams, + overrides: RequestOverrides = None ) -> Response[Booking]: """ Return a Booking. @@ -36,6 +49,7 @@ def find( Args: identifier: The identifier of the Grant to act upon. booking_id: The identifier of the Booking to get. + query_params: The query parameters to include in the request. overrides: The request overrides to use for the request. Returns: @@ -43,7 +57,8 @@ def find( """ return super().find( - path=f"/v3/grants/{identifier}/bookings/{booking_id}", + path=f"/v3/scheduling/bookings/{booking_id}", + query_params=query_params, response_type=Booking, overrides=overrides, ) @@ -76,7 +91,11 @@ def create( ) def confirm( - self, booking_id: str, request_body:ConfirmBookingRequest, overrides: RequestOverrides = None + self, + booking_id: str, + request_body:ConfirmBookingRequest, + query_params: ConfirmBookingQueryParams = None, + overrides: RequestOverrides = None ) -> Response[Booking]: """ Confirm a Booking. @@ -84,6 +103,7 @@ def confirm( Args: booking_id: The identifier of the Booking to confirm. request_body: The values to confirm booking with. + query_params: The query parameters to include in the request. overrides: The request overrides to use for the request. Returns: @@ -93,12 +113,17 @@ def confirm( return super().update( path=f"/v3/scheduling/bookings/{booking_id}", request_body=request_body, + query_params=query_params, response_type=Booking, overrides=overrides, ) def reschedule( - self, booking_id: str, request_body:CreateBookingRequest, overrides: RequestOverrides = None + self, + booking_id: str, + request_body:CreateBookingRequest, + query_params: RescheduleBookingQueryParams = None, + overrides: RequestOverrides = None ) -> Response[Booking]: """ Reschedule a Booking. @@ -106,6 +131,7 @@ def reschedule( Args: booking_id: The identifier of the Booking to reschedule. request_body: The values to reschedule booking with. + query_params: The query parameters to include in the request. overrides: The request overrides to use for the request. Returns: @@ -115,18 +141,23 @@ def reschedule( return super().patch( path=f"/v3/scheduling/bookings/{booking_id}", request_body=request_body, + query_params=query_params, response_type=Booking, overrides=overrides, ) def destroy( - self, booking_id: str, query_params: DestroyBookingQueryParams = None ,overrides: RequestOverrides = None + self, booking_id: str, + request_body: DeleteBookingRequest, + query_params: DestroyBookingQueryParams = None, + overrides: RequestOverrides = None ) -> DeleteResponse: """ Delete a Booking. Args: booking_id: The identifier of the Booking to delete. + request_body: The reason to delete booking with. query_params: The query parameters to include in the request. overrides: The request overrides to use for the request. @@ -136,6 +167,7 @@ def destroy( return super().destroy( path=f"/v3/scheduling/bookings/{booking_id}", + request_body=request_body, query_params=query_params, overrides=overrides, ) \ No newline at end of file diff --git a/tests/resources/test_bookings.py b/tests/resources/test_bookings.py new file mode 100644 index 0000000..b16e645 --- /dev/null +++ b/tests/resources/test_bookings.py @@ -0,0 +1,106 @@ +from nylas.resources.bookings import Bookings + +from nylas.models.scheduler import Booking + +class TestBooking: + def test_booking_deserialization(self): + booking_json = { + "booking_id": "AAAA-BBBB-1111-2222", + "event_id": "CCCC-DDDD-3333-4444", + "title": "My test event", + "organizer": { + "name": "John Doe", + "email": "user@example.com" + }, + "status": "booked", + "description": "This is an example of a description." + } + + booking = Booking.from_dict(booking_json) + + assert booking.booking_id == "AAAA-BBBB-1111-2222" + assert booking.event_id == "CCCC-DDDD-3333-4444" + assert booking.title == "My test event" + assert booking.organizer == {"name": "John Doe", "email": "user@example.com"} + assert booking.status == "booked" + assert booking.description == "This is an example of a description." + + def test_find_booking(self, http_client_find_response): + bookings = Bookings(http_client_find_response) + + bookings.find(booking_id="booking-123") + + http_client_find_response._execute.assert_called_once_with( + "GET", "/v3/scheduling/bookings/booking-123", query_params=None, overrides=None + ) + + def test_create_booking(self, http_client_create_response): + bookings = Bookings(http_client_create_response) + request_body = { + "start_time": 1730725200, + "end_time": 1730727000, + "participants": [ + { + "email": "test@nylas.com" + } + ], + "guest": { + "name": "TEST", + "email": "user@gmail.com" + } + } + bookings.create(request_body=request_body) + http_client_create_response._execute.assert_called_once_with( + "POST", + "/v3/scheduling/bookings", + query_params=None, + request_body=request_body, + overrides=None + ) + + def test_confirm_booking(self, http_client_update_response): + bookings = Bookings(http_client_update_response) + request_body = { + "salt": "_zfg12it", + "status": "cancelled", + } + + bookings.confirm(booking_id="booking-123", request_body=request_body) + http_client_update_response._execute.assert_called_once_with( + "PUT", + "/v3/scheduling/bookings/booking-123", + query_params=None, + request_body=request_body, + overrides=None + ) + + def test_reschedule_booking(self, http_client_update_response): + bookings = Bookings(http_client_update_response) + request_body = { + "start_time": 1730725200, + "end_time": 1730727000, + } + + bookings.reschedule(booking_id="booking-123", request_body=request_body) + http_client_update_response._execute.assert_called_once_with( + "PATCH", + "/v3/scheduling/bookings/booking-123", + query_params=None, + request_body=request_body, + overrides=None + ) + + def test_destroy_booking(self, http_client_delete_response): + bookings = Bookings(http_client_delete_response) + request_body = { + "cancellation_reason": "I am no longer available at this time." + } + bookings.destroy(booking_id="booking-123") + + http_client_delete_response._execute.assert_called_once_with( + "DELETE", + "/v3/scheduling/bookings/booking-123", + request_body=request_body, + query_params=None, + overrides=None + ) \ No newline at end of file From d1c8619518fb9b6086b76712ef436e9f630c94a6 Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Mon, 4 Nov 2024 17:14:03 +0100 Subject: [PATCH 08/13] Fix imports --- CHANGELOG.md | 4 ++++ nylas/models/scheduler.py | 4 ++-- nylas/resources/scheduler.py | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5ecbb7..f66fc44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ nylas-python Changelog ====================== +Unreleased +-------------- +* Add support for Scheduler APIs + v6.4.0 ---------------- * Add support for from field for sending messages diff --git a/nylas/models/scheduler.py b/nylas/models/scheduler.py index 5fcf28c..5c76f4c 100644 --- a/nylas/models/scheduler.py +++ b/nylas/models/scheduler.py @@ -1,5 +1,5 @@ -from dataclasses import dataclass, field -from typing import Dict, Any, Optional, List +from dataclasses import dataclass +from typing import Dict, Optional, List from dataclasses_json import dataclass_json from typing_extensions import TypedDict, NotRequired, Literal diff --git a/nylas/resources/scheduler.py b/nylas/resources/scheduler.py index 3b7a195..11c0781 100644 --- a/nylas/resources/scheduler.py +++ b/nylas/resources/scheduler.py @@ -1,6 +1,6 @@ -from configurations import Configurations -from bookings import Bookings -from sessions import Sessions +from nylas.resources.configurations import Configurations +from nylas.resources.bookings import Bookings +from nylas.resources.sessions import Sessions class Scheduler: """ From b139df5a3e6ed1c5c7807278647c4898a2a0131e Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Mon, 4 Nov 2024 17:59:18 +0100 Subject: [PATCH 09/13] Fix unit test --- nylas/models/scheduler.py | 1 + nylas/resources/configurations.py | 8 ++--- tests/resources/test_bookings.py | 45 ++++++++++++++------------ tests/resources/test_configurations.py | 39 ++++++++++++++-------- tests/resources/test_sessions.py | 7 +++- 5 files changed, 60 insertions(+), 40 deletions(-) diff --git a/nylas/models/scheduler.py b/nylas/models/scheduler.py index 5c76f4c..8dd1872 100644 --- a/nylas/models/scheduler.py +++ b/nylas/models/scheduler.py @@ -222,6 +222,7 @@ class Configuration: scheduler: Settings for the Scheduler UI. appearance: Appearance settings for the Scheduler UI. """ + id: str participants: List[ConfigParticipant] availability: Availability event_booking: EventBooking diff --git a/nylas/resources/configurations.py b/nylas/resources/configurations.py index d2e25da..1499c29 100644 --- a/nylas/resources/configurations.py +++ b/nylas/resources/configurations.py @@ -94,7 +94,7 @@ def find( def create( self, identifier: str, - requestBody: CreateConfigurationRequest, + request_body: CreateConfigurationRequest, overrides: RequestOverrides = None ) -> Response[Configuration]: """ @@ -110,7 +110,7 @@ def create( """ return super().create( path=f"/v3/grants/{identifier}/scheduling/configurations", - request_body=requestBody, + request_body=request_body, overrides=overrides, response_type=Configuration, ) @@ -119,7 +119,7 @@ def update( self, identifier: str, config_id: str, - requestBody: UpdateConfigurationRequest, + request_body: UpdateConfigurationRequest, overrides: RequestOverrides = None ) -> Response[Configuration]: """ @@ -136,7 +136,7 @@ def update( """ return super().update( path=f"/v3/grants/{identifier}/scheduling/configurations/{config_id}", - request_body=requestBody, + request_body=request_body, overrides=overrides, response_type=Configuration, ) diff --git a/tests/resources/test_bookings.py b/tests/resources/test_bookings.py index b16e645..e826cb0 100644 --- a/tests/resources/test_bookings.py +++ b/tests/resources/test_bookings.py @@ -21,21 +21,22 @@ def test_booking_deserialization(self): assert booking.booking_id == "AAAA-BBBB-1111-2222" assert booking.event_id == "CCCC-DDDD-3333-4444" assert booking.title == "My test event" - assert booking.organizer == {"name": "John Doe", "email": "user@example.com"} + assert booking.organizer.name == "John Doe" + assert booking.organizer.email == "user@example.com" assert booking.status == "booked" assert booking.description == "This is an example of a description." - def test_find_booking(self, http_client_find_response): - bookings = Bookings(http_client_find_response) + def test_find_booking(self, http_client_response): + bookings = Bookings(http_client_response) bookings.find(booking_id="booking-123") - http_client_find_response._execute.assert_called_once_with( + http_client_response._execute.assert_called_once_with( "GET", "/v3/scheduling/bookings/booking-123", query_params=None, overrides=None ) - def test_create_booking(self, http_client_create_response): - bookings = Bookings(http_client_create_response) + def test_create_booking(self, http_client_response): + bookings = Bookings(http_client_response) request_body = { "start_time": 1730725200, "end_time": 1730727000, @@ -50,39 +51,41 @@ def test_create_booking(self, http_client_create_response): } } bookings.create(request_body=request_body) - http_client_create_response._execute.assert_called_once_with( + http_client_response._execute.assert_called_once_with( "POST", "/v3/scheduling/bookings", - query_params=None, - request_body=request_body, + None, + None, + request_body, overrides=None ) - def test_confirm_booking(self, http_client_update_response): - bookings = Bookings(http_client_update_response) + def test_confirm_booking(self, http_client_response): + bookings = Bookings(http_client_response) request_body = { "salt": "_zfg12it", "status": "cancelled", } bookings.confirm(booking_id="booking-123", request_body=request_body) - http_client_update_response._execute.assert_called_once_with( + http_client_response._execute.assert_called_once_with( "PUT", "/v3/scheduling/bookings/booking-123", - query_params=None, - request_body=request_body, + None, + None, + request_body, overrides=None ) - def test_reschedule_booking(self, http_client_update_response): - bookings = Bookings(http_client_update_response) + def test_reschedule_booking(self, http_client_response): + bookings = Bookings(http_client_response) request_body = { "start_time": 1730725200, "end_time": 1730727000, } bookings.reschedule(booking_id="booking-123", request_body=request_body) - http_client_update_response._execute.assert_called_once_with( + http_client_response._execute.assert_called_once_with( "PATCH", "/v3/scheduling/bookings/booking-123", query_params=None, @@ -90,14 +93,14 @@ def test_reschedule_booking(self, http_client_update_response): overrides=None ) - def test_destroy_booking(self, http_client_delete_response): - bookings = Bookings(http_client_delete_response) + def test_destroy_booking(self, http_client_response): + bookings = Bookings(http_client_response) request_body = { "cancellation_reason": "I am no longer available at this time." } - bookings.destroy(booking_id="booking-123") + bookings.destroy(booking_id="booking-123", request_body=request_body) - http_client_delete_response._execute.assert_called_once_with( + http_client_response._execute.assert_called_once_with( "DELETE", "/v3/scheduling/bookings/booking-123", request_body=request_body, diff --git a/tests/resources/test_configurations.py b/tests/resources/test_configurations.py index 5b16d08..8ba362f 100644 --- a/tests/resources/test_configurations.py +++ b/tests/resources/test_configurations.py @@ -146,10 +146,11 @@ def test_list_configurations(self, http_client_list_response): configurations.list(identifier="grant-123") http_client_list_response._execute.assert_called_once_with( - method="GET", - path="/v3/grants/grant-123/scheduling/configurations", - query_params=None, - request_body=None, + "GET", + "/v3/grants/grant-123/scheduling/configurations", + None, + None, + None overrides=None, ) @@ -158,8 +159,11 @@ def test_find_configuration(self, http_client_response): configurations.find(identifier="grant-123", config_id="config-123") http_client_response._execute.assert_called_once_with( - method="GET", - path="/v3/grants/grant-123/scheduling/configurations/config-123", + "GET", + "/v3/grants/grant-123/scheduling/configurations/config-123", + None, + None, + None, overrides=None, ) @@ -191,9 +195,11 @@ def test_create_configuration(self, http_client_response): } configurations.create(identifier="grant-123", request_body=request_body) http_client_response._execute.assert_called_once_with( - method="POST", - path="/v3/grants/grant-123/scheduling/configurations", - request_body=request_body, + "POST", + "/v3/grants/grant-123/scheduling/configurations", + None, + None, + request_body, overrides=None, ) @@ -207,9 +213,11 @@ def test_update_configuration(self, http_client_response): configurations.update(identifier="grant-123", config_id="config-123", request_body=request_body) http_client_response._execute.assert_called_once_with( - method="PUT", - path="/v3/grants/grant-123/scheduling/configurations/config-123", - request_body=request_body, + "PUT", + "/v3/grants/grant-123/scheduling/configurations/config-123", + None, + None, + request_body, overrides=None, ) @@ -218,7 +226,10 @@ def test_delete_configuration(self, http_client_response): configurations.destroy(identifier="grant-123", config_id="config-123") http_client_response._execute.assert_called_once_with( - method="DELETE", - path="/v3/grants/grant-123/scheduling/configurations/config-123", + "DELETE", + "/v3/grants/grant-123/scheduling/configurations/config-123", + None, + None, + None, overrides=None, ) \ No newline at end of file diff --git a/tests/resources/test_sessions.py b/tests/resources/test_sessions.py index 9bbab9a..07c8268 100644 --- a/tests/resources/test_sessions.py +++ b/tests/resources/test_sessions.py @@ -5,7 +5,7 @@ class TestSession: def test_session_deserialization(self): session_json = { - "id": "session-id", + "session_id": "session-id", } session = Session.from_dict(session_json) @@ -24,6 +24,8 @@ def test_create_session(self, http_client_response): http_client_response._execute.assert_called_once_with( "POST", "/v3/scheduling/sessions", + None, + None, request_body, overrides=None, ) @@ -36,5 +38,8 @@ def test_destroy_session(self, http_client_response): http_client_response._execute.assert_called_once_with( "DELETE", "/v3/scheduling/sessions/session-123", + None, + None, + None, overrides=None, ) \ No newline at end of file From 7614f6f528f7f439bf47010cabe1631d4165539e Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Mon, 4 Nov 2024 18:00:36 +0100 Subject: [PATCH 10/13] Fix unit test --- tests/resources/test_configurations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/resources/test_configurations.py b/tests/resources/test_configurations.py index 8ba362f..85aeafa 100644 --- a/tests/resources/test_configurations.py +++ b/tests/resources/test_configurations.py @@ -150,7 +150,7 @@ def test_list_configurations(self, http_client_list_response): "/v3/grants/grant-123/scheduling/configurations", None, None, - None + None, overrides=None, ) From bd1d3970a761712735733d2e627bd3275b810cc5 Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Tue, 5 Nov 2024 10:53:43 +0100 Subject: [PATCH 11/13] Fix black and pytest --- nylas/client.py | 2 +- nylas/handler/api_resources.py | 3 +- nylas/models/messages.py | 2 - nylas/models/scheduler.py | 150 ++++++++--- nylas/resources/bookings.py | 328 +++++++++++++------------ nylas/resources/configurations.py | 301 +++++++++++------------ nylas/resources/scheduler.py | 9 +- nylas/resources/sessions.py | 103 ++++---- tests/resources/test_bookings.py | 23 +- tests/resources/test_configurations.py | 31 ++- tests/resources/test_sessions.py | 8 +- 11 files changed, 525 insertions(+), 435 deletions(-) diff --git a/nylas/client.py b/nylas/client.py index e729504..349c55f 100644 --- a/nylas/client.py +++ b/nylas/client.py @@ -170,7 +170,7 @@ def webhooks(self) -> Webhooks: The Webhooks API. """ return Webhooks(self.http_client) - + @property def scheduler(self) -> Scheduler: """ diff --git a/nylas/handler/api_resources.py b/nylas/handler/api_resources.py index f744419..35c6dce 100644 --- a/nylas/handler/api_resources.py +++ b/nylas/handler/api_resources.py @@ -73,7 +73,8 @@ def update( ) return Response.from_dict(response_json, response_type) - + + class UpdatablePatchApiResource(Resource): def patch( self, diff --git a/nylas/models/messages.py b/nylas/models/messages.py index 12da517..7d5d405 100644 --- a/nylas/models/messages.py +++ b/nylas/models/messages.py @@ -132,7 +132,6 @@ class Message: class FindMessageQueryParams(TypedDict): - """ Query parameters for finding a message. @@ -144,7 +143,6 @@ class FindMessageQueryParams(TypedDict): class UpdateMessageRequest(TypedDict): - """ Request payload for updating a message. diff --git a/nylas/models/scheduler.py b/nylas/models/scheduler.py index 8dd1872..c0ee850 100644 --- a/nylas/models/scheduler.py +++ b/nylas/models/scheduler.py @@ -6,12 +6,24 @@ from nylas.models.events import Conferencing from nylas.models.availability import AvailabilityRules, OpenHours -BookingType = Literal['booking', 'organizer-confirmation'] -BookingReminderType = Literal['email', 'webhook'] -BookingRecipientType = Literal['host', 'guest', 'all'] -EmailLanguage = Literal['en', 'es', 'fr', 'de', 'nl', 'sv', 'ja', 'zh'] -AdditionalFieldType = Literal['text', 'multi_line_text', 'email', 'phone_number', 'dropdown', 'date', 'checkbox', 'radio_button'] -AdditonalFieldOptionsType = Literal['text', 'email', 'phone_number', 'date', 'checkbox', 'radio_button'] +BookingType = Literal["booking", "organizer-confirmation"] +BookingReminderType = Literal["email", "webhook"] +BookingRecipientType = Literal["host", "guest", "all"] +EmailLanguage = Literal["en", "es", "fr", "de", "nl", "sv", "ja", "zh"] +AdditionalFieldType = Literal[ + "text", + "multi_line_text", + "email", + "phone_number", + "dropdown", + "date", + "checkbox", + "radio_button", +] +AdditonalFieldOptionsType = Literal[ + "text", "email", "phone_number", "date", "checkbox", "radio_button" +] + @dataclass_json @dataclass @@ -23,6 +35,7 @@ class BookingConfirmedTemplate: title: The title to replace the default 'Booking Confirmed' title. body: The additional body to be appended after the default body. """ + title: Optional[str] = None body: Optional[str] = None @@ -37,23 +50,29 @@ class EmailTemplate: logo: The URL to a custom logo that appears at the top of the booking email. booking_confirmed: Configurable settings specifically for booking confirmed emails. """ + # logo: Optional[str] = None booking_confirmed: Optional[BookingConfirmedTemplate] = None + @dataclass_json @dataclass class AdditionalField: """ Class representation of an additional field. - + Atributes: - label: The text label to be displayed in the Scheduler UI. - type: The field type. Supported values are text, multi_line_text, email, phone_number, dropdown, date, checkbox, and radio_button - required: Whether the field is required to be filled out by the guest when booking an event. - pattern: A regular expression pattern that the value of the field must match. - order: The order in which the field will be displayed in the Scheduler UI. Fields with lower order values will be displayed first. - options: A list of options for the dropdown or radio_button types. This field is required for the dropdown and radio_button types. + label: The text label to be displayed in the Scheduler UI. + type: The field type. Supported values are text, multi_line_text, + email, phone_number, dropdown, date, checkbox, and radio_button + required: Whether the field is required to be filled out by the guest when booking an event. + pattern: A regular expression pattern that the value of the field must match. + order: The order in which the field will be displayed in the Scheduler UI. + Fields with lower order values will be displayed first. + options: A list of options for the dropdown or radio_button types. + This field is required for the dropdown and radio_button types. """ + label: str type: AdditionalFieldType required: bool @@ -61,6 +80,7 @@ class AdditionalField: order: Optional[int] = None options: Optional[AdditonalFieldOptionsType] = None + @dataclass_json @dataclass class SchedulerSettings: @@ -77,11 +97,14 @@ class SchedulerSettings: cancellation_url: The URL used to cancel bookings. organizer_confirmation_url: The URL used to confirm or cancel pending bookings. confirmation_redirect_url: The custom URL to redirect to once the booking is confirmed. - hide_rescheduling_options: Whether the option to reschedule an event is hidden in booking confirmations and notifications. - hide_cancellation_options: Whether the option to cancel an event is hidden in booking confirmations and notifications. + hide_rescheduling_options: Whether the option to reschedule an event + is hidden in booking confirmations and notifications. + hide_cancellation_options: Whether the option to cancel an event + is hidden in booking confirmations and notifications. hide_additional_guests: Whether to hide the additional guests field on the scheduling page. email_template: Configurable settings for booking emails. """ + additional_fields: Optional[Dict[str, AdditionalField]] = None available_days_in_future: Optional[int] = None min_booking_notice: Optional[int] = None @@ -109,6 +132,7 @@ class BookingReminder: recipient: The recipient of the reminder. email_subject: The subject of the email reminder. """ + type: str minutes_before_event: int recipient: Optional[str] = None @@ -131,6 +155,7 @@ class EventBooking: disable_emails: Whether Nylas sends email messages when an event is booked, cancelled, or rescheduled. reminders: The list of reminders to send to participants before the event starts. """ + title: str description: Optional[str] = None location: Optional[str] = None @@ -153,6 +178,7 @@ class Availability: round_to: Nylas rounds each time slot to the nearest multiple of this number of minutes. availability_rules: Availability rules for scheduling configuration. """ + duration_minutes: int interval_minutes: Optional[int] = None round_to: Optional[int] = None @@ -168,6 +194,7 @@ class ParticipantBooking: Attributes: calendar_id: The calendar ID that the event is created in. """ + calendar_id: str @@ -181,6 +208,7 @@ class ParticipantAvailability: calendar_ids: List of calendar IDs associated with the participant's email address. open_hours: Open hours for this participant. The endpoint searches for free time slots during these open hours. """ + calendar_ids: List[str] open_hours: Optional[List[OpenHours]] = None @@ -199,6 +227,7 @@ class ConfigParticipant: is_organizer: Whether the participant is the organizer of the event. timezone: The participant's timezone. """ + email: str availability: ParticipantAvailability booking: ParticipantBooking @@ -222,6 +251,7 @@ class Configuration: scheduler: Settings for the Scheduler UI. appearance: Appearance settings for the Scheduler UI. """ + id: str participants: List[ConfigParticipant] availability: Availability @@ -233,6 +263,19 @@ class Configuration: class CreateConfigurationRequest(TypedDict): + """ + Interface of a Nylas create configuration request. + + Attributes: + participants: List of participants included in the scheduled event. + availability: Rules that determine available time slots for the event. + event_booking: Booking data for the event. + slug: Unique identifier for the Configuration object. + requires_session_auth: If true, scheduling Availability and Bookings endpoints require a valid session ID. + scheduler: Settings for the Scheduler UI. + appearance: Appearance settings for the Scheduler UI. + """ + participants: List[ConfigParticipant] availability: Availability event_booking: EventBooking @@ -243,6 +286,18 @@ class CreateConfigurationRequest(TypedDict): class UpdateConfigurationRequest(TypedDict): + """ + Interface of a Nylas update configuration request. + + Attributes: + participants: List of participants included in the scheduled event. + availability: Rules that determine available time slots for the event. + event_booking: Booking data for the event. + slug: Unique identifier for the Configuration object. + requires_session_auth: If true, scheduling Availability and Bookings endpoints require a valid session ID. + scheduler: Settings for the Scheduler UI. + appearance: Appearance settings for the Scheduler UI. + """ participants: NotRequired[List[ConfigParticipant]] availability: NotRequired[Availability] event_booking: NotRequired[EventBooking] @@ -253,6 +308,17 @@ class UpdateConfigurationRequest(TypedDict): class CreateSessionRequest(TypedDict): + """ + Interface of a Nylas create session request. + + Attributes: + configuration_id: The ID of the Configuration object whose settings are used for calculating availability. + If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. + slug: The slug of the Configuration object whose settings are used for calculating availability. + If you're using session authentication (requires_session_auth is set to true) or using configurationId, + slug is not required. + time_to_live: The time-to-live in seconds for the session + """ configuration_id: NotRequired[str] slug: NotRequired[str] time_to_live: NotRequired[int] @@ -267,6 +333,7 @@ class Session: Attributes: session_id: The ID of the session. """ + session_id: str @@ -280,9 +347,11 @@ class BookingGuest: email: The email address of the guest. name: The name of the guest. """ + email: str name: str + @dataclass_json @dataclass class BookingParticipant: @@ -292,8 +361,9 @@ class BookingParticipant: Attributes: email: The email address of the participant to include in the booking. """ + email: str - + @dataclass_json @dataclass @@ -305,12 +375,15 @@ class CreateBookingRequest: start_time: The event's start time, in Unix epoch format. end_time: The event's end time, in Unix epoch format. guest: Details about the guest that is creating the booking. - participants: List of participant email addresses from the Configuration object to include in the booking. + participants: List of participant email addresses from the + Configuration object to include in the booking. timezone: The guest's timezone that is used in email notifications. email_language: The language of the guest email notifications. additional_guests: List of additional guest email addresses to include in the booking. - additional_fields: Dictionary of additional field keys mapped to values populated by the guest in the booking form. + additional_fields: Dictionary of additional field keys mapped to + values populated by the guest in the booking form. """ + start_time: int end_time: int guest: BookingGuest @@ -331,12 +404,14 @@ class BookingOrganizer: email: The email address of the participant designated as the organizer of the event. name: The name of the participant designated as the organizer of the event. """ + email: str name: Optional[str] = None -BookingStatus = Literal['pending', 'confirmed', 'cancelled'] -ConfirmBookingStatus = Literal['confirm', 'cancel'] +BookingStatus = Literal["pending", "confirmed", "cancelled"] +ConfirmBookingStatus = Literal["confirm", "cancel"] + @dataclass_json @dataclass @@ -352,6 +427,7 @@ class Booking: status: The current status of the booking. description: The description of the event. """ + booking_id: str event_id: str title: str @@ -371,10 +447,12 @@ class ConfirmBookingRequest: status: The action to take on the pending booking. cancellation_reason: The reason the booking is being cancelled. """ + salt: str status: ConfirmBookingStatus cancellation_reason: Optional[str] = None + @dataclass_json @dataclass class DeleteBookingRequest: @@ -384,6 +462,7 @@ class DeleteBookingRequest: Attributes: cancellation_reason: The reason the booking is being cancelled. """ + cancellation_reason: Optional[str] = None @@ -397,9 +476,11 @@ class RescheduleBookingRequest: start_time: The event's start time, in Unix epoch format. end_time: The event's end time, in Unix epoch format. """ + start_time: int end_time: int + @dataclass_json @dataclass class CreateBookingQueryParams: @@ -407,12 +488,15 @@ class CreateBookingQueryParams: Class representation of query parameters for creating a booking. Attributes: - configuration_id: The ID of the Configuration object whose settings are used for calculating availability. - If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. - slug: The slug of the Configuration object whose settings are used for calculating availability. - If you're using session authentication (requires_session_auth is set to true) or using configurationId, slug is not required. - timezone: The timezone to use for the booking. If not provided, Nylas uses the timezone from the Configuration object. + configuration_id: The ID of the Configuration object whose settings are used for calculating availability. + If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. + slug: The slug of the Configuration object whose settings are used for calculating availability. + If you're using session authentication (requires_session_auth is set to true) or using configurationId, + slug is not required. + timezone: The timezone to use for the booking. + If not provided, Nylas uses the timezone from the Configuration object. """ + configuration_id: Optional[str] = None slug: Optional[str] = None timezone: Optional[str] = None @@ -423,16 +507,20 @@ class FindBookingQueryParams: Class representation of query parameters for finding a booking. Attributes: - configuration_id: The ID of the Configuration object whose settings are used for calculating availability. - If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. - slug: The slug of the Configuration object whose settings are used for calculating availability. - If you're using session authentication (requires_session_auth is set to true) or using configurationId, slug is not required. - client_id: The client ID that was used to create the Configuration object. client_id is required only if using slug. + configuration_id: The ID of the Configuration object whose settings are used for calculating availability. + If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. + slug: The slug of the Configuration object whose settings are used for calculating availability. + If you're using session authentication (requires_session_auth is set to true) + or using configurationId, slug is not required. + client_id: The client ID that was used to create the Configuration object. + client_id is required only if using slug. """ + configuration_id: Optional[str] = None slug: Optional[str] = None client_id: Optional[str] = None -ConfirmBookingQueryParams = FindBookingQueryParams + +ConfirmBookingQueryParams = FindBookingQueryParams RescheduleBookingQueryParams = FindBookingQueryParams DestroyBookingQueryParams = FindBookingQueryParams diff --git a/nylas/resources/bookings.py b/nylas/resources/bookings.py index 491646c..5fac015 100644 --- a/nylas/resources/bookings.py +++ b/nylas/resources/bookings.py @@ -1,173 +1,175 @@ from nylas.config import RequestOverrides from nylas.handler.api_resources import ( - ListableApiResource, - FindableApiResource, CreatableApiResource, - UpdatableApiResource, - UpdatablePatchApiResource, DestroyableApiResource, + FindableApiResource, + ListableApiResource, + UpdatableApiResource, + UpdatablePatchApiResource, ) +from nylas.models.response import DeleteResponse, Response from nylas.models.scheduler import ( - Booking, - CreateBookingRequest, - CreateBookingQueryParams, - ConfirmBookingRequest, - FindBookingQueryParams, - DeleteBookingRequest, - RescheduleBookingQueryParams, - DestroyBookingQueryParams, - ConfirmBookingQueryParams + Booking, + ConfirmBookingQueryParams, + ConfirmBookingRequest, + CreateBookingQueryParams, + CreateBookingRequest, + DeleteBookingRequest, + DestroyBookingQueryParams, + FindBookingQueryParams, + RescheduleBookingQueryParams, ) -from nylas.models.response import Response, DeleteResponse + class Bookings( - ListableApiResource, - FindableApiResource, - CreatableApiResource, - UpdatableApiResource, - UpdatablePatchApiResource, - DestroyableApiResource, + ListableApiResource, + FindableApiResource, + CreatableApiResource, + UpdatableApiResource, + UpdatablePatchApiResource, + DestroyableApiResource, ): - """ - Nylas Bookings API - - The Nylas Bookings API allows you to create new bookings or manage existing ones, as well as getting - bookings details for a user. - - A booking can be accessed by one, or several people, and can contain events. - """ - - def find( - self, - booking_id: str, - query_params: FindBookingQueryParams, - overrides: RequestOverrides = None - ) -> Response[Booking]: - """ - Return a Booking. - - Args: - identifier: The identifier of the Grant to act upon. - booking_id: The identifier of the Booking to get. - query_params: The query parameters to include in the request. - overrides: The request overrides to use for the request. - - Returns: - The Booking. - """ - - return super().find( - path=f"/v3/scheduling/bookings/{booking_id}", - query_params=query_params, - response_type=Booking, - overrides=overrides, - ) - - def create( - self, - request_body: CreateBookingRequest, - query_params: CreateBookingQueryParams = None, - overrides: RequestOverrides = None, - ) -> Response[Booking]: - """ - Create a Booking. - - Args: - request_body: The values to create booking with. - overrides: The request overrides to use for the request. - query_params: The query parameters to include in the request. - overrides: The request overrides to use for the request. - - Returns: - The created Booking. - """ - - return super().create( - path=f"/v3/scheduling/bookings", - request_body=request_body, - query_params=query_params, - response_type=Booking, - overrides=overrides, - ) - - def confirm( - self, - booking_id: str, - request_body:ConfirmBookingRequest, - query_params: ConfirmBookingQueryParams = None, - overrides: RequestOverrides = None - ) -> Response[Booking]: - """ - Confirm a Booking. - - Args: - booking_id: The identifier of the Booking to confirm. - request_body: The values to confirm booking with. - query_params: The query parameters to include in the request. - overrides: The request overrides to use for the request. - - Returns: - The confirmed Booking. - """ - - return super().update( - path=f"/v3/scheduling/bookings/{booking_id}", - request_body=request_body, - query_params=query_params, - response_type=Booking, - overrides=overrides, - ) - - def reschedule( - self, - booking_id: str, - request_body:CreateBookingRequest, - query_params: RescheduleBookingQueryParams = None, - overrides: RequestOverrides = None - ) -> Response[Booking]: - """ - Reschedule a Booking. - - Args: - booking_id: The identifier of the Booking to reschedule. - request_body: The values to reschedule booking with. - query_params: The query parameters to include in the request. - overrides: The request overrides to use for the request. - - Returns: - The rescheduled Booking. - """ - - return super().patch( - path=f"/v3/scheduling/bookings/{booking_id}", - request_body=request_body, - query_params=query_params, - response_type=Booking, - overrides=overrides, - ) - - def destroy( - self, booking_id: str, - request_body: DeleteBookingRequest, - query_params: DestroyBookingQueryParams = None, - overrides: RequestOverrides = None - ) -> DeleteResponse: - """ - Delete a Booking. - - Args: - booking_id: The identifier of the Booking to delete. - request_body: The reason to delete booking with. - query_params: The query parameters to include in the request. - overrides: The request overrides to use for the request. - - Returns: - None. - """ - - return super().destroy( - path=f"/v3/scheduling/bookings/{booking_id}", - request_body=request_body, - query_params=query_params, - overrides=overrides, - ) \ No newline at end of file + """ + Nylas Bookings API + + The Nylas Bookings API allows you to create new bookings or manage existing ones, as well as getting + bookings details for a user. + + A booking can be accessed by one, or several people, and can contain events. + """ + + def find( + self, + booking_id: str, + query_params: FindBookingQueryParams = None, + overrides: RequestOverrides = None, + ) -> Response[Booking]: + """ + Return a Booking. + + Args: + identifier: The identifier of the Grant to act upon. + booking_id: The identifier of the Booking to get. + query_params: The query parameters to include in the request. + overrides: The request overrides to use for the request. + + Returns: + The Booking. + """ + + return super().find( + path=f"/v3/scheduling/bookings/{booking_id}", + query_params=query_params, + response_type=Booking, + overrides=overrides, + ) + + def create( + self, + request_body: CreateBookingRequest, + query_params: CreateBookingQueryParams = None, + overrides: RequestOverrides = None, + ) -> Response[Booking]: + """ + Create a Booking. + + Args: + request_body: The values to create booking with. + overrides: The request overrides to use for the request. + query_params: The query parameters to include in the request. + overrides: The request overrides to use for the request. + + Returns: + The created Booking. + """ + + return super().create( + path="/v3/scheduling/bookings", + request_body=request_body, + query_params=query_params, + response_type=Booking, + overrides=overrides, + ) + + def confirm( + self, + booking_id: str, + request_body: ConfirmBookingRequest, + query_params: ConfirmBookingQueryParams = None, + overrides: RequestOverrides = None, + ) -> Response[Booking]: + """ + Confirm a Booking. + + Args: + booking_id: The identifier of the Booking to confirm. + request_body: The values to confirm booking with. + query_params: The query parameters to include in the request. + overrides: The request overrides to use for the request. + + Returns: + The confirmed Booking. + """ + + return super().update( + path=f"/v3/scheduling/bookings/{booking_id}", + request_body=request_body, + query_params=query_params, + response_type=Booking, + overrides=overrides, + ) + + def reschedule( + self, + booking_id: str, + request_body: CreateBookingRequest, + query_params: RescheduleBookingQueryParams = None, + overrides: RequestOverrides = None, + ) -> Response[Booking]: + """ + Reschedule a Booking. + + Args: + booking_id: The identifier of the Booking to reschedule. + request_body: The values to reschedule booking with. + query_params: The query parameters to include in the request. + overrides: The request overrides to use for the request. + + Returns: + The rescheduled Booking. + """ + + return super().patch( + path=f"/v3/scheduling/bookings/{booking_id}", + request_body=request_body, + query_params=query_params, + response_type=Booking, + overrides=overrides, + ) + + def destroy( + self, + booking_id: str, + request_body: DeleteBookingRequest, + query_params: DestroyBookingQueryParams = None, + overrides: RequestOverrides = None, + ) -> DeleteResponse: + """ + Delete a Booking. + + Args: + booking_id: The identifier of the Booking to delete. + request_body: The reason to delete booking with. + query_params: The query parameters to include in the request. + overrides: The request overrides to use for the request. + + Returns: + None. + """ + + return super().destroy( + path=f"/v3/scheduling/bookings/{booking_id}", + request_body=request_body, + query_params=query_params, + overrides=overrides, + ) diff --git a/nylas/resources/configurations.py b/nylas/resources/configurations.py index 1499c29..85c47ec 100644 --- a/nylas/resources/configurations.py +++ b/nylas/resources/configurations.py @@ -1,161 +1,160 @@ from nylas.config import RequestOverrides from nylas.handler.api_resources import ( - ListableApiResource, - FindableApiResource, CreatableApiResource, - UpdatableApiResource, DestroyableApiResource, + FindableApiResource, + ListableApiResource, + UpdatableApiResource, ) - -from nylas.models.scheduler import Configuration, CreateConfigurationRequest, UpdateConfigurationRequest -from nylas.models.response import Response, ListResponse, DeleteResponse from nylas.models.list_query_params import ListQueryParams -from typing import Any +from nylas.models.response import DeleteResponse, ListResponse, Response +from nylas.models.scheduler import ( + Configuration, + CreateConfigurationRequest, + UpdateConfigurationRequest, +) + class ListConfigurationsParams(ListQueryParams): - """ - Interface of the query parameters for listing configurations. - - Attributes: - limit: The maximum number of objects to return. - This field defaults to 50. The maximum allowed value is 200. - page_token: An identifier that specifies which page of data to return. - This value should be taken from a ListResponse object's next_cursor parameter. - identifier: The identifier of the Grant to act upon. - """ - # identifier: str - + """ + Interface of the query parameters for listing configurations. + + Attributes: + limit: The maximum number of objects to return. + This field defaults to 50. The maximum allowed value is 200. + page_token: An identifier that specifies which page of data to return. + This value should be taken from a ListResponse object's next_cursor parameter. + identifier: The identifier of the Grant to act upon. + """ + + identifier: str + class Configurations( - ListableApiResource, - FindableApiResource, - CreatableApiResource, - UpdatableApiResource, - DestroyableApiResource, - ): - """ - Nylas Configuration API - - The Nylas configuration API allows you to create new configurations or manage existing ones, as well as getting - configurations details for a user. - - Nylas Scheduler stores Configuration objects in the Scheduler database and loads them as Scheduling Pages in the Scheduler UI. - """ - - def list( - self, - identifier: str, - query_params: ListConfigurationsParams = None, - overrides: RequestOverrides = None - ) -> ListResponse[Any]: - """ - Return all Configurations. - - Args: - identifier: The identifier of the Grant to act upon. - overrides: The request overrides to use for the request. - - Returns: - The list of Configurations. - """ - # import pdb; pdb.set_trace(); - res = super().list( - path=f"/v3/grants/{identifier}/scheduling/configurations", - overrides=overrides, - response_type=Configuration, - query_params=query_params, - ) - print("What's this", res) - return res - - def find( - self, - identifier: str, - config_id: str, - overrides: RequestOverrides = None - ) -> Response[Configuration]: - """ - Return a Configuration. - - Args: - identifier: The identifier of the Grant to act upon. - config_id: The identifier of the Configuration to get. - overrides: The request overrides to use for the request. - - Returns: - The Configuration object. - """ - return super().find( - path=f"/v3/grants/{identifier}/scheduling/configurations/{config_id}", - overrides=overrides, - response_type=Configuration, - ) - - def create( - self, - identifier: str, - request_body: CreateConfigurationRequest, - overrides: RequestOverrides = None - ) -> Response[Configuration]: - """ - Create a new Configuration. - - Args: - identifier: The identifier of the Grant to act upon. - data: The data to create the Configuration with. - overrides: The request overrides to use for the request. - - Returns: - The Configuration object. - """ - return super().create( - path=f"/v3/grants/{identifier}/scheduling/configurations", - request_body=request_body, - overrides=overrides, - response_type=Configuration, - ) - - def update( - self, - identifier: str, - config_id: str, - request_body: UpdateConfigurationRequest, - overrides: RequestOverrides = None - ) -> Response[Configuration]: - """ - Update a Configuration. - - Args: - identifier: The identifier of the Grant to act upon. - config_id: The identifier of the Configuration to update. - data: The data to update the Configuration with. - overrides: The request overrides to use for the request. - - Returns: - The Configuration object. - """ - return super().update( - path=f"/v3/grants/{identifier}/scheduling/configurations/{config_id}", - request_body=request_body, - overrides=overrides, - response_type=Configuration, - ) - - def destroy( - self, - identifier: str, - config_id: str, - overrides: RequestOverrides = None - ) -> DeleteResponse: - """ - Delete a Configuration. - - Args: - identifier: The identifier of the Grant to act upon. - config_id: The identifier of the Configuration to delete. - overrides: The request overrides to use for the request. - """ - return super().destroy( - path=f"/v3/grants/{identifier}/scheduling/configurations/{config_id}", - overrides=overrides, - ) \ No newline at end of file + ListableApiResource, + FindableApiResource, + CreatableApiResource, + UpdatableApiResource, + DestroyableApiResource, +): + """ + Nylas Configuration API + + The Nylas configuration API allows you to create new configurations or manage existing ones, as well as getting + configurations details for a user. + + Nylas Scheduler stores Configuration objects in the Scheduler database and loads + them as Scheduling Pages in the Scheduler UI. + """ + + def list( + self, + identifier: str, + query_params: ListConfigurationsParams = None, + overrides: RequestOverrides = None, + ) -> ListResponse[Configuration]: + """ + Return all Configurations. + + Args: + identifier: The identifier of the Grant to act upon. + overrides: The request overrides to use for the request. + + Returns: + The list of Configurations. + """ + # import pdb; pdb.set_trace(); + res = super().list( + path=f"/v3/grants/{identifier}/scheduling/configurations", + overrides=overrides, + response_type=Configuration, + query_params=query_params, + ) + print("What's this", res) + return res + + def find( + self, identifier: str, config_id: str, overrides: RequestOverrides = None + ) -> Response[Configuration]: + """ + Return a Configuration. + + Args: + identifier: The identifier of the Grant to act upon. + config_id: The identifier of the Configuration to get. + overrides: The request overrides to use for the request. + + Returns: + The Configuration object. + """ + return super().find( + path=f"/v3/grants/{identifier}/scheduling/configurations/{config_id}", + overrides=overrides, + response_type=Configuration, + ) + + def create( + self, + identifier: str, + request_body: CreateConfigurationRequest, + overrides: RequestOverrides = None, + ) -> Response[Configuration]: + """ + Create a new Configuration. + + Args: + identifier: The identifier of the Grant to act upon. + data: The data to create the Configuration with. + overrides: The request overrides to use for the request. + + Returns: + The Configuration object. + """ + return super().create( + path=f"/v3/grants/{identifier}/scheduling/configurations", + request_body=request_body, + overrides=overrides, + response_type=Configuration, + ) + + def update( + self, + identifier: str, + config_id: str, + request_body: UpdateConfigurationRequest, + overrides: RequestOverrides = None, + ) -> Response[Configuration]: + """ + Update a Configuration. + + Args: + identifier: The identifier of the Grant to act upon. + config_id: The identifier of the Configuration to update. + data: The data to update the Configuration with. + overrides: The request overrides to use for the request. + + Returns: + The Configuration object. + """ + return super().update( + path=f"/v3/grants/{identifier}/scheduling/configurations/{config_id}", + request_body=request_body, + overrides=overrides, + response_type=Configuration, + ) + + def destroy( + self, identifier: str, config_id: str, overrides: RequestOverrides = None + ) -> DeleteResponse: + """ + Delete a Configuration. + + Args: + identifier: The identifier of the Grant to act upon. + config_id: The identifier of the Configuration to delete. + overrides: The request overrides to use for the request. + """ + return super().destroy( + path=f"/v3/grants/{identifier}/scheduling/configurations/{config_id}", + overrides=overrides, + ) diff --git a/nylas/resources/scheduler.py b/nylas/resources/scheduler.py index 11c0781..e337de4 100644 --- a/nylas/resources/scheduler.py +++ b/nylas/resources/scheduler.py @@ -1,11 +1,13 @@ -from nylas.resources.configurations import Configurations from nylas.resources.bookings import Bookings +from nylas.resources.configurations import Configurations from nylas.resources.sessions import Sessions + class Scheduler: """ Class representation of a Nylas Scheduler API. """ + def __init__(self, http_client): self.http_client = http_client @@ -18,7 +20,7 @@ def configurations(self) -> Configurations: The Configurations API. """ return Configurations(self.http_client) - + @property def bookings(self) -> Bookings: """ @@ -28,7 +30,7 @@ def bookings(self) -> Bookings: The Bookings API. """ return Bookings(self.http_client) - + @property def sessions(self) -> Sessions: """ @@ -38,4 +40,3 @@ def sessions(self) -> Sessions: The Sessions API. """ return Sessions(self.http_client) - diff --git a/nylas/resources/sessions.py b/nylas/resources/sessions.py index 2759303..556009a 100644 --- a/nylas/resources/sessions.py +++ b/nylas/resources/sessions.py @@ -1,61 +1,56 @@ from nylas.config import RequestOverrides -from nylas.handler.api_resources import ( - CreatableApiResource, - DestroyableApiResource, -) -from nylas.models.response import Response, DeleteResponse -from nylas.models.scheduler import Session, CreateSessionRequest - -class Sessions( - CreatableApiResource, - DestroyableApiResource -): - """ - Nylas Sessions API - - The Nylas Sessions API allows you to create new sessions or manage existing ones. - """ - - def create( - self, - request_body: CreateSessionRequest, - overrides: RequestOverrides = None, - ) -> Response[Session]: - """ - Create a Session. - - Args: - request_body: The request body to create the Session. - overrides: The request overrides to use for the request. +from nylas.handler.api_resources import CreatableApiResource, DestroyableApiResource +from nylas.models.response import DeleteResponse, Response +from nylas.models.scheduler import CreateSessionRequest, Session - Returns: - The Session. - """ - return super().create( - path=f"/v3/scheduling/sessions", - request_body=request_body, - response_type=Session, - overrides=overrides, - ) - - def destroy( - self, - session_id: str, - overrides: RequestOverrides = None, - ) -> DeleteResponse: +class Sessions(CreatableApiResource, DestroyableApiResource): """ - Destroy a Session. - - Args: - session_id: The identifier of the Session to destroy. - overrides: The request overrides to use for the request. + Nylas Sessions API - Returns: - None. + The Nylas Sessions API allows you to create new sessions or manage existing ones. """ - return super().destroy( - path=f"/v3/scheduling/sessions{session_id}", - overrides=overrides, - ) \ No newline at end of file + def create( + self, + request_body: CreateSessionRequest, + overrides: RequestOverrides = None, + ) -> Response[Session]: + """ + Create a Session. + + Args: + request_body: The request body to create the Session. + overrides: The request overrides to use for the request. + + Returns: + The Session. + """ + + return super().create( + path="/v3/scheduling/sessions", + request_body=request_body, + response_type=Session, + overrides=overrides, + ) + + def destroy( + self, + session_id: str, + overrides: RequestOverrides = None, + ) -> DeleteResponse: + """ + Destroy a Session. + + Args: + session_id: The identifier of the Session to destroy. + overrides: The request overrides to use for the request. + + Returns: + None. + """ + + return super().destroy( + path=f"/v3/scheduling/sessions/{session_id}", + overrides=overrides, + ) diff --git a/tests/resources/test_bookings.py b/tests/resources/test_bookings.py index e826cb0..15dc87e 100644 --- a/tests/resources/test_bookings.py +++ b/tests/resources/test_bookings.py @@ -32,7 +32,12 @@ def test_find_booking(self, http_client_response): bookings.find(booking_id="booking-123") http_client_response._execute.assert_called_once_with( - "GET", "/v3/scheduling/bookings/booking-123", query_params=None, overrides=None + "GET", + "/v3/scheduling/bookings/booking-123", + None, + None, + None, + overrides=None ) def test_create_booking(self, http_client_response): @@ -88,22 +93,24 @@ def test_reschedule_booking(self, http_client_response): http_client_response._execute.assert_called_once_with( "PATCH", "/v3/scheduling/bookings/booking-123", - query_params=None, - request_body=request_body, + None, + None, + request_body, overrides=None ) - def test_destroy_booking(self, http_client_response): - bookings = Bookings(http_client_response) + def test_destroy_booking(self, http_client_delete_response): + bookings = Bookings(http_client_delete_response) request_body = { "cancellation_reason": "I am no longer available at this time." } bookings.destroy(booking_id="booking-123", request_body=request_body) - http_client_response._execute.assert_called_once_with( + http_client_delete_response._execute.assert_called_once_with( "DELETE", "/v3/scheduling/bookings/booking-123", - request_body=request_body, - query_params=None, + None, + None, + request_body, overrides=None ) \ No newline at end of file diff --git a/tests/resources/test_configurations.py b/tests/resources/test_configurations.py index 85aeafa..8b2388f 100644 --- a/tests/resources/test_configurations.py +++ b/tests/resources/test_configurations.py @@ -112,24 +112,23 @@ def test_configuration_deserialization(self): assert configuration.participants[0].is_organizer == True assert configuration.participants[0].name == "Test" assert configuration.participants[0].availability.calendar_ids == ["primary"] - assert configuration.participants[0].availability.open_hours[0].days == [0, 1, 2, 3, 4, 5, 6] - assert configuration.participants[0].availability.open_hours[0].exdates == None - assert configuration.participants[0].availability.open_hours[0].timezone == "" + assert configuration.participants[0].availability.open_hours[0]["days"] == [0, 1, 2, 3, 4, 5, 6] + assert configuration.participants[0].availability.open_hours[0]["exdates"] == None + assert configuration.participants[0].availability.open_hours[0]["timezone"] == "" assert configuration.participants[0].booking.calendar_id == "primary" assert configuration.participants[0].timezone == "" assert configuration.requires_session_auth == False assert configuration.availability.duration_minutes == 30 assert configuration.availability.interval_minutes == 15 assert configuration.availability.round_to == 15 - assert configuration.availability.availability_rules.availability_method == "collective" - assert configuration.availability.availability_rules.buffer.before == 60 - assert configuration.availability.availability_rules.buffer.after == 0 - assert configuration.availability.availability_rules.default_open_hours[0].days == [0, 1, 2, 5, 6] - assert configuration.availability.availability_rules.default_open_hours[0].exdates == None - assert configuration.availability.availability_rules.default_open_hours[0].timezone == "" - assert configuration.availability.availability_rules.default_open_hours[0].start == "09:00" - assert configuration.availability.availability_rules.default_open_hours[0].end == "18:00" - assert configuration.availability.availability_rules.round_robin_group_id == "" + assert configuration.availability.availability_rules["availability_method"] == "collective" + assert configuration.availability.availability_rules["buffer"]["before"] == 60 + assert configuration.availability.availability_rules["buffer"]["after"] == 0 + assert configuration.availability.availability_rules["default_open_hours"][0]["days"] == [0, 1, 2, 5, 6] + assert configuration.availability.availability_rules["default_open_hours"][0]["exdates"] == None + assert configuration.availability.availability_rules["default_open_hours"][0]["timezone"] == "" + assert configuration.availability.availability_rules["default_open_hours"][0]["start"] == "09:00" + assert configuration.availability.availability_rules["default_open_hours"][0]["end"] == "18:00" assert configuration.event_booking.title == "Updated Title" assert configuration.event_booking.timezone == "utc" assert configuration.event_booking.description == "" @@ -139,7 +138,7 @@ def test_configuration_deserialization(self): assert configuration.scheduler.available_days_in_future == 7 assert configuration.scheduler.min_cancellation_notice == 60 assert configuration.scheduler.min_booking_notice == 120 - assert configuration.scheduler.appearance.submit_button_label == "submit" + assert configuration.appearance["submit_button_label"] == "submit" def test_list_configurations(self, http_client_list_response): configurations = Configurations(http_client_list_response) @@ -221,11 +220,11 @@ def test_update_configuration(self, http_client_response): overrides=None, ) - def test_delete_configuration(self, http_client_response): - configurations = Configurations(http_client_response) + def test_destroy_configuration(self, http_client_delete_response): + configurations = Configurations(http_client_delete_response) configurations.destroy(identifier="grant-123", config_id="config-123") - http_client_response._execute.assert_called_once_with( + http_client_delete_response._execute.assert_called_once_with( "DELETE", "/v3/grants/grant-123/scheduling/configurations/config-123", None, diff --git a/tests/resources/test_sessions.py b/tests/resources/test_sessions.py index 07c8268..5d4590d 100644 --- a/tests/resources/test_sessions.py +++ b/tests/resources/test_sessions.py @@ -10,7 +10,7 @@ def test_session_deserialization(self): session = Session.from_dict(session_json) - assert session.id == "session-id" + assert session.session_id == "session-id" def test_create_session(self, http_client_response): sessions = Sessions(http_client_response) @@ -30,12 +30,12 @@ def test_create_session(self, http_client_response): overrides=None, ) - def test_destroy_session(self, http_client_response): - sessions = Sessions(http_client_response) + def test_destroy_session(self, http_client_delete_response): + sessions = Sessions(http_client_delete_response) sessions.destroy(session_id="session-123") - http_client_response._execute.assert_called_once_with( + http_client_delete_response._execute.assert_called_once_with( "DELETE", "/v3/scheduling/sessions/session-123", None, From cbb57742647432ba8b3ef428d74b00cf1854dc86 Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Tue, 5 Nov 2024 10:55:51 +0100 Subject: [PATCH 12/13] Fix pylint --- nylas/models/scheduler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nylas/models/scheduler.py b/nylas/models/scheduler.py index c0ee850..7b20b56 100644 --- a/nylas/models/scheduler.py +++ b/nylas/models/scheduler.py @@ -313,7 +313,8 @@ class CreateSessionRequest(TypedDict): Attributes: configuration_id: The ID of the Configuration object whose settings are used for calculating availability. - If you're using session authentication (requires_session_auth is set to true), configuration_id is not required. + If you're using session authentication (requires_session_auth is set to true), + configuration_id is not required. slug: The slug of the Configuration object whose settings are used for calculating availability. If you're using session authentication (requires_session_auth is set to true) or using configurationId, slug is not required. From 4bc957031f863fd8a047aad44910a6c85160d8d4 Mon Sep 17 00:00:00 2001 From: Subash Pradhan Date: Tue, 12 Nov 2024 10:05:14 +0100 Subject: [PATCH 13/13] Fix Availability model to include Round Robin Group ID --- nylas/models/availability.py | 4 ++-- nylas/resources/bookings.py | 3 ++- tests/resources/test_calendars.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/nylas/models/availability.py b/nylas/models/availability.py index 005977d..68497f3 100644 --- a/nylas/models/availability.py +++ b/nylas/models/availability.py @@ -87,7 +87,7 @@ class AvailabilityRules(TypedDict): default_open_hours: A default set of open hours to apply to all participants. You can overwrite these open hours for individual participants by specifying open_hours on the participant object. - round_robin_event_id: The ID on events that Nylas considers when calculating the order of + round_robin_group_id: The ID on events that Nylas considers when calculating the order of round-robin participants. This is used for both max-fairness and max-availability methods. """ @@ -95,7 +95,7 @@ class AvailabilityRules(TypedDict): availability_method: NotRequired[AvailabilityMethod] buffer: NotRequired[MeetingBuffer] default_open_hours: NotRequired[List[OpenHours]] - round_robin_event_id: NotRequired[str] + round_robin_group_id: NotRequired[str] class AvailabilityParticipant(TypedDict): diff --git a/nylas/resources/bookings.py b/nylas/resources/bookings.py index 5fac015..0fa3cf5 100644 --- a/nylas/resources/bookings.py +++ b/nylas/resources/bookings.py @@ -16,6 +16,7 @@ CreateBookingRequest, DeleteBookingRequest, DestroyBookingQueryParams, + RescheduleBookingRequest, FindBookingQueryParams, RescheduleBookingQueryParams, ) @@ -122,7 +123,7 @@ def confirm( def reschedule( self, booking_id: str, - request_body: CreateBookingRequest, + request_body: RescheduleBookingRequest, query_params: RescheduleBookingQueryParams = None, overrides: RequestOverrides = None, ) -> Response[Booking]: diff --git a/tests/resources/test_calendars.py b/tests/resources/test_calendars.py index 2f0aae9..7fe6b1f 100644 --- a/tests/resources/test_calendars.py +++ b/tests/resources/test_calendars.py @@ -167,7 +167,7 @@ def test_get_availability(self, http_client_response): "exdates": ["2021-03-01"], } ], - "round_robin_event_id": "event-123", + "round_robin_group_id": "event-123", }, }