MangoApps Ruby SDK

A clean, Ruby SDK for MangoApps APIs with OAuth2/OpenID Connect authentication.

Installation

Add this line to your application's Gemfile:

gem "mangoapps-ex-sdk-ruby"

And then execute:

bundle install

Or install it directly:

gem install mangoapps-ex-sdk-ruby

Basic Usage Example

require 'mangoapps-ex-sdk-ruby'

# Initialize client
client = MangoApps::Client.new

# Get user profile
user = client.me
puts "Hello, #{user.name}!"

# Get OAuth user info (from OAuth userinfo endpoint)
userinfo = client.get_userinfo
puts "OAuth User: #{userinfo.name} (#{userinfo.email})"
puts "Username: #{userinfo.preferred_username}"
puts "Subject ID: #{userinfo.sub}"

# Get priority items
priority_items = client.my_priority_items
puts "You have #{priority_items.data.length} priority items:"
priority_items.data.each do |item|
  puts "#{item.title}: #{item.count} pending"
end

# Get available courses
courses = client.course_catalog
puts "Available courses: #{courses.courses.length}"

# Get activity feeds
feeds = client.feeds(offset: 0, limit: 20, all_comments: 'Y')
puts "Activity feeds: #{feeds.feeds.length} (unread: #{feeds.unread_counts.unread_feeds_count})"

# Get all posts
posts = client.get_all_posts(filter_by: "all", offset: 0, limit: 20)
puts "All posts: #{posts.feeds.length}"

# Get post details by ID
if posts.feeds.any?
  post_id = posts.feeds.first.post_id
  post_details = client.get_post_by_id(post_id, full_description: "Y")
  puts "Post details: #{post_details.post.title}"
end

# Get user libraries
libraries = client.get_libraries(offset: 0, limit: 20)
puts "User libraries: #{libraries.libraries.length}"

# Get library categories by ID
if libraries.libraries.any?
  library_id = libraries.libraries.first.id
  library_details = client.get_library_categories(library_id, offset: 0, limit: 20)
  puts "Library details: #{library_details.library.name}"

  # Get library items from first category
  if library_details.library.categories.any?
    category_id = library_details.library.categories.first.id
    library_items = client.get_library_items(library_id, category_id, offset: 0, limit: 20)
    puts "Library items: #{library_items.library_items.length} items in #{library_items.category_name}"
  end
end

# Get user trackers
trackers = client.get_trackers(page: 1, limit: 20)
puts "User trackers: #{trackers.trackers.length}"

# Get user folders (no pagination)
folders = client.get_folders
puts "User folders: #{folders.folders.length}"

# Get files from first folder with content (no pagination)
if folders.folders.any?
  folder_with_content = folders.folders.find { |f| f.child_count.to_i > 0 }
  if folder_with_content
    folder_files = client.get_folder_files(folder_with_content.id, include_folders: "Y")
    puts "Folder files: #{folder_files.files.length} items in #{folder_files.name}"
  end
end

# Get user tasks
tasks = client.get_tasks(filter: "Pending_Tasks", page: 1, limit: 3)
puts "User tasks: #{tasks.tasks.task.length}"

# Get detailed information for a specific task
if tasks.tasks.task.any?
  first_task = tasks.tasks.task.first
  task_id = first_task.is_a?(Array) ? first_task[1] : first_task.id
  task_details = client.get_task_details(task_id)
  puts "Task details: #{task_details.task.task_title} (Status: #{task_details.task.status})"
end

# Get user wikis
wikis = client.get_wikis(mode: "my", offset: 0, limit: 5)
puts "User wikis: #{wikis.wikis.length}"

# Get detailed information for the first wiki
if wikis.wikis.any?
  first_wiki = wikis.wikis.first
  wiki_details = client.get_wiki_details(first_wiki.id)
  puts "Wiki details: #{wiki_details.wiki.details.title} (Read count: #{wiki_details.wiki.details.total_read_count})"
end

Pagination Support

Most list APIs support optional pagination parameters for efficient data retrieval:

# Basic usage with default pagination
posts = client.get_all_posts
courses = client.course_catalog

# Pagination with custom offset and limit (offset-based)
posts = client.get_all_posts(filter_by: "all", offset: 20, limit: 10)
courses = client.course_catalog(page: 1, limit: 5)

# Pagination with custom page and limit (page-based)
tasks = client.get_tasks(filter: "Pending_Tasks", page: 1, limit: 10)
trackers = client.get_trackers(page: 1, limit: 15)

# Library items with offset-based pagination
items = client.get_library_items(library_id, category_id, offset: 0, limit: 15)

Pagination Types:

  • Offset-based APIs: get_all_posts, get_libraries, get_library_categories, get_library_items, notifications, get_wikis, feeds
  • Page-based APIs: course_catalog, get_tasks, get_trackers
  • Non-paginated APIs: course_categories, award_categories, get_awards_list, get_folders, get_folder_files

Default Pagination Values:

  • Offset-based: offset: 0, limit: 20
  • Page-based: page: 1, limit: 20
  • Tasks: page: 1, limit: 5 (smaller default for task management)
  • Posts: offset: 0, limit: 20 with filter_by: "all"

Available Modules

✅ Currently Implemented

Users Module

  • User Profile: client.me - Get current user information with clean dot notation access

Learn Module

  • Course Catalog: client.course_catalog - Get available courses
  • Course Categories: client.course_categories - Get course categories
  • Course Details: client.course_details(course_id) - Get detailed course information by ID
  • My Learning: client.my_learning - Get user's learning progress and courses

Recognitions Module

  • Award Categories: client.award_categories - Get recognition award categories
  • Get Awards List: client.get_awards_list(category_id: id) - Get awards for a specific category
  • Get Profile Awards: client.get_profile_awards - Get user's personal awards and activity
  • Core Value Tags: client.core_value_tags - Get core value tags for recognition
  • Leaderboard Info: client.leaderboard_info - Get user and team leaderboard information

Notifications Module

  • My Priority Items: client.my_priority_items - Get user's priority items including requests, events, quizzes, surveys, tasks, and todos
  • Notifications: client.notifications - Get user's notifications with unread counts and detailed notification information

Feeds Module

  • Feeds: client.feeds - Get user's activity feeds with unread counts and feed details

Posts Module

  • Get All Posts: client.get_all_posts(filter_by: "all") - Get all posts with filtering options
  • Get Post By ID: client.get_post_by_id(post_id, full_description: "Y") - Get detailed post information by ID

Libraries Module

  • Get Libraries: client.get_libraries - Get user's document libraries with categories and items
  • Get Library Categories: client.get_library_categories(library_id) - Get detailed library information and categories by library ID
  • Get Library Items: client.get_library_items(library_id, category_id) - Get library items by library ID and category ID

Trackers Module

  • Get Trackers: client.get_trackers - Get user's trackers with submission dates and conversation details

Attachments Module

  • Get Folders: client.get_folders - Get user's file folders with permissions and metadata
  • Get Folder Files: client.get_folder_files(folder_id, include_folders: "Y") - Get files and folders inside a specific folder

Tasks Module

  • Get Tasks: client.get_tasks(filter: "Pending_Tasks", page: 1, limit: 5) - Get user's tasks with filtering, pagination, and detailed task information
  • Get Task Details: client.get_task_details(task_id) - Get detailed information for a specific task by ID

Wikis Module

  • Get Wikis: client.get_wikis(mode: "my", limit: 20, offset: 0) - Get user's wikis with filtering, pagination, and detailed wiki information
  • Get Wiki Details: client.get_wiki_details(wiki_id) - Get detailed information for a specific wiki by ID

Complete Examples

Notifications Management

require 'mangoapps-ex-sdk-ruby'

# Initialize client
client = MangoApps::Client.new

# Get user's priority items
priority_items = client.my_priority_items

# Display all priority items with details
puts "🔔 User Priority Items Dashboard"
puts "================================"
puts "Success: #{priority_items.success}"
puts "Display Type: #{priority_items.display_type}"
puts ""

priority_items.data.each do |item|
  puts "📋 #{item.title} (ID: #{item.id})"
  puts "   Count: #{item.count} pending items"
  puts "   Action Type: #{item.action_type}"
  puts "   Icon: #{item.icon} (#{item.icon_color})"
  puts "   Background: #{item.icon_bg_color}"
  puts "   Description: #{item.info_details.gsub(/<[^>]*>/, '').strip[0..100]}..."
  puts ""
end

# Get user's notifications
notifications = client.notifications

# Display notifications dashboard
puts "🔔 User Notifications Dashboard"
puts "==============================="
puts "What's new: #{notifications.whats_new_count}"
puts "Unread feeds: #{notifications.unread_feeds_count}"
puts "Mentions: #{notifications.mention_count}"
puts "Direct messages: #{notifications.direct_messages_count}"
puts "Unread notifications: #{notifications.unread_notification_count}"
puts ""

notifications.notifications.first(5).each do |notification|
  puts "📢 #{notification.sender_name} (ID: #{notification.id})"
  puts "   Text: #{notification.text[0..100]}..."
  puts "   Type: #{notification.notification_type || 'None'}"
  puts "   Read: #{notification.is_read} | Updated: #{Time.at(notification.updated_at.to_i).strftime('%Y-%m-%d %H:%M:%S')}"
  puts "   MLink: #{notification.mlink || 'None'}"
  if notification.mention_tags && notification.mention_tags.any?
    puts "   Mentions: #{notification.mention_tags.map { |tag| tag.mention }.join(', ')}"
  end
  puts ""
end

# Filter by specific action types
approval_items = priority_items.data.select { |item| item.action_type == 'approval' }
puts "🔍 Approval Items: #{approval_items.length}"
approval_items.each do |item|
  puts "#{item.title}: #{item.count} items"
end

# Get high-priority items (count > 5)
high_priority = priority_items.data.select { |item| item.count > 5 }
puts "⚠️  High Priority Items: #{high_priority.length}"
high_priority.each do |item|
  puts "#{item.title}: #{item.count} items"
end

User Profile Management

# Get current user profile
user = client.me

# Access user information with clean dot notation
puts "Name: #{user..minimal_profile.name}"
puts "Email: #{user..minimal_profile.email}"
puts "User Type: #{user..minimal_profile.user_type}"

# Access user statistics
puts "Followers: #{user..user_data.followers}"
puts "Following: #{user..user_data.following}"

# Access gamification data
puts "Current Level: #{user..gamification.current_level}"
puts "Total Points: #{user..gamification.total_points}"
puts "Badges: #{user..gamification.badges.length}"

# Access recognition data
puts "Reward Points Received: #{user..recognition.total_reward_points_received}"

Learning Management

# Get course catalog
courses = client.course_catalog

# Browse available courses
courses.courses.each do |course|
  puts "📚 #{course.name}"
  puts "   Type: #{course.course_type}"
  puts "   Delivery: #{course.delivery_mode}"
  puts "   URL: #{course.start_course_url}"
  puts ""

  # Get detailed course information
  course_details = client.course_details(course.id)
  detailed_course = course_details.course
  puts "   📖 Detailed Info:"
  puts "   Description: #{detailed_course.description}"
  puts "   Instructors: #{detailed_course.instructors.length}"
  puts "   Fields: #{detailed_course.fields.length}"
  puts ""
end

# Get course categories
categories = client.course_categories

# Browse course categories
categories.all_categories.each do |category|
  puts "📂 #{category.name}"
  puts "   Position: #{category.position}"
  puts "   Icon: #{category.icon_properties}"
  puts ""
end

# Get user's learning progress
learning = client.my_learning

# Display learning summary
puts "🎓 Learning Summary for #{learning.user_name}"
puts "⏱️ Total training time: #{learning.total_training_time}"
puts "📚 Ongoing: #{learning.ongoing_course_count} | ✅ Completed: #{learning.completed_course_count} | 📝 Registered: #{learning.registered_course_count}"
puts ""

# Browse learning sections
learning.section.each do |section|
  puts "📂 #{section.label} (#{section.count} courses)"

  section.courses.each do |course|
    puts "  📚 #{course.name}"
    puts "     Progress: #{course.course_progress}%"
    puts "     Type: #{course.course_type}"
    puts "     URL: #{course.start_course_url}"
    puts ""
  end
end

Recognition Management

# Get award categories
categories = client.award_categories

# Display available award categories
puts "🏆 Available Award Categories:"
categories.award_categories.each do |category|
  puts "#{category.name} (ID: #{category.id})"
  puts "    Permission: #{category.recipient_permission}"
end
puts ""

# Get awards for a specific category
category_id = 4303  # Safety & Quality category
awards = client.get_awards_list(category_id: category_id)

# Display awards in the category
puts "🏆 Awards in Category #{category_id}:"
awards.get_awards_list.each do |award|
  puts "#{award.name} (ID: #{award.id})"
  puts "    Points: #{award.points} | Reward Points: #{award.reward_points || 'None'}"
  puts "    Description: #{award.description}"
end
puts ""

# Get user profile awards
profile_awards = client.get_profile_awards

# Display user's personal awards
puts "🏆 User Profile Awards:"
puts "  Core Value Tags:"
profile_awards.core_value_tags.each do |tag|
  puts "#{tag.name} (ID: #{tag.id}) - Count: #{tag.count}"
end
puts "  Recent Awards:"
profile_awards.feeds.each do |feed|
  puts "#{feed.feed_property.title} - Points: #{feed.recognition_points}"
  puts "      From: #{feed.from_user.name}"
end
puts ""


# Get user priority items
priority_items = client.my_priority_items

# Display priority items
puts "🔔 User Priority Items:"
priority_items.data.each do |item|
  puts "#{item.title} (ID: #{item.id}) - Count: #{item.count}"
  puts "    Action Type: #{item.action_type} | Icon: #{item.icon}"
end
puts ""

# Get user activity feeds
feeds = client.feeds

# Display feeds
puts "📰 User Activity Feeds:"
puts "  Total feeds: #{feeds.feeds.length}"
puts "  Unread feeds: #{feeds.unread_counts.unread_feeds_count}"
puts "  Direct messages: #{feeds.unread_counts.direct_messages_count}"
puts "  What's new: #{feeds.unread_counts.whats_new_count}"
puts ""

# Display recent feeds
puts "📰 Recent Feeds:"
feeds.feeds.first(3).each do |feed|
  puts "#{feed.feed_property.title} (ID: #{feed.id})"
  puts "    From: #{feed.from_user.name} | Group: #{feed.group_name}"
  puts "    Type: #{feed.feed_type} | Unread: #{feed.unread}"
end
puts ""

# Get all posts
posts = client.get_all_posts(filter_by: "all")

# Display posts
puts "📝 All Posts:"
puts "  Total posts: #{posts.feeds.length}"
puts "  Post view count visibility: #{posts.post_view_count_visibility}"
puts ""

# Display recent posts
puts "📝 Recent Posts:"
posts.feeds.first(3).each do |post|
  puts "#{post.tile.tile_name} (ID: #{post.id})"
  puts "    From: #{post.from_user.name} | Group: #{post.group_name}"
  puts "    Views: #{post.total_view_count} | Comments: #{post.comments.length}"
end
puts ""

# Get detailed post information
if posts.feeds.any?
  first_post_id = posts.feeds.first.post_id
  post_details = client.get_post_by_id(first_post_id, full_description: "Y")

  puts "📝 Post Details (ID: #{first_post_id}):"
  puts "  Title: #{post_details.post.title}"
  puts "  Created by: #{post_details.post.created_name}"
  puts "  View count: #{post_details.post.total_view_count}"
  puts "  Can edit: #{post_details.post.can_edit} | Can comment: #{post_details.post.can_comment}"
  puts "  Full description available: #{post_details.post.tile.tile_full_description.length > 0 ? 'Yes' : 'No'}"
end
puts ""

# Get user libraries
libraries = client.get_libraries

puts "📚 User Libraries:"
puts "  Total libraries: #{libraries.libraries.length}"
puts ""

# Display recent libraries
puts "📚 Recent Libraries:"
libraries.libraries.first(3).each do |library|
  puts "#{library.name} (ID: #{library.id})"
  puts "    Type: #{library.library_type} | Items: #{library.total_items_count}"
  puts "    Categories: #{library.categories.length} | Edit access: #{library.edit_access}"
end
puts ""

# Get detailed library information
if libraries.libraries.any?
  first_library_id = libraries.libraries.first.id
  library_details = client.get_library_categories(first_library_id)

  puts "📚 Library Details (ID: #{first_library_id}):"
  puts "  Name: #{library_details.library.name}"
  puts "  Type: #{library_details.library.library_type} | View: #{library_details.library.view_mode}"
  puts "  Total items: #{library_details.library.total_items_count}"
  puts "  Categories: #{library_details.library.categories.length}"
  puts "  Edit access: #{library_details.library.edit_access}"

  # Get library items from first category
  if library_details.library.categories.any?
    first_category_id = library_details.library.categories.first.id
    library_items = client.get_library_items(first_library_id, first_category_id)

    puts "📚 Library Items (Category: #{library_items.category_name}):"
    puts "  View mode: #{library_items.view_mode} | Library type: #{library_items.library_type}"
    puts "  Items count: #{library_items.library_items.length}"
    puts "  Can add: #{library_items.can_add}"
  end
end
puts ""

# Get user trackers
trackers = client.get_trackers

puts "📊 User Trackers:"
puts "  Total trackers: #{trackers.trackers.length}"
puts ""

# Display recent trackers
puts "📊 Recent Trackers:"
trackers.trackers.first(3).each do |tracker|
  puts "#{tracker.name} (ID: #{tracker.id})"
  puts "    Last submission: #{Time.at(tracker.last_submission_date.to_i).strftime('%Y-%m-%d %H:%M:%S')}"
  puts "    Conversation: #{tracker.conversation_name}"
  puts "    Pinned: #{tracker.is_pinned} | Can share: #{tracker.can_share}"
end
puts ""

# Get user folders
folders = client.get_folders

puts "📁 User Folders:"
puts "  Total folders: #{folders.folders.length}"
puts ""

# Display first few folders
puts "📁 Available Folders:"
folders.folders.first(3).each do |folder|
  puts "#{folder.name} (ID: #{folder.id})"
  puts "    Path: #{folder.relativePath} | Child count: #{folder.child_count}"
  puts "    Can save: #{folder.can_save} | Pinned: #{folder.is_pinned}"
end
puts ""

# Get files from first folder with content
if folders.folders.any?
  folder_with_content = folders.folders.find { |f| f.child_count.to_i > 0 }
  if folder_with_content
    folder_files = client.get_folder_files(folder_with_content.id, include_folders: "Y")
    puts "📁 Folder Files:"
    puts "  Folder: #{folder_files.name} | Total: #{folder_files.total_count}"
    puts "  Role: #{folder_files.role_name} | Upload enabled: #{folder_files.show_in_upload}"
  end
end
puts ""

# Get user tasks
tasks = client.get_tasks(filter: "Pending_Tasks", page: 1, limit: 3)

puts "📋 User Tasks:"
puts "  Total tasks: #{tasks.tasks.task.length}"
puts ""

# Display first few tasks
puts "📋 Recent Tasks:"
tasks.tasks.task.first(3).each do |task|
  puts "#{task.task_title} (ID: #{task.id})"
  puts "    Status: #{task.status} | Assigned to: #{task.assigned_to_name}"
  puts "    Due: #{task.due_on ? Time.at(task.due_on.to_i).strftime('%Y-%m-%d') : 'None'}"
  puts "    Is overdue: #{task.is_overdue} | Priority: #{task.personal_priority}"
end
puts ""

# Get detailed information for the first task
if tasks.tasks.task.any?
  first_task = tasks.tasks.task.first
  task_id = first_task.is_a?(Array) ? first_task[1] : first_task.id
  task_details = client.get_task_details(task_id)

  puts "📋 Task Details:"
  puts "  Task: #{task_details.task.task_title} (ID: #{task_details.task.id})"
  puts "  Status: #{task_details.task.status} | Bucket: #{task_details.task.bucket}"
  puts "  Assigned to: #{task_details.task.assigned_to_name} | Created by: #{task_details.task.creator_name}"
  puts "  Due: #{task_details.task.due_on ? Time.at(task_details.task.due_on.to_i).strftime('%Y-%m-%d') : 'None'}"
  puts "  Is overdue: #{task_details.task.is_overdue} | Priority: #{task_details.task.personal_priority}"
  puts "  Milestone: #{task_details.task.milestone_name || 'None'}"
  puts "  Project: #{task_details.task.conversation_name}"
  puts "  Visibility: #{task_details.task.visibility}"

  # Show reviewers
  if task_details.task.reviewers && task_details.task.reviewers.reviewer
    reviewers = task_details.task.reviewers.reviewer
    puts "  Reviewers: #{reviewers.length} reviewers"
  end

  # Show next actions
  if task_details.task.next_actions && task_details.task.next_actions.action
    actions = task_details.task.next_actions.action
    puts "  Available actions: #{actions.join(', ')}"
  end
end
puts ""

# Get user wikis
wikis = client.get_wikis(mode: "my", limit: 5, offset: 0)

puts "📚 User Wikis:"
puts "  Total wikis: #{wikis.wikis.length}"
puts ""

# Display first few wikis
puts "📚 Recent Wikis:"
wikis.wikis.first(3).each do |wiki|
  puts "#{wiki.title} (ID: #{wiki.id})"
  puts "    Updated: #{Time.at(wiki.updated_at.to_i).strftime('%Y-%m-%d')}"
  puts "    Children: #{wiki.children_count} | Can edit: #{wiki.can_edit}"
  puts "    Conversation: #{wiki.conversation_name || 'None'} (ID: #{wiki.conversation_id})"
  puts "    Is draft: #{wiki.is_draft} | PDF access: #{wiki.generate_pdf_access}"
end
puts ""

# Get detailed information for the first wiki
if wikis.wikis.any?
  first_wiki = wikis.wikis.first
  wiki_details = client.get_wiki_details(first_wiki.id)

  puts "📚 Wiki Details:"
  puts "  Wiki: #{wiki_details.wiki.details.title} (ID: #{wiki_details.wiki.details.id})"
  puts "  Status: #{wiki_details.wiki.details.status} | Platform: #{wiki_details.wiki.details.platform}"
  puts "  Created by: #{wiki_details.wiki.details.created_by_name} | Updated by: #{wiki_details.wiki.details.updated_by_name}"
  puts "  Read count: #{wiki_details.wiki.details.total_read_count} | Children: #{wiki_details.wiki.details.children_count}"
  puts "  Conversation: #{wiki_details.wiki.details.conversation_name}"
  puts "  Edit permissions: #{wiki_details.wiki.details.edit_permissions} | Commentable: #{wiki_details.wiki.details.is_commentable}"
  puts "  Generate PDF access: #{wiki_details.wiki.details.generate_pdf_access} | Show TOC: #{wiki_details.wiki.details.show_toc}"
  puts "  Archived: #{wiki_details.wiki.details.archived} | Is draft: #{wiki_details.wiki.is_draft}"

  # Show permissions
  puts "  Permissions: Comment: #{wiki_details.wiki.can_comment}, Edit: #{wiki_details.wiki.can_edit}, Delete: #{wiki_details.wiki.can_delete}"

  # Show reactions
  if wiki_details.wiki.reactions
    reactions = wiki_details.wiki.reactions
    puts "  Reactions: Like: #{reactions.like_count}, Superlike: #{reactions.superlike_count}"
  end

  # Show comment count
  puts "  Comment count: #{wiki_details.wiki.comment_count}"
end
puts ""


# Get core value tags
tags = client.core_value_tags

# Display core value tags
puts "🎯 Core Value Tags:"
tags.core_value_tags.each do |tag|
  puts "#{tag.name} (ID: #{tag.id})"
  puts "    Color: ##{tag.color}"
end
puts ""

# Get leaderboard information
leaderboard = client.leaderboard_info

# Display leaderboard if available
if leaderboard.leaderboard_info
  puts "🏅 User Leaderboard:"
  leaderboard.leaderboard_info..each do |user|
    puts "  #{user.rank}. #{user.name} - #{user.award_count} awards"
  end
  puts ""

  puts "🏆 Team Leaderboard:"
  leaderboard.leaderboard_info.team_info.each do |team|
    puts "  #{team.rank}. #{team.name} - #{team.award_count} awards"
  end
else
  puts "📊 No leaderboard data configured"
end

Error Handling with Clean Responses

begin
  user = client.me

  # Clean dot notation access
  puts "Welcome, #{user..minimal_profile.name}!"

rescue MangoApps::AuthenticationError => e
  puts "Authentication failed: #{e.message}"
  # Redirect to OAuth flow

rescue MangoApps::APIError => e
  puts "API error: #{e.message}"
  puts "Status: #{e.status_code}"

rescue MangoApps::RateLimitError => e
  puts "Rate limited: #{e.message}"
  # Implement backoff strategy
end

Error Handling

The SDK provides specific exception types for different error scenarios:

begin
  posts = client.posts_list
rescue MangoApps::AuthenticationError => e
  puts "Authentication failed: #{e.message}"
rescue MangoApps::APIError => e
  puts "API error: #{e.message}"
rescue MangoApps::RateLimitError => e
  puts "Rate limited: #{e.message}"
end

# OAuth-specific error handling
begin
  userinfo = client.get_userinfo
rescue MangoApps::TokenExpiredError => e
  puts "OAuth token expired: #{e.message}"
  # Refresh token or redirect to OAuth flow
rescue MangoApps::APIError => e
  puts "OAuth userinfo error: #{e.message}"
end

Available Exception Types

  • MangoApps::Error - Base error class
  • MangoApps::APIError - General API errors
  • MangoApps::AuthenticationError - Authentication failures
  • MangoApps::TokenExpiredError - Token expiration
  • MangoApps::DiscoveryError - OAuth discovery endpoint errors
  • MangoApps::TokenExchangeError - OAuth token exchange errors
  • MangoApps::BadRequestError - 400 errors
  • MangoApps::UnauthorizedError - 401 errors
  • MangoApps::ForbiddenError - 403 errors
  • MangoApps::NotFoundError - 404 errors
  • MangoApps::RateLimitError - 429 errors
  • MangoApps::ServerError - 5xx errors

Configuration Options

config = MangoApps::Config.new(
  domain: "yourdomain.mangoapps.com",
  client_id: "your_client_id",
  client_secret: "your_client_secret",
  redirect_uri: "https://localhost:3000/oauth/callback",
  scope: "openid profile email",
  timeout: 30,
  open_timeout: 10,
  logger: Logger.new(STDOUT)
)

# OAuth-specific configuration
# - All OAuth endpoints automatically use HTTPS
# - Automatic redirect handling for 301/302 responses
# - SSL certificate verification enabled

Current API Coverage

  • Learn Module: Course catalog, categories, course details, and my learning (4 endpoints)
  • Users Module: User profile and authentication (1 endpoint)
  • Recognitions Module: Award categories, get awards list, get profile awards, core value tags, and leaderboard info (5 endpoints)
  • Notifications Module: My priority items for requests, events, quizzes, surveys, tasks, and todos, and user notifications with unread counts (2 endpoints)
  • Feeds Module: User activity feeds with unread counts and feed details (1 endpoint)
  • Posts Module: Get all posts with filtering options and get post by ID (2 endpoints)
  • Libraries Module: Get user's document libraries with categories and items, get library categories by ID, and get library items by library and category ID (3 endpoints)
  • Trackers Module: Get user's trackers with submission dates and conversation details (1 endpoint)
  • Attachments Module: Get user's file folders with permissions and metadata, and get files and folders inside specific folders (2 endpoints)
  • Tasks Module: Get user's tasks with filtering, pagination, and detailed task information, and get detailed information for specific tasks (2 endpoints)
  • Wikis Module: Get user's wikis with filtering, pagination, and detailed wiki information, and get detailed information for specific wikis (2 endpoints)
  • Error Handling: Comprehensive error logging and testing
  • OAuth Flow: Token management, refresh, and userinfo endpoint
  • Internal API Auth: Alternative authentication using API keys
  • Auto Detection: Automatic authentication method detection and prioritization
  • Pagination Support: Optional page and limit parameters for all list APIs
  • HTTPS Security: Automatic HTTPS enforcement with redirect handling

Total: 26 API endpoints across 11 modules + OAuth + Internal API + Auto Detection + Pagination

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Write real tests first (no mocking)
  4. Implement the feature
  5. Ensure all tests pass
  6. Submit a pull request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Changelog

See CHANGELOG.md for a list of changes and version history.