mangoapps-ex-sdk-ruby 0.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +506 -0
- data/LICENSE +201 -0
- data/README.md +2040 -0
- data/lib/mangoapps/client.rb +219 -0
- data/lib/mangoapps/config.rb +98 -0
- data/lib/mangoapps/errors.rb +45 -0
- data/lib/mangoapps/modules/attachments/get_folder_files.rb +14 -0
- data/lib/mangoapps/modules/attachments/get_folders.rb +14 -0
- data/lib/mangoapps/modules/attachments.rb +14 -0
- data/lib/mangoapps/modules/feeds/feeds.rb +14 -0
- data/lib/mangoapps/modules/feeds.rb +12 -0
- data/lib/mangoapps/modules/learn/course_catalog.rb +16 -0
- data/lib/mangoapps/modules/learn/course_categories.rb +16 -0
- data/lib/mangoapps/modules/learn/course_details.rb +13 -0
- data/lib/mangoapps/modules/learn/my_learning.rb +13 -0
- data/lib/mangoapps/modules/learn.rb +18 -0
- data/lib/mangoapps/modules/libraries/get_libraries.rb +14 -0
- data/lib/mangoapps/modules/libraries/get_library_categories.rb +14 -0
- data/lib/mangoapps/modules/libraries/get_library_items.rb +14 -0
- data/lib/mangoapps/modules/libraries.rb +16 -0
- data/lib/mangoapps/modules/notifications/my_priority_items.rb +13 -0
- data/lib/mangoapps/modules/notifications/notifications.rb +14 -0
- data/lib/mangoapps/modules/notifications.rb +14 -0
- data/lib/mangoapps/modules/posts/get_all_posts.rb +14 -0
- data/lib/mangoapps/modules/posts/get_post_by_id.rb +13 -0
- data/lib/mangoapps/modules/posts.rb +14 -0
- data/lib/mangoapps/modules/recognitions/award_categories.rb +14 -0
- data/lib/mangoapps/modules/recognitions/core_value_tags.rb +13 -0
- data/lib/mangoapps/modules/recognitions/get_award_feeds.rb +14 -0
- data/lib/mangoapps/modules/recognitions/get_awards_list.rb +14 -0
- data/lib/mangoapps/modules/recognitions/get_profile_awards.rb +13 -0
- data/lib/mangoapps/modules/recognitions/get_team_awards.rb +13 -0
- data/lib/mangoapps/modules/recognitions/gift_cards.rb +13 -0
- data/lib/mangoapps/modules/recognitions/leaderboard_info.rb +13 -0
- data/lib/mangoapps/modules/recognitions.rb +26 -0
- data/lib/mangoapps/modules/tasks/get_task_details.rb +13 -0
- data/lib/mangoapps/modules/tasks/get_tasks.rb +14 -0
- data/lib/mangoapps/modules/tasks.rb +14 -0
- data/lib/mangoapps/modules/trackers/get_trackers.rb +14 -0
- data/lib/mangoapps/modules/trackers.rb +12 -0
- data/lib/mangoapps/modules/users.rb +11 -0
- data/lib/mangoapps/modules/wikis/get_wiki_details.rb +13 -0
- data/lib/mangoapps/modules/wikis/get_wikis.rb +14 -0
- data/lib/mangoapps/modules/wikis.rb +14 -0
- data/lib/mangoapps/oauth.rb +187 -0
- data/lib/mangoapps/response.rb +92 -0
- data/lib/mangoapps/version.rb +5 -0
- data/lib/mangoapps.rb +34 -0
- metadata +181 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MangoApps
|
4
|
+
class Client
|
5
|
+
module Recognitions
|
6
|
+
module AwardCategories
|
7
|
+
def award_categories(page: 1, limit: 20, params: {})
|
8
|
+
params = params.merge(page: page, limit: limit)
|
9
|
+
get("v2/recognitions/get_award_categories.json", params: params)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MangoApps
|
4
|
+
class Client
|
5
|
+
module Recognitions
|
6
|
+
module GetAwardFeeds
|
7
|
+
def get_award_feeds(page: 1, limit: 20, params: {})
|
8
|
+
params = params.merge(page: page, limit: limit)
|
9
|
+
get("v2/recognitions/get_award_feeds.json", params: params)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MangoApps
|
4
|
+
class Client
|
5
|
+
module Recognitions
|
6
|
+
module GetAwardsList
|
7
|
+
def get_awards_list(category_id, page: 1, limit: 20, params: {})
|
8
|
+
params = params.merge(category_id: category_id, page: page, limit: limit)
|
9
|
+
get("v2/recognitions/get_awards_list.json", params: params)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "recognitions/award_categories"
|
4
|
+
require_relative "recognitions/core_value_tags"
|
5
|
+
require_relative "recognitions/leaderboard_info"
|
6
|
+
require_relative "recognitions/gift_cards"
|
7
|
+
require_relative "recognitions/get_awards_list"
|
8
|
+
require_relative "recognitions/get_profile_awards"
|
9
|
+
require_relative "recognitions/get_team_awards"
|
10
|
+
require_relative "recognitions/get_award_feeds"
|
11
|
+
|
12
|
+
module MangoApps
|
13
|
+
class Client
|
14
|
+
module Recognitions
|
15
|
+
# Include all recognitions sub-modules
|
16
|
+
include MangoApps::Client::Recognitions::AwardCategories
|
17
|
+
include MangoApps::Client::Recognitions::CoreValueTags
|
18
|
+
include MangoApps::Client::Recognitions::LeaderboardInfo
|
19
|
+
include MangoApps::Client::Recognitions::GiftCards
|
20
|
+
include MangoApps::Client::Recognitions::GetAwardsList
|
21
|
+
include MangoApps::Client::Recognitions::GetProfileAwards
|
22
|
+
include MangoApps::Client::Recognitions::GetTeamAwards
|
23
|
+
include MangoApps::Client::Recognitions::GetAwardFeeds
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MangoApps
|
4
|
+
class Client
|
5
|
+
module Tasks
|
6
|
+
module GetTasks
|
7
|
+
def get_tasks(filter: "Pending_Tasks", page: 1, limit: 5, params: {})
|
8
|
+
params = params.merge(filter: filter, page: page, limit: limit)
|
9
|
+
get("tasks/new_index.json", params: params)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "tasks/get_tasks"
|
4
|
+
require_relative "tasks/get_task_details"
|
5
|
+
|
6
|
+
module MangoApps
|
7
|
+
class Client
|
8
|
+
module Tasks
|
9
|
+
# Include all tasks sub-modules
|
10
|
+
include MangoApps::Client::Tasks::GetTasks
|
11
|
+
include MangoApps::Client::Tasks::GetTaskDetails
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MangoApps
|
4
|
+
class Client
|
5
|
+
module Trackers
|
6
|
+
module GetTrackers
|
7
|
+
def get_trackers(page: 1, limit: 20, params: {})
|
8
|
+
params = params.merge(page: page, limit: limit)
|
9
|
+
get("v2/trackers.json", params: params)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MangoApps
|
4
|
+
class Client
|
5
|
+
module Wikis
|
6
|
+
module GetWikis
|
7
|
+
def get_wikis(mode: "my", page: 1, limit: 20, params: {})
|
8
|
+
params = params.merge(mode: mode, page: page, limit: limit)
|
9
|
+
get("v2/wikis.json", params: params)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "wikis/get_wikis"
|
4
|
+
require_relative "wikis/get_wiki_details"
|
5
|
+
|
6
|
+
module MangoApps
|
7
|
+
class Client
|
8
|
+
module Wikis
|
9
|
+
# Include all wikis sub-modules
|
10
|
+
include MangoApps::Client::Wikis::GetWikis
|
11
|
+
include MangoApps::Client::Wikis::GetWikiDetails
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "oauth2"
|
4
|
+
require "json"
|
5
|
+
require "net/http"
|
6
|
+
require "uri"
|
7
|
+
|
8
|
+
module MangoApps
|
9
|
+
class OAuth
|
10
|
+
Discovery = Struct.new(:issuer, :authorization_endpoint, :token_endpoint, :userinfo_endpoint,
|
11
|
+
:end_session_endpoint, :jwks_uri)
|
12
|
+
|
13
|
+
def initialize(config)
|
14
|
+
@config = config
|
15
|
+
end
|
16
|
+
|
17
|
+
# Discover OIDC endpoints from well-known config
|
18
|
+
def discover!
|
19
|
+
# Ensure we always use HTTPS for discovery
|
20
|
+
base_url = @config.base_url
|
21
|
+
base_url = base_url.gsub(/^http:/, 'https:') unless base_url.start_with?('https:')
|
22
|
+
url = URI.parse("#{base_url}/.well-known/openid-configuration")
|
23
|
+
|
24
|
+
begin
|
25
|
+
# Use proper HTTPS handling for discovery
|
26
|
+
http = Net::HTTP.new(url.host, url.port)
|
27
|
+
http.use_ssl = (url.scheme == 'https')
|
28
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER if http.use_ssl?
|
29
|
+
|
30
|
+
request = Net::HTTP::Get.new(url)
|
31
|
+
res = http.request(request)
|
32
|
+
raise MangoApps::DiscoveryError, "OIDC discovery failed: #{res.code}" unless res.is_a?(Net::HTTPSuccess)
|
33
|
+
|
34
|
+
data = JSON.parse(res.body)
|
35
|
+
validate_discovery_data(data)
|
36
|
+
|
37
|
+
@discovery = Discovery.new(
|
38
|
+
data["issuer"],
|
39
|
+
data["authorization_endpoint"],
|
40
|
+
data["token_endpoint"],
|
41
|
+
data["userinfo_endpoint"],
|
42
|
+
data["end_session_endpoint"],
|
43
|
+
data["jwks_uri"]
|
44
|
+
)
|
45
|
+
rescue JSON::ParserError => e
|
46
|
+
raise MangoApps::DiscoveryError, "Invalid JSON response from discovery endpoint: #{e.message}"
|
47
|
+
rescue Net::ReadTimeout, Net::OpenTimeout, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Timeout::Error => e
|
48
|
+
raise MangoApps::DiscoveryError, "Failed to connect to discovery endpoint: #{e.message}"
|
49
|
+
rescue OpenSSL::SSL::SSLError => e
|
50
|
+
raise MangoApps::DiscoveryError, "SSL connection failed for discovery endpoint: #{e.message}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def discovery
|
55
|
+
@discovery || discover!
|
56
|
+
end
|
57
|
+
|
58
|
+
# OAuth2::Client using discovered endpoints
|
59
|
+
def client
|
60
|
+
@client ||= ::OAuth2::Client.new(
|
61
|
+
@config.client_id,
|
62
|
+
@config.client_secret,
|
63
|
+
site: @config.base_url,
|
64
|
+
authorize_url: discovery.authorization_endpoint,
|
65
|
+
token_url: discovery.token_endpoint
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Build an auth URL for browser-based login (PKCE optional)
|
70
|
+
def authorization_url(state:, code_challenge: nil, code_challenge_method: "S256", extra_params: {})
|
71
|
+
params = {
|
72
|
+
redirect_uri: @config.redirect_uri,
|
73
|
+
scope: @config.scope,
|
74
|
+
state: state,
|
75
|
+
response_type: "code",
|
76
|
+
}.merge(extra_params)
|
77
|
+
|
78
|
+
if code_challenge
|
79
|
+
params[:code_challenge] = code_challenge
|
80
|
+
params[:code_challenge_method] = code_challenge_method
|
81
|
+
end
|
82
|
+
|
83
|
+
client.auth_code.authorize_url(params)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Exchange code for tokens (PKCE verifier optional)
|
87
|
+
def get_token(authorization_code:, code_verifier: nil)
|
88
|
+
token = client.auth_code.get_token(
|
89
|
+
authorization_code,
|
90
|
+
redirect_uri: @config.redirect_uri,
|
91
|
+
headers: { "Content-Type" => "application/x-www-form-urlencoded" },
|
92
|
+
code_verifier: code_verifier
|
93
|
+
)
|
94
|
+
persist(token)
|
95
|
+
token
|
96
|
+
rescue OAuth2::Error => e
|
97
|
+
raise MangoApps::TokenExchangeError, "Token exchange failed: #{e.message}"
|
98
|
+
end
|
99
|
+
|
100
|
+
def refresh!(token)
|
101
|
+
raise MangoApps::TokenExpiredError, "No refresh_token available" unless token&.refresh_token
|
102
|
+
|
103
|
+
begin
|
104
|
+
new_token = token.refresh!
|
105
|
+
persist(new_token)
|
106
|
+
new_token
|
107
|
+
rescue OAuth2::Error => e
|
108
|
+
raise MangoApps::TokenExpiredError, "Token refresh failed: #{e.message}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def load_token
|
113
|
+
@config.token_store&.load
|
114
|
+
end
|
115
|
+
|
116
|
+
# Get user info from OAuth userinfo endpoint
|
117
|
+
def get_userinfo(access_token)
|
118
|
+
raise MangoApps::TokenExpiredError, "No access token provided" unless access_token
|
119
|
+
|
120
|
+
userinfo_url = discovery.userinfo_endpoint
|
121
|
+
# Ensure userinfo endpoint uses HTTPS
|
122
|
+
userinfo_url = userinfo_url.gsub(/^http:/, 'https:') unless userinfo_url.start_with?('https:')
|
123
|
+
url = URI.parse(userinfo_url)
|
124
|
+
|
125
|
+
begin
|
126
|
+
# Ensure we use the correct port for HTTPS
|
127
|
+
port = url.port || (url.scheme == 'https' ? 443 : 80)
|
128
|
+
http = Net::HTTP.new(url.host, port)
|
129
|
+
http.use_ssl = (url.scheme == 'https')
|
130
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER if http.use_ssl?
|
131
|
+
|
132
|
+
request = Net::HTTP::Get.new(url)
|
133
|
+
request['Authorization'] = "Bearer #{access_token}"
|
134
|
+
request['Accept'] = 'application/json'
|
135
|
+
|
136
|
+
response = http.request(request)
|
137
|
+
|
138
|
+
# Handle redirects (301, 302)
|
139
|
+
if response.is_a?(Net::HTTPRedirection)
|
140
|
+
redirect_url = response['location']
|
141
|
+
if redirect_url
|
142
|
+
# Follow the redirect with HTTPS
|
143
|
+
redirect_uri = URI.parse(redirect_url)
|
144
|
+
redirect_uri.scheme = 'https' if redirect_uri.scheme == 'http'
|
145
|
+
|
146
|
+
http = Net::HTTP.new(redirect_uri.host, redirect_uri.port)
|
147
|
+
http.use_ssl = (redirect_uri.scheme == 'https')
|
148
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER if http.use_ssl?
|
149
|
+
|
150
|
+
request = Net::HTTP::Get.new(redirect_uri)
|
151
|
+
request['Authorization'] = "Bearer #{access_token}"
|
152
|
+
request['Accept'] = 'application/json'
|
153
|
+
|
154
|
+
response = http.request(request)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
unless response.is_a?(Net::HTTPSuccess)
|
159
|
+
raise MangoApps::APIError, "Userinfo request failed: #{response.code} #{response.message}"
|
160
|
+
end
|
161
|
+
|
162
|
+
JSON.parse(response.body)
|
163
|
+
rescue JSON::ParserError => e
|
164
|
+
raise MangoApps::APIError, "Invalid JSON response from userinfo endpoint: #{e.message}"
|
165
|
+
rescue Net::ReadTimeout, Net::OpenTimeout, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Timeout::Error => e
|
166
|
+
raise MangoApps::APIError, "Failed to connect to userinfo endpoint: #{e.message}"
|
167
|
+
rescue OpenSSL::SSL::SSLError => e
|
168
|
+
raise MangoApps::APIError, "SSL connection failed for userinfo endpoint: #{e.message}"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def validate_discovery_data(data)
|
175
|
+
required_fields = %w[issuer authorization_endpoint token_endpoint]
|
176
|
+
missing_fields = required_fields - data.keys
|
177
|
+
|
178
|
+
if missing_fields.any?
|
179
|
+
raise MangoApps::DiscoveryError, "Missing required fields in discovery response: #{missing_fields.join(', ')}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def persist(token)
|
184
|
+
@config.token_store&.save(token.to_hash)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MangoApps
|
4
|
+
# Response wrapper that provides clean dot notation access to MangoApps API responses
|
5
|
+
# Abstracts away the ms_response wrapper and provides intuitive access patterns
|
6
|
+
class Response
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def initialize(data)
|
10
|
+
@data = data
|
11
|
+
@ms_response = data["ms_response"] || data
|
12
|
+
end
|
13
|
+
|
14
|
+
# Delegate to ms_response for cleaner access
|
15
|
+
def method_missing(method_name, *args, &block)
|
16
|
+
if @ms_response.respond_to?(method_name)
|
17
|
+
@ms_response.public_send(method_name, *args, &block)
|
18
|
+
elsif @ms_response.is_a?(Hash) && @ms_response.key?(method_name.to_s)
|
19
|
+
value = @ms_response[method_name.to_s]
|
20
|
+
wrap_value(value)
|
21
|
+
elsif @ms_response.is_a?(Hash) && @ms_response.key?(method_name.to_sym)
|
22
|
+
value = @ms_response[method_name.to_sym]
|
23
|
+
wrap_value(value)
|
24
|
+
else
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def respond_to_missing?(method_name, include_private = false)
|
30
|
+
@ms_response.respond_to?(method_name, include_private) ||
|
31
|
+
(@ms_response.is_a?(Hash) &&
|
32
|
+
(@ms_response.key?(method_name.to_s) || @ms_response.key?(method_name.to_sym))) ||
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
# Array access for hash-like behavior
|
37
|
+
def [](key)
|
38
|
+
value = @ms_response[key]
|
39
|
+
wrap_value(value)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Hash-like key access
|
43
|
+
def key?(key)
|
44
|
+
@ms_response.key?(key)
|
45
|
+
end
|
46
|
+
|
47
|
+
def keys
|
48
|
+
@ms_response.keys
|
49
|
+
end
|
50
|
+
|
51
|
+
def values
|
52
|
+
@ms_response.values.map { |v| wrap_value(v) }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Enumerable support
|
56
|
+
def each(&block)
|
57
|
+
@ms_response.each(&block)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Convert back to hash if needed
|
61
|
+
def to_h
|
62
|
+
@ms_response
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_hash
|
66
|
+
@ms_response
|
67
|
+
end
|
68
|
+
|
69
|
+
# Pretty inspection
|
70
|
+
def inspect
|
71
|
+
"#<MangoApps::Response:#{object_id} @data=#{@ms_response.inspect}>"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Access to raw data if needed
|
75
|
+
def raw_data
|
76
|
+
@data
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def wrap_value(value)
|
82
|
+
case value
|
83
|
+
when Hash
|
84
|
+
Response.new(value)
|
85
|
+
when Array
|
86
|
+
value.map { |item| wrap_value(item) }
|
87
|
+
else
|
88
|
+
value
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/mangoapps.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "mangoapps/version"
|
4
|
+
require_relative "mangoapps/errors"
|
5
|
+
require_relative "mangoapps/config"
|
6
|
+
require_relative "mangoapps/oauth"
|
7
|
+
require_relative "mangoapps/response"
|
8
|
+
require_relative "mangoapps/client"
|
9
|
+
require_relative "mangoapps/modules/learn"
|
10
|
+
require_relative "mangoapps/modules/users"
|
11
|
+
require_relative "mangoapps/modules/recognitions"
|
12
|
+
require_relative "mangoapps/modules/notifications"
|
13
|
+
require_relative "mangoapps/modules/feeds"
|
14
|
+
require_relative "mangoapps/modules/posts"
|
15
|
+
require_relative "mangoapps/modules/libraries"
|
16
|
+
require_relative "mangoapps/modules/trackers"
|
17
|
+
require_relative "mangoapps/modules/attachments"
|
18
|
+
require_relative "mangoapps/modules/tasks"
|
19
|
+
require_relative "mangoapps/modules/wikis"
|
20
|
+
|
21
|
+
module MangoApps; end
|
22
|
+
|
23
|
+
# Mix in the resources
|
24
|
+
MangoApps::Client.include(MangoApps::Client::Learn)
|
25
|
+
MangoApps::Client.include(MangoApps::Client::Users)
|
26
|
+
MangoApps::Client.include(MangoApps::Client::Recognitions)
|
27
|
+
MangoApps::Client.include(MangoApps::Client::Notifications)
|
28
|
+
MangoApps::Client.include(MangoApps::Client::Feeds)
|
29
|
+
MangoApps::Client.include(MangoApps::Client::Posts)
|
30
|
+
MangoApps::Client.include(MangoApps::Client::Libraries)
|
31
|
+
MangoApps::Client.include(MangoApps::Client::Trackers)
|
32
|
+
MangoApps::Client.include(MangoApps::Client::Attachments)
|
33
|
+
MangoApps::Client.include(MangoApps::Client::Tasks)
|
34
|
+
MangoApps::Client.include(MangoApps::Client::Wikis)
|