diff --git a/CHANGELOG.md b/CHANGELOG.md index 78c99f47..d29b9430 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ### [Unreleased] +* Added support for `single_level` query parameter in Folders API for Microsoft accounts * Added support for `include_hidden_folders` query parameter in folders list endpoint for Microsoft accounts to control whether hidden folders are included in the response ### 6.5.0 / 2025-06-13 diff --git a/examples/folders/folders_example.rb b/examples/folders/folders_example.rb new file mode 100755 index 00000000..f593ddd7 --- /dev/null +++ b/examples/folders/folders_example.rb @@ -0,0 +1,189 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# Example demonstrating the single_level query parameter in the Nylas Ruby SDK Folders API +# +# This example shows how to: +# 1. List folders with default multi-level hierarchy +# 2. List folders with single-level hierarchy (Microsoft accounts only) +# 3. Combine single_level with other query parameters +# +# Prerequisites: +# - Ruby 3.0 or later +# - A Nylas API key +# - A grant ID (connected email account, preferably Microsoft for full functionality) +# +# Environment variables needed: +# export NYLAS_API_KEY="your_api_key" +# export NYLAS_GRANT_ID="your_grant_id" +# export NYLAS_API_URI="https://api.us.nylas.com" # Optional +# +# Alternatively, create a .env file in the examples directory with: +# NYLAS_API_KEY=your_api_key +# NYLAS_GRANT_ID=your_grant_id +# NYLAS_API_URI=https://api.us.nylas.com + +$LOAD_PATH.unshift File.expand_path("../../lib", __dir__) +require "nylas" +require "json" + +# Simple .env file loader +def load_env_file + env_file = File.expand_path("../.env", __dir__) + return unless File.exist?(env_file) + + puts "Loading environment variables from .env file..." + File.readlines(env_file).each do |line| + line = line.strip + next if line.empty? || line.start_with?("#") + + key, value = line.split("=", 2) + next unless key && value + + # Remove quotes if present + value = value.gsub(/\A['"]|['"]\z/, "") + ENV[key] = value + end +end + +def list_folders_multi_level(nylas, grant_id) + puts "\n=== Listing Folders with Multi-Level Hierarchy (Default) ===" + + folders, request_id, next_cursor = nylas.folders.list( + identifier: grant_id + ) + + puts "Found #{folders.length} folders in multi-level hierarchy" + display_folders(folders) + puts "Request ID: #{request_id}" + puts "Next cursor: #{next_cursor || 'None'}" + + folders +end + +def list_folders_single_level(nylas, grant_id) + puts "\n=== Listing Folders with Single-Level Hierarchy (Microsoft Only) ===" + + folders, request_id, next_cursor = nylas.folders.list( + identifier: grant_id, + query_params: { single_level: true } + ) + + puts "Found #{folders.length} folders in single-level hierarchy" + display_folders(folders) + puts "Request ID: #{request_id}" + puts "Next cursor: #{next_cursor || 'None'}" + + folders +end + +def list_folders_with_additional_params(nylas, grant_id) + puts "\n=== Listing Folders with Single-Level + Additional Parameters ===" + + folders, request_id, next_cursor = nylas.folders.list( + identifier: grant_id, + query_params: { + single_level: true, + limit: 5 + } + ) + + puts "Found #{folders.length} folders (limited to 5) in single-level hierarchy" + display_folders(folders) + puts "Request ID: #{request_id}" + puts "Next cursor: #{next_cursor || 'None'}" + + folders +end + +def display_folders(folders) + if folders.empty? + puts " No folders found" + return + end + + folders.each do |folder| + parent_info = folder[:parent_id] ? "Parent: #{folder[:parent_id]}" : "Root folder" + system_folder = folder[:system_folder] ? " (System)" : "" + puts " - #{folder[:name]}#{system_folder}" + puts " ID: #{folder[:id]}" + puts " #{parent_info}" + puts " Unread: #{folder[:unread_count] || 0}, Total: #{folder[:total_count] || 0}" + puts + end +end + +def demonstrate_single_level_parameter + puts "\n=== Single-Level Parameter Documentation ===" + puts "The single_level parameter is designed for Microsoft accounts and controls folder hierarchy:" + puts "- single_level: true -> Retrieves folders from a single-level hierarchy only" + puts "- single_level: false -> Retrieves folders across a multi-level hierarchy (default)" + puts "- This parameter is most effective with Microsoft Exchange/Outlook accounts" + puts "- Other providers may not show significant differences in behavior" +end + +def main + # Load .env file if it exists + load_env_file + + # Check for required environment variables + api_key = ENV["NYLAS_API_KEY"] + grant_id = ENV["NYLAS_GRANT_ID"] + + raise "NYLAS_API_KEY environment variable is not set" unless api_key + raise "NYLAS_GRANT_ID environment variable is not set" unless grant_id + + puts "Using API key: #{api_key[0..4]}..." + puts "Using grant ID: #{grant_id[0..8]}..." + + # Initialize the Nylas client + nylas = Nylas::Client.new( + api_key: api_key, + api_uri: ENV["NYLAS_API_URI"] || "https://api.us.nylas.com" + ) + + puts "\n=== Nylas Folders Single-Level Parameter Example ===" + + begin + # Demonstrate the parameter concept + demonstrate_single_level_parameter + + # Example 1: List folders with default multi-level hierarchy + multi_level_folders = list_folders_multi_level(nylas, grant_id) + + # Example 2: List folders with single-level hierarchy + single_level_folders = list_folders_single_level(nylas, grant_id) + + # Example 3: List folders with single-level and additional parameters + list_folders_with_additional_params(nylas, grant_id) + + # Compare results if both calls returned folders + if multi_level_folders.any? && single_level_folders.any? + puts "\n=== Comparison ===" + puts "Multi-level hierarchy returned: #{multi_level_folders.length} folders" + puts "Single-level hierarchy returned: #{single_level_folders.length} folders" + + if multi_level_folders.length != single_level_folders.length + puts "Different folder counts suggest the single_level parameter is working as expected." + else + puts "Same folder count - this might indicate:" + puts "- The account doesn't have nested folders" + puts "- The provider doesn't support hierarchical folders" + puts "- The account is not a Microsoft account" + end + end + rescue StandardError => e + puts "\nError occurred: #{e.message}" + puts "This might happen if:" + puts "- The API key or grant ID is invalid" + puts "- The account doesn't have permission to access folders" + puts "- Network connectivity issues" + puts "\nFull error details:" + puts e.inspect + end + + puts "\n=== Example completed ===" +end + +# Run the example if this file is executed directly +main if __FILE__ == $PROGRAM_NAME diff --git a/lib/nylas/resources/folders.rb b/lib/nylas/resources/folders.rb index 00c61170..be0f2d44 100644 --- a/lib/nylas/resources/folders.rb +++ b/lib/nylas/resources/folders.rb @@ -15,6 +15,10 @@ class Folders < Resource # # @param identifier [String] Grant ID or email account to query. # @param query_params [Hash, nil] Query params to pass to the request. + # Supported parameters include: + # - single_level: (Boolean) For Microsoft accounts only. If true, retrieves folders from + # a single-level hierarchy only. If false (default), retrieves folders across a + # multi-level hierarchy. # - include_hidden_folders [Boolean] (Microsoft only) When true, includes hidden folders. # @return [Array(Array(Hash), String, String)] The list of folders, API Request ID, and next cursor. def list(identifier:, query_params: nil) diff --git a/spec/nylas/resources/folders_spec.rb b/spec/nylas/resources/folders_spec.rb index e226cb5e..ab078c39 100644 --- a/spec/nylas/resources/folders_spec.rb +++ b/spec/nylas/resources/folders_spec.rb @@ -35,9 +35,35 @@ expect(folders_response).to eq(list_response) end - it "calls the get method with the correct query parameters including include_hidden_folders" do + it "calls the get method with query parameters including single_level" do identifier = "abc-123-grant-id" - query_params = { include_hidden_folders: true } + query_params = { single_level: true } + path = "#{api_uri}/v3/grants/#{identifier}/folders" + allow(folders).to receive(:get_list) + .with(path: path, query_params: query_params) + .and_return(list_response) + + folders_response = folders.list(identifier: identifier, query_params: query_params) + + expect(folders_response).to eq(list_response) + end + + it "calls the get method with query parameters including single_level set to false" do + identifier = "abc-123-grant-id" + query_params = { single_level: false } + path = "#{api_uri}/v3/grants/#{identifier}/folders" + allow(folders).to receive(:get_list) + .with(path: path, query_params: query_params) + .and_return(list_response) + + folders_response = folders.list(identifier: identifier, query_params: query_params) + + expect(folders_response).to eq(list_response) + end + + it "calls the get method with multiple query parameters including single_level" do + identifier = "abc-123-grant-id" + query_params = { single_level: true, limit: 10, include_hidden_folders: true } path = "#{api_uri}/v3/grants/#{identifier}/folders" allow(folders).to receive(:get_list) .with(path: path, query_params: query_params)