conversant 1.0.16
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/.env.example +39 -0
- data/.gitignore +52 -0
- data/.gitlab-ci.yml +108 -0
- data/.rspec +3 -0
- data/.rubocop.yml +16 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +487 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +21 -0
- data/README.md +860 -0
- data/RELEASE.md +726 -0
- data/Rakefile +21 -0
- data/conversant.gemspec +49 -0
- data/examples/inheritance_integration.rb +348 -0
- data/examples/rails_initializer.rb +69 -0
- data/lib/conversant/configuration.rb +132 -0
- data/lib/conversant/v3/base.rb +47 -0
- data/lib/conversant/v3/http_client.rb +456 -0
- data/lib/conversant/v3/mixins/authentication.rb +221 -0
- data/lib/conversant/v3/services/authorization.rb +194 -0
- data/lib/conversant/v3/services/cdn/analytics.rb +483 -0
- data/lib/conversant/v3/services/cdn/audit.rb +71 -0
- data/lib/conversant/v3/services/cdn/business.rb +122 -0
- data/lib/conversant/v3/services/cdn/certificate.rb +180 -0
- data/lib/conversant/v3/services/cdn/dashboard.rb +109 -0
- data/lib/conversant/v3/services/cdn/domain.rb +223 -0
- data/lib/conversant/v3/services/cdn/monitoring.rb +65 -0
- data/lib/conversant/v3/services/cdn/partner/analytics.rb +233 -0
- data/lib/conversant/v3/services/cdn/partner.rb +60 -0
- data/lib/conversant/v3/services/cdn.rb +221 -0
- data/lib/conversant/v3/services/lms/dashboard.rb +99 -0
- data/lib/conversant/v3/services/lms/domain.rb +108 -0
- data/lib/conversant/v3/services/lms/job.rb +211 -0
- data/lib/conversant/v3/services/lms/partner/analytics.rb +266 -0
- data/lib/conversant/v3/services/lms/partner/business.rb +151 -0
- data/lib/conversant/v3/services/lms/partner/report.rb +170 -0
- data/lib/conversant/v3/services/lms/partner.rb +58 -0
- data/lib/conversant/v3/services/lms/preset.rb +57 -0
- data/lib/conversant/v3/services/lms.rb +173 -0
- data/lib/conversant/v3/services/oss/partner/analytics.rb +105 -0
- data/lib/conversant/v3/services/oss/partner.rb +48 -0
- data/lib/conversant/v3/services/oss.rb +128 -0
- data/lib/conversant/v3/services/portal/dashboard.rb +114 -0
- data/lib/conversant/v3/services/portal.rb +219 -0
- data/lib/conversant/v3/services/vms/analytics.rb +114 -0
- data/lib/conversant/v3/services/vms/business.rb +190 -0
- data/lib/conversant/v3/services/vms/partner/analytics.rb +133 -0
- data/lib/conversant/v3/services/vms/partner/business.rb +90 -0
- data/lib/conversant/v3/services/vms/partner.rb +57 -0
- data/lib/conversant/v3/services/vms/transcoding.rb +184 -0
- data/lib/conversant/v3/services/vms.rb +166 -0
- data/lib/conversant/v3.rb +36 -0
- data/lib/conversant/version.rb +5 -0
- data/lib/conversant.rb +108 -0
- data/publish.sh +107 -0
- data/sig/conversant/v3/services/authorization.rbs +34 -0
- data/sig/conversant/v3/services/cdn.rbs +123 -0
- data/sig/conversant/v3/services/lms.rbs +80 -0
- data/sig/conversant/v3/services/portal.rbs +22 -0
- data/sig/conversant/v3/services/vms.rbs +64 -0
- data/sig/conversant/v3.rbs +85 -0
- data/sig/conversant.rbs +37 -0
- metadata +267 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conversant
|
|
4
|
+
module V3
|
|
5
|
+
module Services
|
|
6
|
+
class LMS
|
|
7
|
+
# Preset service for live transcoding preset management
|
|
8
|
+
#
|
|
9
|
+
# Manages transcoding presets which define encoding parameters
|
|
10
|
+
# such as bitrate, resolution, codec settings for live streams.
|
|
11
|
+
#
|
|
12
|
+
# @example Get all transcoding presets
|
|
13
|
+
# lms = Conversant::V3.lms(12345)
|
|
14
|
+
#
|
|
15
|
+
# presets = lms.preset.all
|
|
16
|
+
# presets.each do |preset|
|
|
17
|
+
# puts "#{preset['name']}: #{preset['resolution']} @ #{preset['bitrate']}"
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# @since 1.0.8
|
|
21
|
+
class Preset
|
|
22
|
+
# @return [LMS] the parent LMS service instance
|
|
23
|
+
attr_reader :parent
|
|
24
|
+
|
|
25
|
+
# Initialize preset service
|
|
26
|
+
#
|
|
27
|
+
# @param parent [LMS] the parent LMS service instance
|
|
28
|
+
def initialize(parent)
|
|
29
|
+
@parent = parent
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Get all available transcoding presets
|
|
33
|
+
#
|
|
34
|
+
# Retrieves the list of transcoding presets configured for the customer,
|
|
35
|
+
# including encoding parameters like resolution, bitrate, codec settings.
|
|
36
|
+
#
|
|
37
|
+
# @return [Array<Hash>] array of preset configurations, or empty array on error
|
|
38
|
+
#
|
|
39
|
+
# @example Get all presets
|
|
40
|
+
# presets = lms.preset.all
|
|
41
|
+
# presets.each do |preset|
|
|
42
|
+
# puts "#{preset['name']}: #{preset['resolution']} @ #{preset['bitrate']}"
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# @since 1.0.8
|
|
46
|
+
def all
|
|
47
|
+
response = JSON.parse(@parent.send(:call, 'GET', '/live/preset/list_page'))
|
|
48
|
+
response&.[]('list') || []
|
|
49
|
+
rescue StandardError => e
|
|
50
|
+
@parent.send(:logger).error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
51
|
+
[]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'authorization'
|
|
4
|
+
|
|
5
|
+
module Conversant
|
|
6
|
+
module V3
|
|
7
|
+
module Services
|
|
8
|
+
# Live Media Streaming (LMS) service for managing streaming operations
|
|
9
|
+
#
|
|
10
|
+
# Provides comprehensive functionality for live streaming management including:
|
|
11
|
+
# - Job management for streaming operations
|
|
12
|
+
# - Domain configuration for streaming endpoints
|
|
13
|
+
# - Dashboard metrics and monitoring
|
|
14
|
+
#
|
|
15
|
+
# @example Basic usage
|
|
16
|
+
# lms = Conversant::V3.lms(12345)
|
|
17
|
+
#
|
|
18
|
+
# # Get streaming jobs
|
|
19
|
+
# jobs = lms.job.where(status: 'active')
|
|
20
|
+
#
|
|
21
|
+
# # Get dashboard metrics
|
|
22
|
+
# live_metrics = lms.dashboard.live
|
|
23
|
+
#
|
|
24
|
+
# @since 1.0.0
|
|
25
|
+
class LMS < ::Conversant::V3::Base
|
|
26
|
+
include Authorization
|
|
27
|
+
# Get job management service instance
|
|
28
|
+
#
|
|
29
|
+
# @return [Job] job service for streaming job management
|
|
30
|
+
# @since 1.0.0
|
|
31
|
+
def job
|
|
32
|
+
@job ||= Job.new(self)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Get domain management service instance
|
|
36
|
+
#
|
|
37
|
+
# @return [Domain] domain service for streaming domain management
|
|
38
|
+
# @since 1.0.0
|
|
39
|
+
def domain
|
|
40
|
+
@domain ||= Domain.new(self)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Get dashboard metrics service instance
|
|
44
|
+
#
|
|
45
|
+
# @return [Dashboard] dashboard service for streaming metrics
|
|
46
|
+
# @since 1.0.0
|
|
47
|
+
def dashboard
|
|
48
|
+
@dashboard ||= Dashboard.new(self)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Get preset service instance
|
|
52
|
+
#
|
|
53
|
+
# @return [Preset] preset service for transcoding configuration
|
|
54
|
+
# @since 1.0.8
|
|
55
|
+
def preset
|
|
56
|
+
@preset ||= Preset.new(self)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Get partner service instance
|
|
60
|
+
#
|
|
61
|
+
# Provides access to partner-level analytics for Live Media Streaming
|
|
62
|
+
# that aggregate data across multiple customer accounts.
|
|
63
|
+
#
|
|
64
|
+
# @return [Partner] partner service for LMS analytics
|
|
65
|
+
# @since 1.0.12
|
|
66
|
+
#
|
|
67
|
+
# @example Access partner analytics
|
|
68
|
+
# lms = Conversant::V3.lms(12345)
|
|
69
|
+
# duration = lms.partner.analytics.duration(payload)
|
|
70
|
+
def partner
|
|
71
|
+
@partner ||= Partner.new(self)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @deprecated Use {#partner} instead
|
|
75
|
+
# Get partner analytics service instance (deprecated)
|
|
76
|
+
#
|
|
77
|
+
# @return [LMS::Partner::Analytics] partner analytics for LMS reporting
|
|
78
|
+
# @since 1.0.8
|
|
79
|
+
# @deprecated Use `lms.partner.analytics` instead of `lms.partner_analytics`
|
|
80
|
+
def partner_analytics
|
|
81
|
+
@partner_analytics ||= Partner::Analytics.new(self)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
protected
|
|
85
|
+
|
|
86
|
+
def call(method, uri, payload = nil)
|
|
87
|
+
url = "#{configuration.private_lms_endpoint}#{uri}"
|
|
88
|
+
|
|
89
|
+
headers = authorized_headers
|
|
90
|
+
|
|
91
|
+
# Check for JSESSIONID in Cookie header
|
|
92
|
+
if headers['Cookie'].nil? || !headers['Cookie'].include?('JSESSIONID=')
|
|
93
|
+
logger.error "#{identifier}.METHOD:call.NO_JSESSIONID"
|
|
94
|
+
raise AuthenticationError, 'Missing JSESSIONID for LMS'
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
code, response = request(method, url, payload, headers)
|
|
98
|
+
|
|
99
|
+
if code >= 400
|
|
100
|
+
logger.error "#{identifier}.METHOD:call.HTTP_ERROR:#{code}"
|
|
101
|
+
raise ApiError, "LMS API error: #{code}"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
response.body
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
protected
|
|
108
|
+
|
|
109
|
+
def service_endpoint
|
|
110
|
+
configuration.private_lms_endpoint
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def session_cookie_name
|
|
114
|
+
'JSESSIONID'
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def requires_session?
|
|
118
|
+
true
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
private
|
|
122
|
+
|
|
123
|
+
def fetch_new_session
|
|
124
|
+
sessions = authenticate
|
|
125
|
+
return nil unless sessions && sessions[:session] && sessions[:sso_gw_session2]
|
|
126
|
+
|
|
127
|
+
timestamp = (Time.now.to_f * 1000).to_i
|
|
128
|
+
reporting_url = "#{configuration.private_lms_endpoint}/?customerId=#{customer_id}&isHideMenu=f&t=#{timestamp}"
|
|
129
|
+
|
|
130
|
+
logger.debug "#{identifier}.METHOD:authorize.REQUESTING_JSESSIONID"
|
|
131
|
+
|
|
132
|
+
response = RestClient.get(
|
|
133
|
+
reporting_url,
|
|
134
|
+
{
|
|
135
|
+
authority: URI.parse(configuration.private_lms_endpoint).hostname,
|
|
136
|
+
referer: portal_endpoint,
|
|
137
|
+
user_agent: configuration.default_ua,
|
|
138
|
+
cookies: {
|
|
139
|
+
'SESSION': sessions[:session],
|
|
140
|
+
'SSO_GW_SESSION2': sessions[:sso_gw_session2]
|
|
141
|
+
},
|
|
142
|
+
timeout: 30,
|
|
143
|
+
open_timeout: 30
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
if response.cookies['JSESSIONID']
|
|
148
|
+
jsessionid = response.cookies['JSESSIONID']
|
|
149
|
+
redis.set(session_cache_key, jsessionid, ex: configuration.cache_ttl)
|
|
150
|
+
logger.debug "#{identifier}.METHOD:authorize.JSESSIONID_OBTAINED"
|
|
151
|
+
jsessionid
|
|
152
|
+
else
|
|
153
|
+
logger.error "#{identifier}.METHOD:authorize.NO_JSESSIONID_IN_RESPONSE"
|
|
154
|
+
nil
|
|
155
|
+
end
|
|
156
|
+
rescue RestClient::Unauthorized, RestClient::Forbidden => e
|
|
157
|
+
logger.error "#{identifier}.METHOD:authorize.AUTH_ERROR:#{e.message}"
|
|
158
|
+
nil
|
|
159
|
+
rescue StandardError => e
|
|
160
|
+
logger.error "#{identifier}.METHOD:authorize.ERROR:#{e.message}"
|
|
161
|
+
nil
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Load nested service classes after LMS is defined
|
|
169
|
+
require_relative 'lms/job'
|
|
170
|
+
require_relative 'lms/domain'
|
|
171
|
+
require_relative 'lms/dashboard'
|
|
172
|
+
require_relative 'lms/preset'
|
|
173
|
+
require_relative 'lms/partner'
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conversant
|
|
4
|
+
module V3
|
|
5
|
+
module Services
|
|
6
|
+
class OSS
|
|
7
|
+
class Partner
|
|
8
|
+
# OSS (Object Storage Service) analytics for partner-level reporting
|
|
9
|
+
#
|
|
10
|
+
# Provides partner-level analytics and reporting for Object Storage Service
|
|
11
|
+
# including storage usage metrics for S3-compatible storage across multiple
|
|
12
|
+
# customer accounts.
|
|
13
|
+
#
|
|
14
|
+
# @since 1.0.12
|
|
15
|
+
class Analytics
|
|
16
|
+
# @return [Conversant::V3::Services::OSS] the parent OSS service instance
|
|
17
|
+
attr_reader :parent
|
|
18
|
+
|
|
19
|
+
# Initialize partner OSS analytics service
|
|
20
|
+
#
|
|
21
|
+
# Note: OSS analytics uses the CDN service endpoint for API calls.
|
|
22
|
+
#
|
|
23
|
+
# @param parent [Conversant::V3::Services::OSS] the parent OSS service instance
|
|
24
|
+
def initialize(parent)
|
|
25
|
+
@parent = parent
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Get storage usage metrics for OSS (full year data)
|
|
29
|
+
#
|
|
30
|
+
# Retrieves Object Storage Service usage data including storage capacity,
|
|
31
|
+
# bandwidth usage, and request counts aggregated by month for billing
|
|
32
|
+
# and capacity planning purposes. Returns all months for the specified year.
|
|
33
|
+
#
|
|
34
|
+
# @param year [String, Integer] year in YYYY format
|
|
35
|
+
# @param params [Hash] optional query parameters
|
|
36
|
+
# @option params [String] :end end date for the report
|
|
37
|
+
#
|
|
38
|
+
# @return [Array<Hash>] array of monthly storage usage data, or empty array on error
|
|
39
|
+
#
|
|
40
|
+
# @example Get OSS storage usage for a year
|
|
41
|
+
# usages = oss.partner.analytics.usages("2025")
|
|
42
|
+
# usages.each do |month|
|
|
43
|
+
# puts "#{month['month']}: #{month['diskUsage']} bytes"
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# @since 1.0.8
|
|
47
|
+
def usages(year, params = {})
|
|
48
|
+
query_string = params.map { |k, v| "#{k}=#{v}" }.join('&')
|
|
49
|
+
uri = "/oss/storage_usages/#{year}"
|
|
50
|
+
uri += "?#{query_string}" unless query_string.empty?
|
|
51
|
+
response = @parent.send(:call, 'GET', uri)
|
|
52
|
+
JSON.parse(response) || []
|
|
53
|
+
rescue StandardError => e
|
|
54
|
+
@parent.send(:logger).error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
55
|
+
[]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Get storage usage for current month
|
|
59
|
+
#
|
|
60
|
+
# Retrieves disk usage for the month containing the specified date (or current month).
|
|
61
|
+
# This is useful for getting current month's storage usage for billing purposes.
|
|
62
|
+
#
|
|
63
|
+
# @param payload [Hash] Parameters for the usage query
|
|
64
|
+
# @option payload [Date, String, Time] :end End date for the query (defaults to current date)
|
|
65
|
+
#
|
|
66
|
+
# @return [Integer, nil] Disk usage in bytes, or nil on error
|
|
67
|
+
#
|
|
68
|
+
# @example Get current month's storage usage
|
|
69
|
+
# usage = oss.partner.analytics.current_month_usage
|
|
70
|
+
# puts "Current usage: #{usage / 1_073_741_824.0} GB"
|
|
71
|
+
#
|
|
72
|
+
# @example Get specific month's storage usage
|
|
73
|
+
# usage = oss.partner.analytics.current_month_usage(end: '2025-04-30')
|
|
74
|
+
# puts "April 2025 usage: #{usage / 1_073_741_824.0} GB"
|
|
75
|
+
#
|
|
76
|
+
# @since 1.0.12
|
|
77
|
+
def current_month_usage(payload = {})
|
|
78
|
+
require 'date'
|
|
79
|
+
|
|
80
|
+
# Extract the end date from the payload, defaulting to the current date
|
|
81
|
+
today = if payload.[](:end) || payload.[]('end')
|
|
82
|
+
(payload[:end] || payload['end']).to_date
|
|
83
|
+
else
|
|
84
|
+
Date.today
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Fetch storage usage data for the year containing the end date
|
|
88
|
+
yearly_data = usages(today.year.to_s)
|
|
89
|
+
return 0 if yearly_data.nil? || yearly_data.empty?
|
|
90
|
+
|
|
91
|
+
# Find the storage usage for the specific month
|
|
92
|
+
today_month_format = today.strftime('%Y-%m')
|
|
93
|
+
month_data = yearly_data.find { |item| item&.[]('month') == today_month_format }
|
|
94
|
+
|
|
95
|
+
month_data&.[]('diskUsage') || 0
|
|
96
|
+
rescue StandardError => e
|
|
97
|
+
@parent.send(:logger).error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
98
|
+
nil
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conversant
|
|
4
|
+
module V3
|
|
5
|
+
module Services
|
|
6
|
+
class OSS
|
|
7
|
+
# Partner service for OSS partner-level operations
|
|
8
|
+
#
|
|
9
|
+
# Provides access to partner-level analytics for Object Storage Service
|
|
10
|
+
# that aggregate data across multiple customer accounts.
|
|
11
|
+
#
|
|
12
|
+
# @example Access partner analytics
|
|
13
|
+
# oss = Conversant::V3.oss(12345)
|
|
14
|
+
#
|
|
15
|
+
# # Partner-level OSS storage analytics
|
|
16
|
+
# usages = oss.partner.analytics.usages("2025", end: "2025-12-31")
|
|
17
|
+
# puts "Total storage: #{usages['total_storage']} GB"
|
|
18
|
+
#
|
|
19
|
+
# @since 1.0.12
|
|
20
|
+
class Partner
|
|
21
|
+
# @return [OSS] the parent OSS service instance
|
|
22
|
+
attr_reader :parent
|
|
23
|
+
|
|
24
|
+
# Initialize partner service
|
|
25
|
+
#
|
|
26
|
+
# @param parent [OSS] the parent OSS service instance
|
|
27
|
+
def initialize(parent)
|
|
28
|
+
@parent = parent
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Get partner analytics service instance
|
|
32
|
+
#
|
|
33
|
+
# Provides partner-level analytics for OSS services including storage
|
|
34
|
+
# usage, capacity metrics, and bandwidth across multiple customers.
|
|
35
|
+
#
|
|
36
|
+
# @return [Analytics] OSS partner analytics service
|
|
37
|
+
# @since 1.0.12
|
|
38
|
+
def analytics
|
|
39
|
+
@analytics ||= Analytics.new(@parent)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Load nested analytics class after Partner is defined
|
|
48
|
+
require_relative 'partner/analytics'
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'authorization'
|
|
4
|
+
|
|
5
|
+
module Conversant
|
|
6
|
+
module V3
|
|
7
|
+
module Services
|
|
8
|
+
# Object Storage Service (OSS) for S3-compatible storage operations
|
|
9
|
+
#
|
|
10
|
+
# Provides comprehensive functionality for object storage operations including:
|
|
11
|
+
# - Storage usage metrics and analytics
|
|
12
|
+
# - Partner-level reporting across multiple customers
|
|
13
|
+
# - Capacity planning and billing data
|
|
14
|
+
#
|
|
15
|
+
# @example Basic usage
|
|
16
|
+
# oss = Conversant::V3.oss(12345)
|
|
17
|
+
#
|
|
18
|
+
# # Get storage usage for a year
|
|
19
|
+
# usages = oss.partner.analytics.usages("2025")
|
|
20
|
+
#
|
|
21
|
+
# @since 1.0.12
|
|
22
|
+
class OSS < ::Conversant::V3::Base
|
|
23
|
+
include Authorization
|
|
24
|
+
|
|
25
|
+
# Get partner service instance
|
|
26
|
+
#
|
|
27
|
+
# Provides access to partner-level analytics for Object Storage Service
|
|
28
|
+
# that aggregate data across multiple customer accounts.
|
|
29
|
+
#
|
|
30
|
+
# @return [Partner] partner service for OSS analytics
|
|
31
|
+
# @since 1.0.12
|
|
32
|
+
#
|
|
33
|
+
# @example Access partner analytics
|
|
34
|
+
# oss = Conversant::V3.oss(12345)
|
|
35
|
+
# usages = oss.partner.analytics.usages("2025")
|
|
36
|
+
def partner
|
|
37
|
+
@partner ||= Partner.new(self)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
protected
|
|
41
|
+
|
|
42
|
+
def call(method, uri, payload = nil)
|
|
43
|
+
# OSS API calls use PRIVATE_OSS_ENDPOINT
|
|
44
|
+
url = "#{configuration.private_oss_endpoint}#{uri}"
|
|
45
|
+
|
|
46
|
+
# Get authorized headers (SESSION cookie from OSS)
|
|
47
|
+
headers = authorized_headers
|
|
48
|
+
|
|
49
|
+
# Check for SESSION in Cookie header
|
|
50
|
+
if headers['Cookie'].nil? || !headers['Cookie'].include?('SESSION=')
|
|
51
|
+
logger.error "#{identifier}.METHOD:call.NO_SESSION"
|
|
52
|
+
raise AuthenticationError, 'Missing SESSION for OSS'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
code, response = request(method, url, payload, headers)
|
|
56
|
+
|
|
57
|
+
if code >= 400
|
|
58
|
+
logger.error "#{identifier}.METHOD:call.HTTP_ERROR:#{code}"
|
|
59
|
+
raise ApiError, "OSS API error: #{code}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
response.body
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def fetch_new_session
|
|
68
|
+
sessions = authenticate
|
|
69
|
+
return nil unless sessions && sessions[:session] && sessions[:sso_gw_session2]
|
|
70
|
+
|
|
71
|
+
# OSS has its own authorization URL
|
|
72
|
+
timestamp = (Time.now.to_f * 1000).to_i
|
|
73
|
+
signature_url = "#{configuration.private_oss_endpoint}/?customerId=#{customer_id}&isHideMenu=f&t=#{timestamp}"
|
|
74
|
+
logger.debug "#{identifier}.METHOD:authorize.REQUESTING_SESSION"
|
|
75
|
+
|
|
76
|
+
response = RestClient.get(
|
|
77
|
+
signature_url,
|
|
78
|
+
{
|
|
79
|
+
authority: URI.parse(configuration.private_oss_endpoint).hostname,
|
|
80
|
+
referer: portal_endpoint,
|
|
81
|
+
user_agent: configuration.default_ua,
|
|
82
|
+
cookies: {
|
|
83
|
+
'SESSION': sessions[:session],
|
|
84
|
+
'SSO_GW_SESSION2': sessions[:sso_gw_session2]
|
|
85
|
+
},
|
|
86
|
+
timeout: 30,
|
|
87
|
+
open_timeout: 30
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if response.cookies['SESSION']
|
|
92
|
+
session_cookie = response.cookies['SESSION']
|
|
93
|
+
redis.set(session_cache_key, session_cookie, ex: configuration.cache_ttl)
|
|
94
|
+
logger.debug "#{identifier}.METHOD:authorize.SESSION_OBTAINED"
|
|
95
|
+
session_cookie
|
|
96
|
+
else
|
|
97
|
+
logger.error "#{identifier}.METHOD:authorize.NO_SESSION_IN_RESPONSE"
|
|
98
|
+
nil
|
|
99
|
+
end
|
|
100
|
+
rescue RestClient::Unauthorized, RestClient::Forbidden => e
|
|
101
|
+
logger.error "#{identifier}.METHOD:authorize.AUTH_ERROR:#{e.message}"
|
|
102
|
+
nil
|
|
103
|
+
rescue StandardError => e
|
|
104
|
+
logger.error "#{identifier}.METHOD:authorize.ERROR:#{e.message}"
|
|
105
|
+
nil
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
protected
|
|
109
|
+
|
|
110
|
+
def service_endpoint
|
|
111
|
+
# OSS uses its own endpoint for both authentication and API calls
|
|
112
|
+
configuration.private_oss_endpoint
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def session_cookie_name
|
|
116
|
+
'SESSION'
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def requires_session?
|
|
120
|
+
true
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Load nested service classes after OSS is defined
|
|
128
|
+
require_relative 'oss/partner'
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conversant
|
|
4
|
+
module V3
|
|
5
|
+
module Services
|
|
6
|
+
class Portal
|
|
7
|
+
# Dashboard service for Portal customer metadata and reporting
|
|
8
|
+
#
|
|
9
|
+
# Provides access to customer-related metadata including product usage,
|
|
10
|
+
# geographic distribution, industry classification, and organizational hierarchy.
|
|
11
|
+
#
|
|
12
|
+
# @since 1.0.8
|
|
13
|
+
class Dashboard
|
|
14
|
+
# @return [Portal] the parent Portal service instance
|
|
15
|
+
attr_reader :parent
|
|
16
|
+
|
|
17
|
+
# Initialize dashboard service
|
|
18
|
+
#
|
|
19
|
+
# @param parent [Portal] the parent Portal service instance
|
|
20
|
+
def initialize(parent)
|
|
21
|
+
@parent = parent
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Get product usage report for a customer
|
|
25
|
+
#
|
|
26
|
+
# Retrieves information about which products (CDN, LMS, VMS, OSS) the customer
|
|
27
|
+
# is using and their usage statistics.
|
|
28
|
+
#
|
|
29
|
+
# @param params [Hash] query parameters
|
|
30
|
+
# @option params [String, Integer] :customerId customer ID
|
|
31
|
+
# @option params [Integer] :_ timestamp in milliseconds (for cache busting)
|
|
32
|
+
#
|
|
33
|
+
# @return [Hash] product report data, or empty hash on error
|
|
34
|
+
#
|
|
35
|
+
# @example Get product report
|
|
36
|
+
# report = portal.dashboard.products(customerId: "31723", _: Time.now.to_i * 1000)
|
|
37
|
+
# puts "CDN enabled: #{report['cdn_enabled']}"
|
|
38
|
+
#
|
|
39
|
+
# @since 1.0.8
|
|
40
|
+
def products(params = {})
|
|
41
|
+
query_string = params.map { |k, v| "#{k}=#{v}" }.join('&')
|
|
42
|
+
response = @parent.send(:call, 'GET', "/getProductReport?#{query_string}")
|
|
43
|
+
JSON.parse(response)
|
|
44
|
+
rescue StandardError => e
|
|
45
|
+
@parent.send(:logger).error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
46
|
+
{}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Get list of countries
|
|
50
|
+
#
|
|
51
|
+
# Retrieves the list of countries available in the system, typically used
|
|
52
|
+
# for filtering or categorizing customers by geographic location.
|
|
53
|
+
#
|
|
54
|
+
# @return [Array<Hash>] array of country data, or empty array on error
|
|
55
|
+
#
|
|
56
|
+
# @example Get all countries
|
|
57
|
+
# countries = portal.dashboard.countries
|
|
58
|
+
# countries.each { |country| puts "#{country['name']} (#{country['code']})" }
|
|
59
|
+
#
|
|
60
|
+
# @since 1.0.8
|
|
61
|
+
def countries
|
|
62
|
+
response = @parent.send(:call, 'GET', '/getCountry')
|
|
63
|
+
JSON.parse(response)
|
|
64
|
+
rescue StandardError => e
|
|
65
|
+
@parent.send(:logger).error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
66
|
+
[]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Get list of industries
|
|
70
|
+
#
|
|
71
|
+
# Retrieves the list of industry classifications available in the system,
|
|
72
|
+
# used for categorizing customers by business sector.
|
|
73
|
+
#
|
|
74
|
+
# @return [Array<Hash>] array of industry data, or empty array on error
|
|
75
|
+
#
|
|
76
|
+
# @example Get all industries
|
|
77
|
+
# industries = portal.dashboard.industries
|
|
78
|
+
# industries.each { |industry| puts "#{industry['name']}" }
|
|
79
|
+
#
|
|
80
|
+
# @since 1.0.8
|
|
81
|
+
def industries
|
|
82
|
+
response = @parent.send(:call, 'GET', '/getIndustry')
|
|
83
|
+
JSON.parse(response)
|
|
84
|
+
rescue StandardError => e
|
|
85
|
+
@parent.send(:logger).error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
86
|
+
[]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Get customer organizational tree view
|
|
90
|
+
#
|
|
91
|
+
# Retrieves the hierarchical organization structure showing parent-child
|
|
92
|
+
# relationships between customers, useful for partner/reseller views.
|
|
93
|
+
#
|
|
94
|
+
# @param payload [Hash] tree view query parameters (optional)
|
|
95
|
+
#
|
|
96
|
+
# @return [Hash] tree structure data, or empty hash on error
|
|
97
|
+
#
|
|
98
|
+
# @example Get customer tree
|
|
99
|
+
# tree = portal.dashboard.tree_view
|
|
100
|
+
# puts "Root customers: #{tree['children'].length}"
|
|
101
|
+
#
|
|
102
|
+
# @since 1.0.8
|
|
103
|
+
def tree_view(payload = {})
|
|
104
|
+
response = @parent.send(:call, 'POST', '/customer/tree_view/', payload)
|
|
105
|
+
JSON.parse(response)
|
|
106
|
+
rescue StandardError => e
|
|
107
|
+
@parent.send(:logger).error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
108
|
+
{}
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|