diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..e0f15db2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "automatic" +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a16d767c..553151ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Nylas Java SDK Changelog +### Unreleased +* Added support for Notetaker APIs +* Added support for Notetaker via the calendar and event APIs + ### [2.7.0] - Release 2025-03-03 * Added support for listing import events via `events.listImportEvents()` * Added sandbox to the Environment Enum diff --git a/examples/.env.example b/examples/.env.example new file mode 100644 index 00000000..2fb9dc1a --- /dev/null +++ b/examples/.env.example @@ -0,0 +1,11 @@ +# Nylas API Key - Required +# Get it from your Nylas Dashboard: https://dashboard.nylas.com/ +NYLAS_API_KEY=your_api_key_here + +# Meeting Link - Required for Notetaker examples +# This should be a link to a Zoom, Google Meet, or Microsoft Teams meeting +MEETING_LINK=your_meeting_link_here + +# Nylas API URI - Optional (defaults to https://api.us.nylas.com) +# Only change this if instructed by Nylas support +NYLAS_API_URI=https://api.us.nylas.com \ No newline at end of file diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 00000000..4598a2a5 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,33 @@ +# Compiled class files +*.class + +# Build output +/build/ + +# Gradle files +.gradle/ + +# IntelliJ IDEA files +.idea/ +*.iml +*.iws +*.ipr +out/ + +# Eclipse files +.classpath +.project +.settings/ +bin/ + +# VS Code files +.vscode/ + +# Environment variables +.env + +# Mac files +.DS_Store + +# Logs +*.log \ No newline at end of file diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 00000000..142aeda1 --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,23 @@ +.PHONY: help list java kotlin + +# Default target +help: + @echo "Nylas Java/Kotlin SDK Examples" + @echo "" + @echo "Available targets:" + @echo " help - Show this help message" + @echo " list - List available examples" + @echo " java - Run the Java Notetaker example" + @echo " kotlin - Run the Kotlin Notetaker example" + +# List available examples +list: + @cd .. && ./gradlew :examples:listExamples + +# Run the Java example +java: + @cd .. && ./gradlew :examples:run -PmainClass=com.nylas.examples.NotetakerExample + +# Run the Kotlin example +kotlin: + @cd .. && ./gradlew :examples:run -PmainClass=com.nylas.examples.KotlinNotetakerExampleKt \ No newline at end of file diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..98320822 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,94 @@ +# Nylas Java/Kotlin SDK Examples + +Simple examples demonstrating how to use the Nylas Java/Kotlin SDK. + +## Available Examples + +### Notetaker Example + +The `NotetakerExample` demonstrates how to use the Nylas Java/Kotlin SDK to interact with the Notetakers API: + +- Invite a Notetaker to a meeting +- List all Notetakers +- Get media from a Notetaker (if available) +- Leave a Notetaker session + +## Setup + +### 1. Environment Setup + +Copy the `.env.example` file to `.env` and fill in your credentials: + +```bash +cp .env.example .env +``` + +Edit the `.env` file with your details: +``` +# Get your API key from the Nylas Dashboard +NYLAS_API_KEY=your_api_key_here + +# Add your meeting link (Zoom, Google Meet, or Microsoft Teams) +MEETING_LINK=your_meeting_link_here +``` + +### 2. Running the Examples + +#### Option 1: Using Gradle + +Run Java example: +```bash +./gradlew :examples:run -PmainClass=com.nylas.examples.NotetakerExample +``` + +Run Kotlin example: +```bash +./gradlew :examples:run -PmainClass=com.nylas.examples.KotlinNotetakerExampleKt +``` + +#### Option 2: Using the Makefile + +List available examples: +```bash +make list +``` + +Run the Java example: +```bash +make java +``` + +Run the Kotlin example: +```bash +make kotlin-way +``` + +#### Option 3: From an IDE + +1. Open the project in your IDE (IntelliJ IDEA, Eclipse, etc.) +2. Set the required environment variables in your run configuration +3. Run the main method in either: + - `NotetakerExample.java` (Java) + - `KotlinNotetakerExample.kt` (Kotlin) + +## Project Structure + +``` +examples/ +├── .env.example # Template for environment variables +├── build.gradle.kts # Gradle build file for examples +├── Makefile # Helpful commands for running examples +├── README.md # This file +└── src/ + └── main/ + ├── java/ # Java examples + │ └── com/nylas/examples/ + │ └── NotetakerExample.java + └── kotlin/ # Kotlin examples + └── com/nylas/examples/ + └── KotlinNotetakerExample.kt +``` + +## Additional Information + +For more information about the Nylas API, refer to the [Nylas API documentation](https://developer.nylas.com/). \ No newline at end of file diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts new file mode 100644 index 00000000..c56eb75f --- /dev/null +++ b/examples/build.gradle.kts @@ -0,0 +1,70 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + id("java") + id("application") + id("org.jetbrains.kotlin.jvm") version "1.8.21" +} + +group = "com.nylas.examples" +version = "1.0-SNAPSHOT" + +repositories { + mavenCentral() + mavenLocal() // For local Nylas SDK development +} + +dependencies { + // Add the Nylas SDK dependency + implementation(project(":")) // References the main Nylas SDK project + + // Core dependencies + implementation("org.json:json:20230227") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + + // Test dependencies + testImplementation(platform("org.junit:junit-bom:5.9.1")) + testImplementation("org.junit.jupiter:junit-jupiter") +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType { + kotlinOptions { + jvmTarget = "1.8" + } +} + +application { + // The mainClass will be overridden by the -PmainClass command-line parameter + mainClass.set(findProperty("mainClass") as String? ?: "com.nylas.examples.NotetakerExample") +} + +tasks.test { + useJUnitPlatform() +} + +// Task to list available examples +tasks.register("listExamples") { + doLast { + println("Available examples:") + println("- Java: com.nylas.examples.NotetakerExample") + println("- Kotlin: com.nylas.examples.KotlinNotetakerExampleKt") + println("\nRun an example with: ./gradlew :examples:run -PmainClass=") + } +} + +// Configure source sets for Java and Kotlin +sourceSets { + main { + java { + srcDir("src/main/java") + } + kotlin { + srcDir("src/main/kotlin") + } + } +} \ No newline at end of file diff --git a/examples/src/main/java/com/nylas/examples/NotetakerExample.java b/examples/src/main/java/com/nylas/examples/NotetakerExample.java new file mode 100644 index 00000000..f64c9e38 --- /dev/null +++ b/examples/src/main/java/com/nylas/examples/NotetakerExample.java @@ -0,0 +1,260 @@ +package com.nylas.examples; + +import com.nylas.NylasClient; +import com.nylas.models.CreateNotetakerRequest; +import com.nylas.models.LeaveNotetakerResponse; +import com.nylas.models.ListResponse; +import com.nylas.models.Notetaker; +import com.nylas.models.NotetakerMediaResponse; +import com.nylas.models.Response; +import com.nylas.models.NylasApiError; +import com.nylas.models.NylasSdkTimeoutError; +import okhttp3.OkHttpClient; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * This example demonstrates how to use the Nylas Java SDK to work with Notetakers. + * A Notetaker is an AI assistant that can join your meetings to take notes, record, + * and transcribe the meeting content. + * + * This example shows how to: + * 1. Create and configure a Nylas client + * 2. Invite a Notetaker to join a meeting + * 3. List all your Notetakers + * 4. Download media (recordings/transcripts) from a Notetaker + * 5. Leave a Notetaker session + * + * Prerequisites: + * 1. A Nylas API key (sign up at https://www.nylas.com if you don't have one) + * 2. A meeting link (e.g., Google Meet, Zoom, etc.) + * + * To run this example: + * 1. Copy examples/.env.example to examples/.env and configure your settings + * 2. Run using Gradle: + * ./gradlew :examples:run -PmainClass=com.nylas.examples.NotetakerExample + */ +public class NotetakerExample { + public static void main(String[] args) { + try { + // Load configuration from environment variables or .env file + Map config = loadConfig(); + + // Initialize the Nylas client with your API key + NylasClient nylas = new NylasClient( + config.get("NYLAS_API_KEY"), + new OkHttpClient.Builder(), + config.getOrDefault("NYLAS_API_URI", "https://api.us.nylas.com") + ); + + // Run the example workflow + runNotetakerExample(nylas, config); + + // Exit successfully + System.exit(0); + + } catch (NylasApiError e) { + System.out.println("\n❌ Nylas API Error: " + e.getMessage()); + System.out.println(" Status code: " + e.getStatusCode()); + System.out.println(" Request ID: " + e.getRequestId()); + System.exit(1); + } catch (IllegalArgumentException e) { + System.out.println("\n❌ Configuration Error: " + e.getMessage()); + System.exit(1); + } catch (Exception e) { + System.out.println("\n❌ Unexpected Error: " + e.getMessage()); + e.printStackTrace(); + System.exit(1); + } + } + + /** + * Runs through the complete Notetaker example workflow + */ + private static void runNotetakerExample(NylasClient nylas, Map config) throws NylasApiError, NylasSdkTimeoutError { + System.out.println("\n🚀 Starting Nylas Notetaker Example"); + + // Step 1: Invite a Notetaker to a meeting + Response notetaker = inviteNotetaker(nylas, config); + System.out.println("\n✅ Successfully invited Notetaker"); + + // Step 2: List all Notetakers + listNotetakers(nylas); + System.out.println("\n✅ Successfully listed all Notetakers"); + + // Step 3: Get media from the Notetaker (if available) + if (notetaker.getData().getState() == Notetaker.NotetakerState.MEDIA_AVAILABLE) { + getNotetakerMedia(nylas, notetaker.getData().getId()); + System.out.println("\n✅ Successfully retrieved Notetaker media"); + } else { + System.out.println("\nℹ️ No media available yet for this Notetaker"); + } + + // Step 4: Leave the Notetaker session + leaveNotetaker(nylas, notetaker.getData().getId()); + System.out.println("\n✅ Successfully left Notetaker session"); + } + + /** + * Loads configuration from environment variables and .env file + * @throws IllegalArgumentException if required configuration is missing + */ + private static Map loadConfig() { + Map config = new HashMap<>(); + + // Try loading from environment variables first + System.getenv().entrySet().stream() + .filter(entry -> entry.getKey().startsWith("NYLAS_") || entry.getKey().equals("MEETING_LINK")) + .forEach(entry -> config.put(entry.getKey(), entry.getValue())); + + // Then try loading from .env file if needed + List envPaths = Arrays.asList("examples/.env", ".env"); + for (String path : envPaths) { + File envFile = new File(path); + if (envFile.exists()) { + System.out.println("📝 Loading configuration from " + envFile.getAbsolutePath()); + try { + Files.lines(envFile.toPath()) + .filter(line -> !line.trim().isEmpty() && !line.startsWith("#")) + .forEach(line -> { + String[] parts = line.split("=", 2); + if (parts.length == 2) { + String key = parts[0].trim(); + String value = parts[1].trim(); + if (!config.containsKey(key)) { + config.put(key, value); + } + } + }); + } catch (IOException e) { + System.out.println("Warning: Failed to load .env file: " + e.getMessage()); + } + } + } + + // Validate required configuration + List requiredKeys = Arrays.asList("NYLAS_API_KEY", "MEETING_LINK"); + List missingKeys = requiredKeys.stream() + .filter(key -> !config.containsKey(key)) + .collect(Collectors.toList()); + + if (!missingKeys.isEmpty()) { + throw new IllegalArgumentException( + "Missing required configuration: " + String.join(", ", missingKeys) + "\n" + + "Please set these in examples/.env or as environment variables." + ); + } + + return config; + } + + /** + * Invites a Notetaker to join a meeting + */ + private static Response inviteNotetaker(NylasClient nylas, Map config) throws NylasApiError, NylasSdkTimeoutError { + System.out.println("\n📋 Inviting Notetaker to Meeting"); + + String meetingLink = getOrThrow(config, "MEETING_LINK"); + + // Configure the Notetaker's meeting settings + CreateNotetakerRequest.MeetingSettings meetingSettings = new CreateNotetakerRequest.MeetingSettings( + true, // videoRecording + true, // audioRecording + true // transcription + ); + + // Create and configure the Notetaker + CreateNotetakerRequest request = new CreateNotetakerRequest( + meetingLink, + null, // joinTime + "Nylas Notetaker Example", + meetingSettings + ); + + // Send the invitation + Response notetaker = nylas.notetakers().create(request); + + System.out.println("Notetaker Details:"); + System.out.println(" • ID: " + notetaker.getData().getId()); + System.out.println(" • Name: " + notetaker.getData().getName()); + System.out.println(" • State: " + notetaker.getData().getState()); + System.out.println(" • Meeting Link: " + meetingLink); + + return notetaker; + } + + /** + * Lists all Notetakers in your account + */ + private static void listNotetakers(NylasClient nylas) throws NylasApiError, NylasSdkTimeoutError { + System.out.println("\n📋 Listing All Notetakers"); + + ListResponse notetakers = nylas.notetakers().list(); + + System.out.println("Found " + notetakers.getData().size() + " Notetakers:"); + for (Notetaker notetaker : notetakers.getData()) { + System.out.println(" • " + notetaker.getName()); + System.out.println(" - ID: " + notetaker.getId()); + System.out.println(" - State: " + notetaker.getState()); + } + } + + /** + * Downloads available media (recordings/transcripts) from a Notetaker + */ + private static void getNotetakerMedia(NylasClient nylas, String notetakerId) throws NylasApiError, NylasSdkTimeoutError { + System.out.println("\n📋 Getting Notetaker Media"); + + Response media = nylas.notetakers().downloadMedia(notetakerId); + + if (media.getData().getRecording() != null) { + System.out.println("Recording:"); + System.out.println(" • URL: " + media.getData().getRecording().getUrl()); + System.out.println(" • Size: " + media.getData().getRecording().getSize() + " MB"); + } + + if (media.getData().getTranscript() != null) { + System.out.println("Transcript:"); + System.out.println(" • URL: " + media.getData().getTranscript().getUrl()); + System.out.println(" • Size: " + media.getData().getTranscript().getSize() + " MB"); + } + } + + /** + * Leaves a Notetaker session + */ + private static void leaveNotetaker(NylasClient nylas, String notetakerId) throws NylasApiError, NylasSdkTimeoutError { + System.out.println("\n📋 Leaving Notetaker Session"); + + Response response = nylas.notetakers().leave(notetakerId); + System.out.println("Left Notetaker:"); + System.out.println(" • ID: " + response.getData().getId()); + System.out.println(" • Message: " + response.getData().getMessage()); + } + + /** + * Helper method to get a required config value or throw an exception + */ + private static String getOrThrow(Map config, String key) { + String value = config.get(key); + if (value == null) { + throw new IllegalArgumentException(key + " is required but not configured"); + } + return value; + } + + /** + * Helper method to get a config value with a default + */ + private static String getOrDefault(Map config, String key, String defaultValue) { + String value = config.get(key); + return value != null ? value : defaultValue; + } +} \ No newline at end of file diff --git a/examples/src/main/kotlin/com/nylas/examples/KotlinNotetakerExample.kt b/examples/src/main/kotlin/com/nylas/examples/KotlinNotetakerExample.kt new file mode 100644 index 00000000..2ad320bd --- /dev/null +++ b/examples/src/main/kotlin/com/nylas/examples/KotlinNotetakerExample.kt @@ -0,0 +1,228 @@ +package com.nylas.examples + +import com.nylas.NylasClient +import com.nylas.models.* +import java.io.File + +/** + * This example demonstrates how to use the Nylas Kotlin SDK to work with Notetakers. + * A Notetaker is an AI assistant that can join your meetings to take notes, record, + * and transcribe the meeting content. + * + * This example shows how to: + * 1. Create and configure a Nylas client + * 2. Invite a Notetaker to join a meeting + * 3. List all your Notetakers + * 4. Download media (recordings/transcripts) from a Notetaker + * 5. Leave a Notetaker session + * + * Prerequisites: + * 1. A Nylas API key (sign up at https://www.nylas.com if you don't have one) + * 2. A meeting link (e.g., Google Meet, Zoom, etc.) + * + * To run this example: + * 1. Copy examples/.env.example to examples/.env and configure your settings + * 2. Run using Gradle: + * ./gradlew :examples:run -PmainClass=com.nylas.examples.KotlinNotetakerExampleKt + * Or use the Makefile: make kotlin-way + */ + +fun main() { + try { + // Load configuration from environment variables or .env file + val config = loadConfig() + + // Initialize the Nylas client with your API key + val nylas = NylasClient( + apiKey = config.getOrThrow("NYLAS_API_KEY"), + apiUri = config.getOrDefault("NYLAS_API_URI", "https://api.us.nylas.com") + ) + + // Example workflow + runNotetakerExample(nylas, config) + + } catch (e: NylasApiError) { + println("❌ Nylas API Error: ${e.message}") + println(" Status code: ${e.statusCode}") + println(" Request ID: ${e.requestId}") + System.exit(1) + } catch (e: IllegalArgumentException) { + println("❌ Configuration Error: ${e.message}") + System.exit(1) + } catch (e: Exception) { + println("❌ Unexpected Error: ${e.message}") + e.printStackTrace() + System.exit(1) + } +} + +/** + * Runs through the complete Notetaker example workflow + */ +private fun runNotetakerExample(nylas: NylasClient, config: Map) { + println("\n🚀 Starting Nylas Notetaker Example") + + // Step 1: Invite a Notetaker to a meeting + val notetaker = inviteNotetaker(nylas, config) + println("\n✅ Successfully invited Notetaker") + + // Step 2: List all Notetakers + listNotetakers(nylas) + println("\n✅ Successfully listed all Notetakers") + + // Step 3: Get media from the Notetaker (if available) + if (notetaker.data.state == Notetaker.NotetakerState.MEDIA_AVAILABLE) { + getNotetakerMedia(nylas, notetaker.data.id) + println("\n✅ Successfully retrieved Notetaker media") + } else { + println("\nℹ️ No media available yet for this Notetaker") + } + + // Step 4: Leave the Notetaker session + leaveNotetaker(nylas, notetaker.data.id) + println("\n✅ Successfully left Notetaker session") +} + +/** + * Loads configuration from environment variables and .env file + * @throws IllegalArgumentException if required configuration is missing + */ +private fun loadConfig(): Map { + val config = mutableMapOf() + + // Try loading from environment variables first + System.getenv() + .filter { (key, _) -> key.startsWith("NYLAS_") || key == "MEETING_LINK" } + .forEach { (key, value) -> config[key] = value } + + // Then try loading from .env file if needed + listOf("examples/.env", ".env").forEach { path -> + val envFile = File(path) + if (envFile.exists()) { + println("📝 Loading configuration from ${envFile.absolutePath}") + envFile.useLines { lines -> + lines + .filter { it.isNotBlank() && !it.startsWith("#") } + .forEach { line -> + val (key, value) = line.split("=", limit = 2) + .map { it.trim() } + if (!config.containsKey(key)) { + config[key] = value + } + } + } + } + } + + // Validate required configuration + val requiredKeys = listOf("NYLAS_API_KEY", "MEETING_LINK") + val missingKeys = requiredKeys.filter { !config.containsKey(it) } + if (missingKeys.isNotEmpty()) { + throw IllegalArgumentException( + "Missing required configuration: ${missingKeys.joinToString(", ")}\n" + + "Please set these in examples/.env or as environment variables." + ) + } + + return config +} + +/** + * Invites a Notetaker to join a meeting + * @param nylas The Nylas client + * @param config Configuration containing the meeting link + * @return Response containing the created Notetaker + */ +private fun inviteNotetaker(nylas: NylasClient, config: Map): Response { + println("\n📋 Inviting Notetaker to Meeting") + + val meetingLink = config.getOrThrow("MEETING_LINK") + + // Configure the Notetaker's meeting settings + val meetingSettings = CreateNotetakerRequest.MeetingSettings( + videoRecording = true, + audioRecording = true, + transcription = true + ) + + // Create and configure the Notetaker + val request = CreateNotetakerRequest( + meetingLink = meetingLink, + name = "Nylas Notetaker Example", + meetingSettings = meetingSettings + ) + + // Send the invitation + val notetaker = nylas.notetakers().create(request) + + println(""" + |Notetaker Details: + | • ID: ${notetaker.data.id} + | • Name: ${notetaker.data.name} + | • State: ${notetaker.data.state} + | • Meeting Link: $meetingLink + """.trimMargin()) + + return notetaker +} + +/** + * Lists all Notetakers in your account + */ +private fun listNotetakers(nylas: NylasClient) { + println("\n📋 Listing All Notetakers") + + val notetakers = nylas.notetakers().list() + + println("Found ${notetakers.data.size} Notetakers:") + notetakers.data.forEach { notetaker -> + println(""" + | • ${notetaker.name} + | - ID: ${notetaker.id} + | - State: ${notetaker.state} + """.trimMargin()) + } +} + +/** + * Downloads available media (recordings/transcripts) from a Notetaker + */ +private fun getNotetakerMedia(nylas: NylasClient, notetakerId: String) { + println("\n📋 Getting Notetaker Media") + + val media = nylas.notetakers().downloadMedia(notetakerId) + + media.data.recording?.let { recording -> + println(""" + |Recording: + | • URL: ${recording.url} + | • Size: ${recording.size} MB + """.trimMargin()) + } + + media.data.transcript?.let { transcript -> + println(""" + |Transcript: + | • URL: ${transcript.url} + | • Size: ${transcript.size} MB + """.trimMargin()) + } +} + +/** + * Leaves a Notetaker session + */ +private fun leaveNotetaker(nylas: NylasClient, notetakerId: String) { + println("\n📋 Leaving Notetaker Session") + + val response = nylas.notetakers().leave(notetakerId) + println(""" + |Left Notetaker: + | • ID: ${response.data.id} + | • Message: ${response.data.message} + """.trimMargin()) +} + +// Extension function to safely get a required config value +private fun Map.getOrThrow(key: String): String = + this[key] ?: throw IllegalArgumentException("$key is required but not configured") \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 1b5578f0..5102999f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,3 +8,6 @@ */ rootProject.name = "nylas" + +// Include the examples subproject +include("examples") diff --git a/src/main/kotlin/com/nylas/NylasClient.kt b/src/main/kotlin/com/nylas/NylasClient.kt index ce770e9e..786ffa4a 100644 --- a/src/main/kotlin/com/nylas/NylasClient.kt +++ b/src/main/kotlin/com/nylas/NylasClient.kt @@ -155,7 +155,13 @@ open class NylasClient( * Access the Scheduler API * @return The Scheduler API */ - fun scheduler(): Scheduler = Scheduler(this) + open fun scheduler(): Scheduler = Scheduler(this) + + /** + * Access the Notetakers API + * @return The Notetakers API + */ + open fun notetakers(): Notetakers = Notetakers(this) /** * Get a URL builder instance for the Nylas API. diff --git a/src/main/kotlin/com/nylas/models/Calendar.kt b/src/main/kotlin/com/nylas/models/Calendar.kt index 9e00cc5f..a72784b1 100644 --- a/src/main/kotlin/com/nylas/models/Calendar.kt +++ b/src/main/kotlin/com/nylas/models/Calendar.kt @@ -74,6 +74,11 @@ data class Calendar( */ @Json(name = "metadata") val metadata: Map? = null, + /** + * Notetaker meeting bot settings for this calendar. + */ + @Json(name = "notetaker") + val notetaker: CalendarNotetaker? = null, ) { /** * Get the type of object. diff --git a/src/main/kotlin/com/nylas/models/CalendarNotetaker.kt b/src/main/kotlin/com/nylas/models/CalendarNotetaker.kt new file mode 100644 index 00000000..6cb7d992 --- /dev/null +++ b/src/main/kotlin/com/nylas/models/CalendarNotetaker.kt @@ -0,0 +1,103 @@ +package com.nylas.models + +import com.squareup.moshi.Json + +/** + * Class representation of Notetaker meeting bot settings for a calendar. + */ +data class CalendarNotetaker( + /** + * The display name for the Notetaker bot. + */ + @Json(name = "name") + val name: String? = "Nylas Notetaker", + + /** + * Notetaker Meeting Settings + */ + @Json(name = "meeting_settings") + val meetingSettings: MeetingSettings? = null, + + /** + * Rules for when the Notetaker should join a meeting. + */ + @Json(name = "rules") + val rules: Rules? = null, +) { + /** + * Data class for Notetaker Meeting Settings + */ + data class MeetingSettings( + /** + * When true, Notetaker records the meeting's video. + */ + @Json(name = "video_recording") + val videoRecording: Boolean? = true, + + /** + * When true, Notetaker records the meeting's audio. + */ + @Json(name = "audio_recording") + val audioRecording: Boolean? = true, + + /** + * When true, Notetaker transcribes the meeting's audio. + */ + @Json(name = "transcription") + val transcription: Boolean? = true, + ) + + /** + * Data class for Notetaker event selection rules + */ + data class Rules( + /** + * Types of events to include for notetaking. + */ + @Json(name = "event_selection") + val eventSelection: List? = null, + + /** + * Filters to apply based on the number of participants. + */ + @Json(name = "participant_filter") + val participantFilter: ParticipantFilter? = null, + ) + + /** + * Event selection types for Notetaker. + */ + enum class EventSelectionType { + @Json(name = "internal") + INTERNAL, + + @Json(name = "external") + EXTERNAL, + + @Json(name = "own_events") + OWN_EVENTS, + + @Json(name = "participant_only") + PARTICIPANT_ONLY, + + @Json(name = "all") + ALL, + } + + /** + * Participant filters for Notetaker. + */ + data class ParticipantFilter( + /** + * Only have meeting bot join meetings with greater than or equal to this number of participants. + */ + @Json(name = "participants_gte") + val participantsGte: Int? = null, + + /** + * Only have meeting bot join meetings with less than or equal to this number of participants. + */ + @Json(name = "participants_lte") + val participantsLte: Int? = null, + ) +} diff --git a/src/main/kotlin/com/nylas/models/CreateCalendarRequest.kt b/src/main/kotlin/com/nylas/models/CreateCalendarRequest.kt index 7a81d7c3..9044e086 100644 --- a/src/main/kotlin/com/nylas/models/CreateCalendarRequest.kt +++ b/src/main/kotlin/com/nylas/models/CreateCalendarRequest.kt @@ -32,6 +32,11 @@ data class CreateCalendarRequest( */ @Json(name = "metadata") val metadata: Map? = null, + /** + * Notetaker meeting bot settings for this calendar. + */ + @Json(name = "notetaker") + val notetaker: CalendarNotetaker? = null, ) { /** * A builder for creating a [CreateCalendarRequest]. @@ -45,6 +50,7 @@ data class CreateCalendarRequest( private var location: String? = null private var timezone: String? = null private var metadata: Map? = null + private var notetaker: CalendarNotetaker? = null /** * Set the description of the calendar. @@ -75,10 +81,17 @@ data class CreateCalendarRequest( */ fun metadata(metadata: Map) = apply { this.metadata = metadata } + /** + * Set Notetaker meeting bot settings for this calendar. + * @param notetaker Notetaker meeting bot settings. + * @return The builder. + */ + fun notetaker(notetaker: CalendarNotetaker) = apply { this.notetaker = notetaker } + /** * Build the [CreateCalendarRequest]. * @return A [CreateCalendarRequest] with the provided values. */ - fun build() = CreateCalendarRequest(name, description, location, timezone, metadata) + fun build() = CreateCalendarRequest(name, description, location, timezone, metadata, notetaker) } } diff --git a/src/main/kotlin/com/nylas/models/CreateEventRequest.kt b/src/main/kotlin/com/nylas/models/CreateEventRequest.kt index 30e248b9..56f90664 100644 --- a/src/main/kotlin/com/nylas/models/CreateEventRequest.kt +++ b/src/main/kotlin/com/nylas/models/CreateEventRequest.kt @@ -89,6 +89,11 @@ data class CreateEventRequest( */ @Json(name = "hide_participant") val hideParticipant: Boolean? = null, + /** + * Notetaker meeting bot settings for this event. + */ + @Json(name = "notetaker") + val notetaker: EventNotetakerRequest? = null, ) { /** * This sealed class represents the different types of event time configurations. @@ -431,6 +436,7 @@ data class CreateEventRequest( private var visibility: EventVisibility? = null private var capacity: Int? = null private var hideParticipant: Boolean? = null + private var notetaker: EventNotetakerRequest? = null /** * Set the event title. @@ -538,6 +544,13 @@ data class CreateEventRequest( */ fun hideParticipant(hideParticipant: Boolean) = apply { this.hideParticipant = hideParticipant } + /** + * Set the notetaker meeting bot settings for the event. + * @param notetaker The notetaker meeting bot settings for the event. + * @return The builder. + */ + fun notetaker(notetaker: EventNotetakerRequest) = apply { this.notetaker = notetaker } + /** * Builds the [CreateEventRequest] object. * @return [CreateEventRequest] object. @@ -559,6 +572,7 @@ data class CreateEventRequest( visibility, capacity, hideParticipant, + notetaker, ) } } diff --git a/src/main/kotlin/com/nylas/models/CreateNotetakerRequest.kt b/src/main/kotlin/com/nylas/models/CreateNotetakerRequest.kt new file mode 100644 index 00000000..a5da1852 --- /dev/null +++ b/src/main/kotlin/com/nylas/models/CreateNotetakerRequest.kt @@ -0,0 +1,138 @@ +package com.nylas.models + +import com.squareup.moshi.Json + +/** + * Class representation of the Nylas Notetaker creation request. + */ +data class CreateNotetakerRequest( + /** + * A meeting invitation link that Notetaker uses to join the meeting. + */ + @Json(name = "meeting_link") + val meetingLink: String, + + /** + * When Notetaker should join the meeting, in Unix timestamp format. + */ + @Json(name = "join_time") + val joinTime: Long? = null, + + /** + * The display name for the Notetaker bot. + */ + @Json(name = "name") + val name: String? = "Nylas Notetaker", + + /** + * Notetaker Meeting Settings + */ + @Json(name = "meeting_settings") + val meetingSettings: MeetingSettings? = null, +) { + /** + * Data class for Notetaker Meeting Settings + */ + data class MeetingSettings( + /** + * When true, Notetaker records the meeting's video. + */ + @Json(name = "video_recording") + val videoRecording: Boolean? = true, + + /** + * When true, Notetaker records the meeting's audio. + */ + @Json(name = "audio_recording") + val audioRecording: Boolean? = true, + + /** + * When true, Notetaker transcribes the meeting's audio. + */ + @Json(name = "transcription") + val transcription: Boolean? = true, + ) { + /** + * Builder for [MeetingSettings]. + */ + class Builder { + private var videoRecording: Boolean? = true + private var audioRecording: Boolean? = true + private var transcription: Boolean? = true + + /** + * Set video recording setting. + * @param videoRecording Whether to record video. + * @return The builder. + */ + fun videoRecording(videoRecording: Boolean) = apply { this.videoRecording = videoRecording } + + /** + * Set audio recording setting. + * @param audioRecording Whether to record audio. + * @return The builder. + */ + fun audioRecording(audioRecording: Boolean) = apply { this.audioRecording = audioRecording } + + /** + * Set transcription setting. + * @param transcription Whether to transcribe audio. + * @return The builder. + */ + fun transcription(transcription: Boolean) = apply { this.transcription = transcription } + + /** + * Build the [MeetingSettings]. + * @return The [MeetingSettings]. + */ + fun build() = MeetingSettings( + videoRecording = videoRecording, + audioRecording = audioRecording, + transcription = transcription, + ) + } + } + + /** + * Builder for [CreateNotetakerRequest]. + */ + class Builder( + private val meetingLink: String, + ) { + private var joinTime: Long? = null + private var name: String? = "Nylas Notetaker" + private var meetingSettings: MeetingSettings? = null + + /** + * Set join time. + * @param joinTime When Notetaker should join the meeting. + * @return The builder. + */ + fun joinTime(joinTime: Long) = apply { this.joinTime = joinTime } + + /** + * Set display name. + * @param name The display name for the Notetaker bot. + * @return The builder. + */ + fun name(name: String) = apply { this.name = name } + + /** + * Set meeting settings. + * @param meetingSettings The meeting settings. + * @return The builder. + */ + fun meetingSettings(meetingSettings: MeetingSettings) = apply { this.meetingSettings = meetingSettings } + + /** + * Build the [CreateNotetakerRequest]. + * @return The [CreateNotetakerRequest]. + */ + fun build() = CreateNotetakerRequest( + meetingLink = meetingLink, + joinTime = joinTime, + name = name, + meetingSettings = meetingSettings, + ) + } +} diff --git a/src/main/kotlin/com/nylas/models/Event.kt b/src/main/kotlin/com/nylas/models/Event.kt index 0e455b21..63c07436 100644 --- a/src/main/kotlin/com/nylas/models/Event.kt +++ b/src/main/kotlin/com/nylas/models/Event.kt @@ -145,6 +145,11 @@ data class Event( */ @Json(name = "updated_at") val updatedAt: Long? = null, + /** + * Notetaker meeting bot settings for this event. + */ + @Json(name = "notetaker") + val notetaker: EventNotetaker? = null, ) { /** * Get the type of object. diff --git a/src/main/kotlin/com/nylas/models/EventNotetaker.kt b/src/main/kotlin/com/nylas/models/EventNotetaker.kt new file mode 100644 index 00000000..8cfce0db --- /dev/null +++ b/src/main/kotlin/com/nylas/models/EventNotetaker.kt @@ -0,0 +1,91 @@ +package com.nylas.models + +import com.squareup.moshi.Json + +/** + * Class representation of Notetaker meeting bot settings for an event. + * This is used for responses and contains the id field. + */ +data class EventNotetaker( + /** + * The Notetaker ID. + */ + @Json(name = "id") + val id: String? = null, + + /** + * The display name for the Notetaker bot. + */ + @Json(name = "name") + val name: String? = "Nylas Notetaker", + + /** + * Notetaker Meeting Settings + */ + @Json(name = "meeting_settings") + val meetingSettings: MeetingSettings? = null, +) { + /** + * Data class for Notetaker Meeting Settings + */ + data class MeetingSettings( + /** + * When true, Notetaker records the meeting's video. + */ + @Json(name = "video_recording") + val videoRecording: Boolean? = true, + + /** + * When true, Notetaker records the meeting's audio. + */ + @Json(name = "audio_recording") + val audioRecording: Boolean? = true, + + /** + * When true, Notetaker transcribes the meeting's audio. + */ + @Json(name = "transcription") + val transcription: Boolean? = true, + ) +} + +/** + * Class representation of Notetaker meeting bot settings for an event creation request. + * This version omits the id field as it should not be part of the request. + */ +data class EventNotetakerRequest( + /** + * The display name for the Notetaker bot. + */ + @Json(name = "name") + val name: String? = "Nylas Notetaker", + + /** + * Notetaker Meeting Settings + */ + @Json(name = "meeting_settings") + val meetingSettings: MeetingSettings? = null, +) { + /** + * Data class for Notetaker Meeting Settings + */ + data class MeetingSettings( + /** + * When true, Notetaker records the meeting's video. + */ + @Json(name = "video_recording") + val videoRecording: Boolean? = true, + + /** + * When true, Notetaker records the meeting's audio. + */ + @Json(name = "audio_recording") + val audioRecording: Boolean? = true, + + /** + * When true, Notetaker transcribes the meeting's audio. + */ + @Json(name = "transcription") + val transcription: Boolean? = true, + ) +} diff --git a/src/main/kotlin/com/nylas/models/ListNotetakersQueryParams.kt b/src/main/kotlin/com/nylas/models/ListNotetakersQueryParams.kt new file mode 100644 index 00000000..97b85052 --- /dev/null +++ b/src/main/kotlin/com/nylas/models/ListNotetakersQueryParams.kt @@ -0,0 +1,130 @@ +package com.nylas.models + +import com.squareup.moshi.Json + +/** + * Class representing the query parameters for listing Notetakers. + */ +data class ListNotetakersQueryParams( + /** + * Filter for Notetaker bots with the specified meeting state. + */ + @Json(name = "state") + val state: Notetaker.NotetakerState? = null, + + /** + * Filter for Notetaker bots that are scheduled to join meetings after the specified time. + */ + @Json(name = "join_time_from") + val joinTimeFrom: Long? = null, + + /** + * Filter for Notetaker bots that are scheduled to join meetings until the specified time. + */ + @Json(name = "join_time_until") + val joinTimeUntil: Long? = null, + + /** + * The maximum number of objects to return. + * This field defaults to 50. The maximum allowed value is 200. + */ + @Json(name = "limit") + val limit: Int? = null, + + /** + * An identifier that specifies which page of data to return. + * This value should be taken from the [ListResponse.nextCursor] response field. + */ + @Json(name = "page_token") + val pageToken: String? = null, + + /** + * An identifier that specifies which page of data to return. + * This value should be taken from the [ListResponse.prevCursor] response field. + */ + @Json(name = "prev_page_token") + val prevPageToken: String? = null, + + /** + * Specify fields that you want Nylas to return, as a comma-separated list. + * This allows you to receive only the portion of object data that you're interested in. + */ + @Json(name = "select") + var select: String? = null, +) : IQueryParams { + /** + * Builder for [ListNotetakersQueryParams]. + */ + class Builder { + private var state: Notetaker.NotetakerState? = null + private var joinTimeFrom: Long? = null + private var joinTimeUntil: Long? = null + private var limit: Int? = null + private var pageToken: String? = null + private var prevPageToken: String? = null + private var select: String? = null + + /** + * Sets the state filter for Notetakers. + * @param state The meeting state to filter by. + * @return The builder. + */ + fun state(state: Notetaker.NotetakerState?) = apply { this.state = state } + + /** + * Sets the join time from filter. + * @param joinTimeFrom Unix timestamp to filter Notetakers joining after this time. + * @return The builder. + */ + fun joinTimeFrom(joinTimeFrom: Long?) = apply { this.joinTimeFrom = joinTimeFrom } + + /** + * Sets the join time until filter. + * @param joinTimeUntil Unix timestamp to filter Notetakers joining until this time. + * @return The builder. + */ + fun joinTimeUntil(joinTimeUntil: Long?) = apply { this.joinTimeUntil = joinTimeUntil } + + /** + * Sets the maximum number of objects to return. + * @param limit The maximum number of objects to return. + * @return The builder. + */ + fun limit(limit: Int?) = apply { this.limit = limit } + + /** + * Sets the page token for pagination. + * @param pageToken The page token for the next page of results. + * @return The builder. + */ + fun pageToken(pageToken: String?) = apply { this.pageToken = pageToken } + + /** + * Sets the previous page token for pagination. + * @param prevPageToken The page token for the previous page of results. + * @return The builder. + */ + fun prevPageToken(prevPageToken: String?) = apply { this.prevPageToken = prevPageToken } + + /** + * Sets the fields to return in the response. + * @param select List of field names to return (e.g. "id,updated_at") + * @return The builder. + */ + fun select(select: String?) = apply { this.select = select } + + /** + * Builds the [ListNotetakersQueryParams] object. + * @return The [ListNotetakersQueryParams] object. + */ + fun build() = ListNotetakersQueryParams( + state = state, + joinTimeFrom = joinTimeFrom, + joinTimeUntil = joinTimeUntil, + limit = limit, + pageToken = pageToken, + prevPageToken = prevPageToken, + select = select, + ) + } +} diff --git a/src/main/kotlin/com/nylas/models/Notetaker.kt b/src/main/kotlin/com/nylas/models/Notetaker.kt new file mode 100644 index 00000000..92655700 --- /dev/null +++ b/src/main/kotlin/com/nylas/models/Notetaker.kt @@ -0,0 +1,199 @@ +package com.nylas.models + +import com.squareup.moshi.Json + +/** + * Class representation of the Nylas Notetaker response. + */ +data class Notetaker( + /** + * The Notetaker ID. + */ + @Json(name = "id") + val id: String, + + /** + * The display name for the Notetaker bot. + */ + @Json(name = "name") + val name: String? = "Nylas Notetaker", + + /** + * When Notetaker joined the meeting, in Unix timestamp format. + */ + @Json(name = "join_time") + val joinTime: Long? = null, + + /** + * The meeting link. + */ + @Json(name = "meeting_link") + val meetingLink: String? = null, + + /** + * The meeting provider. + */ + @Json(name = "meeting_provider") + val meetingProvider: MeetingProvider? = null, + + /** + * The current state of the Notetaker bot. + */ + @Json(name = "state") + val state: NotetakerState? = null, + + /** + * Notetaker Meeting Settings + */ + @Json(name = "meeting_settings") + val meetingSettings: MeetingSettings? = null, + + /** + * The type of object. + */ + @Json(name = "object") + val obj: String = "notetaker", +) { + /** + * Enum for meeting providers + */ + enum class MeetingProvider { + @Json(name = "Google Meet") + GOOGLE_MEET, + + @Json(name = "Zoom Meeting") + ZOOM_MEETING, + + @Json(name = "Microsoft Teams") + MICROSOFT_TEAMS, + } + + /** + * Enum for Notetaker states + */ + enum class NotetakerState { + @Json(name = "scheduled") + SCHEDULED, + + @Json(name = "connecting") + CONNECTING, + + @Json(name = "waiting_for_entry") + WAITING_FOR_ENTRY, + + @Json(name = "failed_entry") + FAILED_ENTRY, + + @Json(name = "attending") + ATTENDING, + + @Json(name = "media_processing") + MEDIA_PROCESSING, + + @Json(name = "media_available") + MEDIA_AVAILABLE, + + @Json(name = "media_error") + MEDIA_ERROR, + + @Json(name = "media_deleted") + MEDIA_DELETED, + } + + /** + * Data class for Notetaker Meeting Settings + */ + data class MeetingSettings( + /** + * When true, Notetaker records the meeting's video. + */ + @Json(name = "video_recording") + val videoRecording: Boolean? = true, + + /** + * When true, Notetaker records the meeting's audio. + */ + @Json(name = "audio_recording") + val audioRecording: Boolean? = true, + + /** + * When true, Notetaker transcribes the meeting's audio. + */ + @Json(name = "transcription") + val transcription: Boolean? = true, + ) + + /** + * Get the type of object. + * @return The type of object. + */ + fun getObject() = obj +} + +/** + * Response for leaving a Notetaker + */ +data class LeaveNotetakerResponse( + /** + * The Notetaker ID + */ + @Json(name = "id") + val id: String, + + /** + * A message describing the API response + */ + @Json(name = "message") + val message: String, +) + +/** + * Response for downloading Notetaker media + */ +data class NotetakerMediaResponse( + /** + * The meeting recording + */ + @Json(name = "recording") + val recording: Recording? = null, + + /** + * The meeting transcript + */ + @Json(name = "transcript") + val transcript: Transcript? = null, +) { + /** + * Recording details + */ + data class Recording( + /** + * A link to the meeting recording + */ + @Json(name = "url") + val url: String, + + /** + * The size of the file, in MB + */ + @Json(name = "size") + val size: Int, + ) + + /** + * Transcript details + */ + data class Transcript( + /** + * A link to the meeting transcript + */ + @Json(name = "url") + val url: String, + + /** + * The size of the file, in MB + */ + @Json(name = "size") + val size: Int, + ) +} diff --git a/src/main/kotlin/com/nylas/models/UpdateCalendarRequest.kt b/src/main/kotlin/com/nylas/models/UpdateCalendarRequest.kt index c30d8faa..2af0426e 100644 --- a/src/main/kotlin/com/nylas/models/UpdateCalendarRequest.kt +++ b/src/main/kotlin/com/nylas/models/UpdateCalendarRequest.kt @@ -44,6 +44,11 @@ data class UpdateCalendarRequest( */ @Json(name = "hex_foreground_color") val hexForegroundColor: String? = null, + /** + * Notetaker meeting bot settings for this calendar. + */ + @Json(name = "notetaker") + val notetaker: CalendarNotetaker? = null, ) { class Builder { private var name: String? = null @@ -53,6 +58,7 @@ data class UpdateCalendarRequest( private var metadata: Map? = null private var hexColor: String? = null private var hexForegroundColor: String? = null + private var notetaker: CalendarNotetaker? = null /** * Set the name of the Calendar. @@ -99,9 +105,15 @@ data class UpdateCalendarRequest( */ fun hexForegroundColor(hexForegroundColor: String) = apply { this.hexForegroundColor = hexForegroundColor } + /** + * Set Notetaker meeting bot settings for this calendar. + * @param notetaker Notetaker meeting bot settings. + */ + fun notetaker(notetaker: CalendarNotetaker) = apply { this.notetaker = notetaker } + /** * Build the UpdateCalendarRequest object. */ - fun build() = UpdateCalendarRequest(name, description, location, timezone, metadata, hexColor, hexForegroundColor) + fun build() = UpdateCalendarRequest(name, description, location, timezone, metadata, hexColor, hexForegroundColor, notetaker) } } diff --git a/src/main/kotlin/com/nylas/models/UpdateEventRequest.kt b/src/main/kotlin/com/nylas/models/UpdateEventRequest.kt index f1f644cc..f40b6921 100644 --- a/src/main/kotlin/com/nylas/models/UpdateEventRequest.kt +++ b/src/main/kotlin/com/nylas/models/UpdateEventRequest.kt @@ -89,6 +89,11 @@ data class UpdateEventRequest( */ @Json(name = "hide_participant") val hideParticipant: Boolean? = null, + /** + * Notetaker meeting bot settings for this event. + */ + @Json(name = "notetaker") + val notetaker: EventNotetakerRequest? = null, ) { /** * This sealed class represents the different types of event time configurations. @@ -514,6 +519,7 @@ data class UpdateEventRequest( private var visibility: EventVisibility? = null private var capacity: Int? = null private var hideParticipant: Boolean? = null + private var notetaker: EventNotetakerRequest? = null /** * Set the when object. @@ -629,6 +635,13 @@ data class UpdateEventRequest( */ fun hideParticipant(hideParticipant: Boolean) = apply { this.hideParticipant = hideParticipant } + /** + * Update the notetaker meeting bot settings for the event. + * @param notetaker Notetaker meeting bot settings for this event. + * @return The builder. + */ + fun notetaker(notetaker: EventNotetakerRequest) = apply { this.notetaker = notetaker } + /** * Builds the [UpdateEventRequest] object. * @return [UpdateEventRequest] object. @@ -650,6 +663,7 @@ data class UpdateEventRequest( visibility, capacity, hideParticipant, + notetaker, ) } } diff --git a/src/main/kotlin/com/nylas/models/UpdateNotetakerRequest.kt b/src/main/kotlin/com/nylas/models/UpdateNotetakerRequest.kt new file mode 100644 index 00000000..70a60b31 --- /dev/null +++ b/src/main/kotlin/com/nylas/models/UpdateNotetakerRequest.kt @@ -0,0 +1,129 @@ +package com.nylas.models + +import com.squareup.moshi.Json + +/** + * Class representation of the Nylas Notetaker update request. + */ +data class UpdateNotetakerRequest( + /** + * When Notetaker should join the meeting, in Unix timestamp format. + */ + @Json(name = "join_time") + val joinTime: Long? = null, + + /** + * The display name for the Notetaker bot. + */ + @Json(name = "name") + val name: String? = null, + + /** + * Notetaker Meeting Settings + */ + @Json(name = "meeting_settings") + val meetingSettings: MeetingSettings? = null, +) { + /** + * Data class for Notetaker Meeting Settings + */ + data class MeetingSettings( + /** + * When true, Notetaker records the meeting's video. + */ + @Json(name = "video_recording") + val videoRecording: Boolean? = null, + + /** + * When true, Notetaker records the meeting's audio. + */ + @Json(name = "audio_recording") + val audioRecording: Boolean? = null, + + /** + * When true, Notetaker transcribes the meeting's audio. + */ + @Json(name = "transcription") + val transcription: Boolean? = null, + ) { + /** + * Builder for [MeetingSettings]. + */ + class Builder { + private var videoRecording: Boolean? = null + private var audioRecording: Boolean? = null + private var transcription: Boolean? = null + + /** + * Set video recording setting. + * @param videoRecording Whether to record video. + * @return The builder. + */ + fun videoRecording(videoRecording: Boolean) = apply { this.videoRecording = videoRecording } + + /** + * Set audio recording setting. + * @param audioRecording Whether to record audio. + * @return The builder. + */ + fun audioRecording(audioRecording: Boolean) = apply { this.audioRecording = audioRecording } + + /** + * Set transcription setting. + * @param transcription Whether to transcribe audio. + * @return The builder. + */ + fun transcription(transcription: Boolean) = apply { this.transcription = transcription } + + /** + * Build the [MeetingSettings]. + * @return The [MeetingSettings]. + */ + fun build() = MeetingSettings( + videoRecording = videoRecording, + audioRecording = audioRecording, + transcription = transcription, + ) + } + } + + /** + * Builder for [UpdateNotetakerRequest]. + */ + class Builder { + private var joinTime: Long? = null + private var name: String? = null + private var meetingSettings: MeetingSettings? = null + + /** + * Set join time. + * @param joinTime When Notetaker should join the meeting. + * @return The builder. + */ + fun joinTime(joinTime: Long) = apply { this.joinTime = joinTime } + + /** + * Set display name. + * @param name The display name for the Notetaker bot. + * @return The builder. + */ + fun name(name: String) = apply { this.name = name } + + /** + * Set meeting settings. + * @param meetingSettings The meeting settings. + * @return The builder. + */ + fun meetingSettings(meetingSettings: MeetingSettings) = apply { this.meetingSettings = meetingSettings } + + /** + * Build the [UpdateNotetakerRequest]. + * @return The [UpdateNotetakerRequest]. + */ + fun build() = UpdateNotetakerRequest( + joinTime = joinTime, + name = name, + meetingSettings = meetingSettings, + ) + } +} diff --git a/src/main/kotlin/com/nylas/resources/Notetakers.kt b/src/main/kotlin/com/nylas/resources/Notetakers.kt new file mode 100644 index 00000000..f84f0529 --- /dev/null +++ b/src/main/kotlin/com/nylas/resources/Notetakers.kt @@ -0,0 +1,142 @@ +package com.nylas.resources + +import com.nylas.NylasClient +import com.nylas.models.* +import com.nylas.util.JsonHelper +import com.squareup.moshi.Types + +class Notetakers(client: NylasClient) : Resource(client, Notetaker::class.java) { + /** + * Return all Notetakers + * @param queryParams The query parameters to include in the request + * @param identifier Grant ID or email account to query. + * @param overrides Optional request overrides to apply + * @return The list of Notetakers + */ + @Throws(NylasApiError::class, NylasSdkTimeoutError::class) + @JvmOverloads + fun list( + queryParams: ListNotetakersQueryParams? = null, + identifier: String? = null, + overrides: RequestOverrides? = null, + ): ListResponse { + val path = identifier?.let { String.format("v3/grants/%s/notetakers", it) } ?: "v3/notetakers" + return listResource(path, queryParams, overrides) + } + + /** + * Return a Notetaker + * @param notetakerId The id of the Notetaker to retrieve. + * @param identifier Grant ID or email account to query. + * @param overrides Optional request overrides to apply + * @return The Notetaker + */ + @Throws(NylasApiError::class, NylasSdkTimeoutError::class) + @JvmOverloads + fun find( + notetakerId: String, + identifier: String? = null, + overrides: RequestOverrides? = null, + ): Response { + val path = identifier?.let { String.format("v3/grants/%s/notetakers/%s", it, notetakerId) } ?: String.format("v3/notetakers/%s", notetakerId) + return findResource(path, overrides = overrides) + } + + /** + * Create a Notetaker + * @param requestBody The values to create the Notetaker with + * @param identifier Grant ID or email account in which to create the object. + * @param overrides Optional request overrides to apply + * @return The created Notetaker + */ + @Throws(NylasApiError::class, NylasSdkTimeoutError::class) + @JvmOverloads + fun create( + requestBody: CreateNotetakerRequest, + identifier: String? = null, + overrides: RequestOverrides? = null, + ): Response { + val path = identifier?.let { String.format("v3/grants/%s/notetakers", it) } ?: "v3/notetakers" + val adapter = JsonHelper.moshi().adapter(CreateNotetakerRequest::class.java) + val serializedRequestBody = adapter.toJson(requestBody) + return createResource(path, serializedRequestBody, overrides = overrides) + } + + /** + * Update a Notetaker + * @param notetakerId The id of the Notetaker to update. + * @param requestBody The values to update the Notetaker with + * @param identifier Grant ID or email account in which to update an object. + * @param overrides Optional request overrides to apply + * @return The updated Notetaker + */ + @Throws(NylasApiError::class, NylasSdkTimeoutError::class) + @JvmOverloads + fun update( + notetakerId: String, + requestBody: UpdateNotetakerRequest, + identifier: String? = null, + overrides: RequestOverrides? = null, + ): Response { + val path = identifier?.let { String.format("v3/grants/%s/notetakers/%s", it, notetakerId) } ?: String.format("v3/notetakers/%s", notetakerId) + val adapter = JsonHelper.moshi().adapter(UpdateNotetakerRequest::class.java) + val serializedRequestBody = adapter.toJson(requestBody) + return updateResource(path, serializedRequestBody, overrides = overrides) + } + + /** + * Remove Notetaker from meeting + * @param notetakerId The id of the Notetaker to remove. + * @param identifier Grant ID or email account from which to remove the Notetaker. + * @param overrides Optional request overrides to apply + * @return The removal response + */ + @Throws(NylasApiError::class, NylasSdkTimeoutError::class) + @JvmOverloads + fun leave( + notetakerId: String, + identifier: String? = null, + overrides: RequestOverrides? = null, + ): Response { + val path = identifier?.let { String.format("v3/grants/%s/notetakers/%s/leave", it, notetakerId) } ?: String.format("v3/notetakers/%s/leave", notetakerId) + val responseType = Types.newParameterizedType(Response::class.java, LeaveNotetakerResponse::class.java) + return client.executePost(path, responseType, null, null, overrides) + } + + /** + * Download Notetaker media + * @param notetakerId The id of the Notetaker to access. + * @param identifier Grant ID or email account to access. + * @param overrides Optional request overrides to apply + * @return The Notetaker media download response + */ + @Throws(NylasApiError::class, NylasSdkTimeoutError::class) + @JvmOverloads + fun downloadMedia( + notetakerId: String, + identifier: String? = null, + overrides: RequestOverrides? = null, + ): Response { + val path = identifier?.let { String.format("v3/grants/%s/notetakers/%s/media", it, notetakerId) } ?: String.format("v3/notetakers/%s/media", notetakerId) + val type = Types.newParameterizedType(Response::class.java, NotetakerMediaResponse::class.java) + return client.executeGet(path, type, null, overrides) + } + + /** + * Cancel a scheduled Notetaker + * @param notetakerId The id of the Notetaker to cancel. + * @param identifier Grant ID or email account to query. + * @param overrides Optional request overrides to apply + * @return The cancellation response + */ + @Throws(NylasApiError::class, NylasSdkTimeoutError::class) + @JvmOverloads + fun cancel( + notetakerId: String, + identifier: String? = null, + overrides: RequestOverrides? = null, + ): DeleteResponse { + val path = identifier?.let { String.format("v3/grants/%s/notetakers/%s/cancel", it, notetakerId) } ?: String.format("v3/notetakers/%s/cancel", notetakerId) + return destroyResource(path, overrides = overrides) + } +} diff --git a/src/test/kotlin/com/nylas/models/CalendarNotetakerTest.kt b/src/test/kotlin/com/nylas/models/CalendarNotetakerTest.kt new file mode 100644 index 00000000..4821de3a --- /dev/null +++ b/src/test/kotlin/com/nylas/models/CalendarNotetakerTest.kt @@ -0,0 +1,64 @@ +package com.nylas.models + +import com.nylas.util.JsonHelper +import okio.Buffer +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertNull + +class CalendarNotetakerTest { + @Test + fun `CalendarNotetaker serializes properly`() { + val adapter = JsonHelper.moshi().adapter(CalendarNotetaker::class.java) + val jsonBuffer = Buffer().writeUtf8( + """ + { + "name": "Custom Notetaker", + "meeting_settings": { + "video_recording": true, + "audio_recording": false, + "transcription": true + }, + "rules": { + "event_selection": ["internal", "external"], + "participant_filter": { + "participants_gte": 3, + "participants_lte": 20 + } + } + } + """.trimIndent(), + ) + + val notetaker = adapter.fromJson(jsonBuffer)!! + assertIs(notetaker) + assertEquals("Custom Notetaker", notetaker.name) + assertEquals(true, notetaker.meetingSettings?.videoRecording) + assertEquals(false, notetaker.meetingSettings?.audioRecording) + assertEquals(true, notetaker.meetingSettings?.transcription) + assertEquals(2, notetaker.rules?.eventSelection?.size) + assertEquals(CalendarNotetaker.EventSelectionType.INTERNAL, notetaker.rules?.eventSelection?.get(0)) + assertEquals(CalendarNotetaker.EventSelectionType.EXTERNAL, notetaker.rules?.eventSelection?.get(1)) + assertEquals(3, notetaker.rules?.participantFilter?.participantsGte) + assertEquals(20, notetaker.rules?.participantFilter?.participantsLte) + } + + @Test + fun `CalendarNotetaker deserializes with minimal fields`() { + val adapter = JsonHelper.moshi().adapter(CalendarNotetaker::class.java) + val jsonBuffer = Buffer().writeUtf8( + """ + { + "name": "Minimal Notetaker" + } + """.trimIndent(), + ) + + val notetaker = adapter.fromJson(jsonBuffer)!! + assertIs(notetaker) + assertEquals("Minimal Notetaker", notetaker.name) + assertNull(notetaker.meetingSettings) + assertNull(notetaker.rules) + } +} diff --git a/src/test/kotlin/com/nylas/models/EventNotetakerTest.kt b/src/test/kotlin/com/nylas/models/EventNotetakerTest.kt new file mode 100644 index 00000000..17b06ddb --- /dev/null +++ b/src/test/kotlin/com/nylas/models/EventNotetakerTest.kt @@ -0,0 +1,94 @@ +package com.nylas.models + +import com.nylas.util.JsonHelper +import okio.Buffer +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertNull + +class EventNotetakerTest { + @Test + fun `EventNotetaker response serializes properly`() { + val adapter = JsonHelper.moshi().adapter(EventNotetaker::class.java) + val jsonBuffer = Buffer().writeUtf8( + """ + { + "id": "notetaker-123", + "name": "Custom Event Notetaker", + "meeting_settings": { + "video_recording": false, + "audio_recording": true, + "transcription": true + } + } + """.trimIndent(), + ) + + val notetaker = adapter.fromJson(jsonBuffer)!! + assertIs(notetaker) + assertEquals("notetaker-123", notetaker.id) + assertEquals("Custom Event Notetaker", notetaker.name) + assertEquals(false, notetaker.meetingSettings?.videoRecording) + assertEquals(true, notetaker.meetingSettings?.audioRecording) + assertEquals(true, notetaker.meetingSettings?.transcription) + } + + @Test + fun `EventNotetaker response deserializes with minimal fields`() { + val adapter = JsonHelper.moshi().adapter(EventNotetaker::class.java) + val jsonBuffer = Buffer().writeUtf8( + """ + { + "id": "notetaker-456" + } + """.trimIndent(), + ) + + val notetaker = adapter.fromJson(jsonBuffer)!! + assertIs(notetaker) + assertEquals("notetaker-456", notetaker.id) + assertEquals("Nylas Notetaker", notetaker.name) // Default value + assertNull(notetaker.meetingSettings) + } + + @Test + fun `EventNotetakerRequest serializes properly`() { + val adapter = JsonHelper.moshi().adapter(EventNotetakerRequest::class.java) + val jsonBuffer = Buffer().writeUtf8( + """ + { + "name": "Custom Event Notetaker", + "meeting_settings": { + "video_recording": false, + "audio_recording": true, + "transcription": true + } + } + """.trimIndent(), + ) + + val notetaker = adapter.fromJson(jsonBuffer)!! + assertIs(notetaker) + assertEquals("Custom Event Notetaker", notetaker.name) + assertEquals(false, notetaker.meetingSettings?.videoRecording) + assertEquals(true, notetaker.meetingSettings?.audioRecording) + assertEquals(true, notetaker.meetingSettings?.transcription) + } + + @Test + fun `EventNotetakerRequest deserializes with minimal fields`() { + val adapter = JsonHelper.moshi().adapter(EventNotetakerRequest::class.java) + val jsonBuffer = Buffer().writeUtf8( + """ + { + } + """.trimIndent(), + ) + + val notetaker = adapter.fromJson(jsonBuffer)!! + assertIs(notetaker) + assertEquals("Nylas Notetaker", notetaker.name) // Default value + assertNull(notetaker.meetingSettings) + } +} diff --git a/src/test/kotlin/com/nylas/resources/CalendarsTest.kt b/src/test/kotlin/com/nylas/resources/CalendarsTest.kt index f9b88ea6..43c1ee26 100644 --- a/src/test/kotlin/com/nylas/resources/CalendarsTest.kt +++ b/src/test/kotlin/com/nylas/resources/CalendarsTest.kt @@ -57,7 +57,22 @@ class CalendarsTest { "name": "My New Calendar", "object": "calendar", "read_only": false, - "timezone": "America/Los_Angeles" + "timezone": "America/Los_Angeles", + "notetaker": { + "name": "Custom Calendar Notetaker", + "meeting_settings": { + "video_recording": true, + "audio_recording": true, + "transcription": false + }, + "rules": { + "event_selection": ["internal", "all"], + "participant_filter": { + "participants_gte": 2, + "participants_lte": 10 + } + } + } } """.trimIndent(), ) @@ -75,6 +90,15 @@ class CalendarsTest { assertEquals("My New Calendar", cal.name) assertEquals(false, cal.readOnly) assertEquals("America/Los_Angeles", cal.timezone) + assertEquals("Custom Calendar Notetaker", cal.notetaker?.name) + assertEquals(true, cal.notetaker?.meetingSettings?.videoRecording) + assertEquals(true, cal.notetaker?.meetingSettings?.audioRecording) + assertEquals(false, cal.notetaker?.meetingSettings?.transcription) + assertEquals(2, cal.notetaker?.rules?.eventSelection?.size) + assertEquals(CalendarNotetaker.EventSelectionType.INTERNAL, cal.notetaker?.rules?.eventSelection?.get(0)) + assertEquals(CalendarNotetaker.EventSelectionType.ALL, cal.notetaker?.rules?.eventSelection?.get(1)) + assertEquals(2, cal.notetaker?.rules?.participantFilter?.participantsGte) + assertEquals(10, cal.notetaker?.rules?.participantFilter?.participantsLte) } } @@ -138,6 +162,21 @@ class CalendarsTest { metadata = mapOf("your-key" to "value"), name = "My New Calendar", timezone = "America/Los_Angeles", + notetaker = CalendarNotetaker( + name = "Test Notetaker", + meetingSettings = CalendarNotetaker.MeetingSettings( + videoRecording = true, + audioRecording = true, + transcription = false, + ), + rules = CalendarNotetaker.Rules( + eventSelection = listOf(CalendarNotetaker.EventSelectionType.INTERNAL), + participantFilter = CalendarNotetaker.ParticipantFilter( + participantsGte = 2, + participantsLte = null, + ), + ), + ), ) calendars.create(grantId, createCalendarRequest) @@ -171,6 +210,21 @@ class CalendarsTest { timezone = "America/Los_Angeles", hexColor = "#039BE5", hexForegroundColor = "#039BE5", + notetaker = CalendarNotetaker( + name = "Updated Notetaker", + meetingSettings = CalendarNotetaker.MeetingSettings( + videoRecording = false, + audioRecording = true, + transcription = true, + ), + rules = CalendarNotetaker.Rules( + eventSelection = listOf(CalendarNotetaker.EventSelectionType.EXTERNAL, CalendarNotetaker.EventSelectionType.ALL), + participantFilter = CalendarNotetaker.ParticipantFilter( + participantsGte = null, + participantsLte = 15, + ), + ), + ), ) calendars.update(grantId, calendarId, updateCalendarRequest) diff --git a/src/test/kotlin/com/nylas/resources/EventsTests.kt b/src/test/kotlin/com/nylas/resources/EventsTests.kt index 2c248258..67caafb3 100644 --- a/src/test/kotlin/com/nylas/resources/EventsTests.kt +++ b/src/test/kotlin/com/nylas/resources/EventsTests.kt @@ -102,6 +102,15 @@ class EventsTests { "start_timezone": "America/New_York", "end_timezone": "America/New_York", "object": "timespan" + }, + "notetaker": { + "id": "notetaker-123", + "name": "Event Notetaker", + "meeting_settings": { + "video_recording": false, + "audio_recording": true, + "transcription": true + } } } """.trimIndent(), @@ -155,6 +164,13 @@ class EventsTests { assertEquals(1661877792, whenTimespan.endTime) assertEquals("America/New_York", whenTimespan.startTimezone) assertEquals("America/New_York", whenTimespan.endTimezone) + + // Verify notetaker field + assertEquals("notetaker-123", event.notetaker?.id) + assertEquals("Event Notetaker", event.notetaker?.name) + assertEquals(false, event.notetaker?.meetingSettings?.videoRecording) + assertEquals(true, event.notetaker?.meetingSettings?.audioRecording) + assertEquals(true, event.notetaker?.meetingSettings?.transcription) } @Test @@ -314,6 +330,14 @@ class EventsTests { description = "Description of my new event", location = "Los Angeles, CA", metadata = mapOf("your-key" to "value"), + notetaker = EventNotetakerRequest( + name = "Event Creation Notetaker", + meetingSettings = EventNotetakerRequest.MeetingSettings( + videoRecording = true, + audioRecording = true, + transcription = true, + ), + ), ) val createEventQueryParams = CreateEventQueryParams( @@ -348,6 +372,14 @@ class EventsTests { UpdateEventRequest( description = "Description of my new event", location = "Los Angeles, CA", + notetaker = EventNotetakerRequest( + name = "Updated Event Notetaker", + meetingSettings = EventNotetakerRequest.MeetingSettings( + videoRecording = false, + audioRecording = true, + transcription = true, + ), + ), ) val updateEventQueryParams = UpdateEventQueryParams( diff --git a/src/test/kotlin/com/nylas/resources/NotetakersTests.kt b/src/test/kotlin/com/nylas/resources/NotetakersTests.kt new file mode 100644 index 00000000..0d0c8f57 --- /dev/null +++ b/src/test/kotlin/com/nylas/resources/NotetakersTests.kt @@ -0,0 +1,282 @@ +package com.nylas.resources + +import com.nylas.NylasClient +import com.nylas.models.* +import com.nylas.models.Response +import com.nylas.util.JsonHelper +import com.squareup.moshi.Types +import okhttp3.* +import okio.Buffer +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Nested +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.* +import java.lang.reflect.Type +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertNull + +class NotetakersTests { + private val mockHttpClient: OkHttpClient = Mockito.mock(OkHttpClient::class.java) + private val mockCall: Call = Mockito.mock(Call::class.java) + private val mockResponse: okhttp3.Response = Mockito.mock(okhttp3.Response::class.java) + private val mockResponseBody: ResponseBody = Mockito.mock(ResponseBody::class.java) + private val mockOkHttpClientBuilder: OkHttpClient.Builder = Mockito.mock() + + @BeforeEach + fun setup() { + MockitoAnnotations.openMocks(this) + whenever(mockOkHttpClientBuilder.addInterceptor(any())).thenReturn(mockOkHttpClientBuilder) + whenever(mockOkHttpClientBuilder.build()).thenReturn(mockHttpClient) + whenever(mockHttpClient.newCall(any())).thenReturn(mockCall) + whenever(mockCall.execute()).thenReturn(mockResponse) + whenever(mockResponse.isSuccessful).thenReturn(true) + whenever(mockResponse.body()).thenReturn(mockResponseBody) + } + + @Nested + inner class SerializationTests { + @Test + fun `Notetaker serializes properly`() { + val adapter = JsonHelper.moshi().adapter(Notetaker::class.java) + val jsonBuffer = Buffer().writeUtf8( + """ + { + "id": "notetaker-123", + "name": "Nylas Notetaker", + "join_time": 1234567890, + "meeting_link": "https://meet.google.com/abc-123", + "meeting_provider": "Google Meet", + "state": "scheduled", + "object": "notetaker", + "meeting_settings": { + "video_recording": true, + "audio_recording": true, + "transcription": true + } + } + """.trimIndent(), + ) + + val notetaker = adapter.fromJson(jsonBuffer)!! + assertIs(notetaker) + assertEquals("notetaker-123", notetaker.id) + assertEquals("Nylas Notetaker", notetaker.name) + assertEquals(1234567890, notetaker.joinTime) + assertEquals("https://meet.google.com/abc-123", notetaker.meetingLink) + assertEquals(Notetaker.MeetingProvider.GOOGLE_MEET, notetaker.meetingProvider) + assertEquals(Notetaker.NotetakerState.SCHEDULED, notetaker.state) + assertEquals("notetaker", notetaker.getObject()) + assertEquals(true, notetaker.meetingSettings?.videoRecording) + assertEquals(true, notetaker.meetingSettings?.audioRecording) + assertEquals(true, notetaker.meetingSettings?.transcription) + } + + @Test + fun `DeleteResponse serializes properly`() { + val adapter = JsonHelper.moshi().adapter(DeleteResponse::class.java) + val jsonBuffer = Buffer().writeUtf8( + """ + { + "request_id": "req-123" + } + """.trimIndent(), + ) + + val response = adapter.fromJson(jsonBuffer)!! + assertIs(response) + assertEquals("req-123", response.requestId) + } + } + + @Nested + inner class CrudTests { + private lateinit var grantId: String + private lateinit var mockNylasClient: NylasClient + private lateinit var notetakers: Notetakers + + @BeforeEach + fun setup() { + grantId = "abc-123-grant-id" + mockNylasClient = Mockito.mock(NylasClient::class.java) + notetakers = Notetakers(mockNylasClient) + } + + @Test + fun `listing notetakers calls requests with the correct params`() { + val queryParams = ListNotetakersQueryParams( + limit = 10, + pageToken = "abc-123", + select = "id,updated_at", + ) + + notetakers.list(queryParams, grantId) + + val pathCaptor = argumentCaptor() + val typeCaptor = argumentCaptor() + val queryParamCaptor = argumentCaptor() + val overrideParamCaptor = argumentCaptor() + verify(mockNylasClient).executeGet>( + pathCaptor.capture(), + typeCaptor.capture(), + queryParamCaptor.capture(), + overrideParamCaptor.capture(), + ) + + assertEquals("v3/grants/$grantId/notetakers", pathCaptor.firstValue) + assertEquals(Types.newParameterizedType(ListResponse::class.java, Notetaker::class.java), typeCaptor.firstValue) + assertEquals(queryParams, queryParamCaptor.firstValue) + } + + @Test + fun `finding a notetaker calls requests with the correct params`() { + val notetakerId = "notetaker-123" + + notetakers.find(notetakerId, grantId) + + val pathCaptor = argumentCaptor() + val typeCaptor = argumentCaptor() + val overrideParamCaptor = argumentCaptor() + verify(mockNylasClient).executeGet>( + pathCaptor.capture(), + typeCaptor.capture(), + isNull(), + overrideParamCaptor.capture(), + ) + + assertEquals("v3/grants/$grantId/notetakers/$notetakerId", pathCaptor.firstValue) + assertEquals(Types.newParameterizedType(Response::class.java, Notetaker::class.java), typeCaptor.firstValue) + } + + @Test + fun `creating a notetaker calls requests with the correct params`() { + val adapter = JsonHelper.moshi().adapter(CreateNotetakerRequest::class.java) + val createNotetakerRequest = CreateNotetakerRequest( + meetingLink = "https://meet.example.com/meeting", + name = "Meeting Assistant", + joinTime = 1625097600, + meetingSettings = CreateNotetakerRequest.MeetingSettings( + videoRecording = true, + audioRecording = true, + transcription = true, + ), + ) + + notetakers.create(createNotetakerRequest, grantId) + + val pathCaptor = argumentCaptor() + val typeCaptor = argumentCaptor() + val requestBodyCaptor = argumentCaptor() + val overrideParamCaptor = argumentCaptor() + verify(mockNylasClient).executePost>( + pathCaptor.capture(), + typeCaptor.capture(), + requestBodyCaptor.capture(), + isNull(), + overrideParamCaptor.capture(), + ) + + assertEquals("v3/grants/$grantId/notetakers", pathCaptor.firstValue) + assertEquals(Types.newParameterizedType(Response::class.java, Notetaker::class.java), typeCaptor.firstValue) + assertEquals(adapter.toJson(createNotetakerRequest), requestBodyCaptor.firstValue) + } + + @Test + fun `updating a notetaker calls requests with the correct params`() { + val notetakerId = "notetaker-123" + val adapter = JsonHelper.moshi().adapter(UpdateNotetakerRequest::class.java) + val updateNotetakerRequest = UpdateNotetakerRequest( + name = "Updated Meeting Assistant", + joinTime = 1625184000, + meetingSettings = UpdateNotetakerRequest.MeetingSettings( + videoRecording = false, + audioRecording = true, + transcription = true, + ), + ) + + notetakers.update(notetakerId, updateNotetakerRequest, grantId) + + val pathCaptor = argumentCaptor() + val typeCaptor = argumentCaptor() + val requestBodyCaptor = argumentCaptor() + val overrideParamCaptor = argumentCaptor() + verify(mockNylasClient).executePut>( + pathCaptor.capture(), + typeCaptor.capture(), + requestBodyCaptor.capture(), + isNull(), + overrideParamCaptor.capture(), + ) + + assertEquals("v3/grants/$grantId/notetakers/$notetakerId", pathCaptor.firstValue) + assertEquals(Types.newParameterizedType(Response::class.java, Notetaker::class.java), typeCaptor.firstValue) + assertEquals(adapter.toJson(updateNotetakerRequest), requestBodyCaptor.firstValue) + } + + @Test + fun `leaving a notetaker calls requests with the correct params`() { + val notetakerId = "notetaker-123" + + notetakers.leave(notetakerId, grantId) + + val pathCaptor = argumentCaptor() + val typeCaptor = argumentCaptor() + val overrideParamCaptor = argumentCaptor() + verify(mockNylasClient).executePost>( + pathCaptor.capture(), + typeCaptor.capture(), + isNull(), + isNull(), + overrideParamCaptor.capture(), + ) + + assertEquals("v3/grants/$grantId/notetakers/$notetakerId/leave", pathCaptor.firstValue) + assertEquals(Types.newParameterizedType(Response::class.java, LeaveNotetakerResponse::class.java), typeCaptor.firstValue) + } + + @Test + fun `downloading notetaker media calls requests with the correct params`() { + val notetakerId = "notetaker-123" + + notetakers.downloadMedia(notetakerId, grantId) + + val pathCaptor = argumentCaptor() + val typeCaptor = argumentCaptor() + val overrideParamCaptor = argumentCaptor() + verify(mockNylasClient).executeGet>( + pathCaptor.capture(), + typeCaptor.capture(), + isNull(), + overrideParamCaptor.capture(), + ) + + assertEquals("v3/grants/$grantId/notetakers/$notetakerId/media", pathCaptor.firstValue) + assertEquals(Types.newParameterizedType(Response::class.java, NotetakerMediaResponse::class.java), typeCaptor.firstValue) + } + + @Test + fun `canceling a notetaker calls requests with the correct params`() { + val notetakerId = "notetaker-123" + + notetakers.cancel(notetakerId, grantId) + + val pathCaptor = argumentCaptor() + val typeCaptor = argumentCaptor() + val queryParamCaptor = argumentCaptor() + val overrideParamCaptor = argumentCaptor() + verify(mockNylasClient).executeDelete( + pathCaptor.capture(), + typeCaptor.capture(), + queryParamCaptor.capture(), + overrideParamCaptor.capture(), + ) + + assertEquals("v3/grants/$grantId/notetakers/$notetakerId/cancel", pathCaptor.firstValue) + assertEquals(DeleteResponse::class.java, typeCaptor.firstValue) + assertNull(queryParamCaptor.firstValue) + } + } +}