cts-mpx 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +50 -0
- data/.rspec +2 -0
- data/.rubocop.yml +88 -0
- data/CONTRIBUTING +8 -0
- data/COPYRIGHT +10 -0
- data/EXAMPLES.md +81 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +172 -0
- data/Guardfile +41 -0
- data/LICENSE +201 -0
- data/NOTICE +9 -0
- data/README.md +60 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/config/data_services.json +423 -0
- data/config/ingest_services.json +14 -0
- data/config/root_registry_sea1.json +118 -0
- data/config/web_services.json +544 -0
- data/cts-mpx.gemspec +43 -0
- data/examples/basic_query.rb +23 -0
- data/examples/login.rb +7 -0
- data/examples/update_media.rb +16 -0
- data/examples/update_procedurally.rb +20 -0
- data/lib/cts/mpx.rb +42 -0
- data/lib/cts/mpx/driver.rb +47 -0
- data/lib/cts/mpx/driver/assemblers.rb +96 -0
- data/lib/cts/mpx/driver/connections.rb +41 -0
- data/lib/cts/mpx/driver/exceptions.rb +50 -0
- data/lib/cts/mpx/driver/helpers.rb +67 -0
- data/lib/cts/mpx/driver/page.rb +38 -0
- data/lib/cts/mpx/driver/request.rb +60 -0
- data/lib/cts/mpx/driver/response.rb +72 -0
- data/lib/cts/mpx/entries.rb +80 -0
- data/lib/cts/mpx/entry.rb +100 -0
- data/lib/cts/mpx/field.rb +38 -0
- data/lib/cts/mpx/fields.rb +120 -0
- data/lib/cts/mpx/query.rb +115 -0
- data/lib/cts/mpx/registry.rb +60 -0
- data/lib/cts/mpx/service.rb +70 -0
- data/lib/cts/mpx/services.rb +113 -0
- data/lib/cts/mpx/services/data.rb +124 -0
- data/lib/cts/mpx/services/ingest.rb +60 -0
- data/lib/cts/mpx/services/web.rb +90 -0
- data/lib/cts/mpx/user.rb +74 -0
- data/lib/cts/mpx/validators.rb +51 -0
- data/lib/cts/mpx/version.rb +6 -0
- data/sdk-ring-diagram.png +0 -0
- data/sdk-uml.png +0 -0
- data/uml.nomnoml +242 -0
- metadata +401 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
module Cts
|
2
|
+
module Mpx
|
3
|
+
module Driver
|
4
|
+
# <Description>
|
5
|
+
# @attribute entries
|
6
|
+
# @return [Array] array of deserialized entries
|
7
|
+
# @attribute xmlns
|
8
|
+
# @return [Hash] active namespace received for this page
|
9
|
+
class Page
|
10
|
+
extend Creatable
|
11
|
+
include Enumerable
|
12
|
+
|
13
|
+
attribute name: 'entries', kind_of: Array
|
14
|
+
attribute name: 'xmlns', kind_of: Hash
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@entries = []
|
18
|
+
@xmlns = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
# return a json copy of the object, useful for later interpreation
|
22
|
+
# @param [Object] indent_depth sets indent depth to 2 if not nil
|
23
|
+
# @return [String] json serialized copy of the page
|
24
|
+
def to_s(indent_depth = nil)
|
25
|
+
indent_depth = 2 if indent_depth
|
26
|
+
|
27
|
+
Oj.dump(
|
28
|
+
{
|
29
|
+
"xmlns" => xmlns,
|
30
|
+
"entries" => entries
|
31
|
+
},
|
32
|
+
indent: indent_depth
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Cts
|
2
|
+
module Mpx
|
3
|
+
module Driver
|
4
|
+
#
|
5
|
+
# A single request of any type to the services.
|
6
|
+
#
|
7
|
+
# @attribute method
|
8
|
+
# @return [Symbol] type of rest method, GET, PUT, POST, DELETE
|
9
|
+
# @attribute url
|
10
|
+
# @return [String] url to make the request against
|
11
|
+
# @attribute query
|
12
|
+
# @return [Hash] query to send with the request
|
13
|
+
# @attribute payload
|
14
|
+
# @return [String] payload to be sent to the services
|
15
|
+
# @attribute response
|
16
|
+
# @return [Cts::Mpx::Driver::Response] response from the service
|
17
|
+
# @attribute headers
|
18
|
+
# @return [Hash] headers to transmit to the services along with the request
|
19
|
+
class Request
|
20
|
+
extend Creatable
|
21
|
+
|
22
|
+
attribute name: 'method', kind_of: Symbol
|
23
|
+
attribute name: 'url', kind_of: String
|
24
|
+
attribute name: 'query', kind_of: Hash
|
25
|
+
attribute name: 'payload', kind_of: String
|
26
|
+
attribute name: 'response', kind_of: ::Cts::Mpx::Driver::Response
|
27
|
+
attribute name: 'headers', kind_of: Hash
|
28
|
+
|
29
|
+
# Call the built request.
|
30
|
+
# @raise [RuntimeException] if the method is not a get, put, post or delete
|
31
|
+
# @raise [RuntimeException] if the url is not a valid reference
|
32
|
+
# @return [Cts::Mpx::Driver::Response] response from the service
|
33
|
+
def call
|
34
|
+
@headers ||= {}
|
35
|
+
@query ||= {}
|
36
|
+
|
37
|
+
call_exceptions method, url
|
38
|
+
socket = Connections[url]
|
39
|
+
params = {
|
40
|
+
headers: @headers,
|
41
|
+
path: URI.parse(url).path,
|
42
|
+
query: @query
|
43
|
+
}
|
44
|
+
params[:body] = payload if payload
|
45
|
+
|
46
|
+
r = socket.send method, params
|
47
|
+
@response = Response.create original: r
|
48
|
+
@response
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def call_exceptions(method, url)
|
54
|
+
raise "#{method} is not a valid method" unless %i[get put post delete].include? method.downcase
|
55
|
+
raise "#{url} is not a valid reference" unless Cts::Mpx::Validators.reference? url
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Cts
|
2
|
+
module Mpx
|
3
|
+
module Driver
|
4
|
+
#
|
5
|
+
# Class to contain a response from the services, has a few helper methods to make reading the data easier.
|
6
|
+
#
|
7
|
+
class Response
|
8
|
+
extend Creatable
|
9
|
+
|
10
|
+
# @!attribute original
|
11
|
+
# @return [Excon::Response] copy of the original excon response.
|
12
|
+
attribute name: 'original', kind_of: Excon::Response
|
13
|
+
|
14
|
+
#
|
15
|
+
# Hash output of the data returned from the services.
|
16
|
+
#
|
17
|
+
# @return [Hash] Hash including keys specific to the service and type of service.
|
18
|
+
#
|
19
|
+
def data
|
20
|
+
return @data if @data
|
21
|
+
|
22
|
+
raise 'response does not appear to be healthy' unless healthy?
|
23
|
+
|
24
|
+
begin
|
25
|
+
@data = Oj.load(original.body)
|
26
|
+
rescue Oj::ParseError => e
|
27
|
+
raise "could not parse data: #{e}"
|
28
|
+
end
|
29
|
+
@data
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Is the response healthy? did it have a status code outside 2xx or 3xx.
|
34
|
+
#
|
35
|
+
# @return [TrueFalse] false if status <= 199 or => 400, otherwise true.
|
36
|
+
#
|
37
|
+
def healthy?
|
38
|
+
return false if status <= 199 || status >= 400
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Does this response contain a service exception
|
44
|
+
#
|
45
|
+
# @return [TrueFalse] true if it does, false if it does not.
|
46
|
+
#
|
47
|
+
def service_exception?
|
48
|
+
data['isException'] == true
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# a page of data, processes the response.data for any entries.
|
53
|
+
#
|
54
|
+
# @return [Cts::Mpx::Driver::Page] a page of data.
|
55
|
+
#
|
56
|
+
def page
|
57
|
+
raise 'response does not appear to be healthy' unless healthy?
|
58
|
+
Cts::Mpx::Driver::Page.create entries: data['entries'], xmlns: data['$xmlns']
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Status code of the response
|
63
|
+
#
|
64
|
+
# @return [Fixnum] http status code
|
65
|
+
#
|
66
|
+
def status
|
67
|
+
original.status || nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Cts
|
2
|
+
module Mpx
|
3
|
+
# Enumerable collection that can store an entry in it
|
4
|
+
# @attribute collection storage for the individual entry
|
5
|
+
# @return [Entry[]]
|
6
|
+
class Entries
|
7
|
+
include Enumerable
|
8
|
+
include Driver
|
9
|
+
extend Creatable
|
10
|
+
|
11
|
+
attribute name: 'collection', kind_of: Array
|
12
|
+
|
13
|
+
# Create a new entries collection from a page
|
14
|
+
# @param [Page] page the page object to process
|
15
|
+
# @raise [ArgumentError] if :page is not available
|
16
|
+
# @return [Entries] a new entries collection
|
17
|
+
def self.create_from_page(page)
|
18
|
+
Exceptions.raise_unless_argument_error? page, Page
|
19
|
+
entries = new
|
20
|
+
page.entries.each do |e|
|
21
|
+
entry = Entry.new
|
22
|
+
entry.fields = Fields.create_from_data(data: e, xmlns: page.xmlns)
|
23
|
+
entry.id = entry.fields['id'] if entry.fields['id']
|
24
|
+
entries.add entry
|
25
|
+
end
|
26
|
+
entries
|
27
|
+
end
|
28
|
+
|
29
|
+
# Addressable method, indexed by entry object
|
30
|
+
# @param [Entry] key the entry to return
|
31
|
+
# @return [Self.collection,Entry,nil] Can return the collection, a single entry, or nil if nothing found
|
32
|
+
def [](key = nil)
|
33
|
+
return @collection unless key
|
34
|
+
@collection.find { |e| e.id == key }
|
35
|
+
end
|
36
|
+
|
37
|
+
# Add an entry object to the collection
|
38
|
+
# @param [Entry] entry instantiated Entry to include
|
39
|
+
# @raise [ArgumentError] if entry is not an Entry
|
40
|
+
# @return [Self]
|
41
|
+
def add(entry)
|
42
|
+
return self if @collection.include? entry
|
43
|
+
Exceptions.raise_unless_argument_error? entry, Entry
|
44
|
+
@collection.push entry
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
# Iterator method for self
|
49
|
+
# @return [Entry] next object in the list
|
50
|
+
def each
|
51
|
+
@collection.each { |c| yield c }
|
52
|
+
end
|
53
|
+
|
54
|
+
# Reset the entry array to a blank state
|
55
|
+
# @return [Void]
|
56
|
+
def initialize
|
57
|
+
reset
|
58
|
+
end
|
59
|
+
|
60
|
+
# Remove a entry object from the collection
|
61
|
+
# @param [Entry] argument instantiated Entry to remove
|
62
|
+
# @return [Self]
|
63
|
+
def remove(argument)
|
64
|
+
@collection.delete_if { |f| f == argument }
|
65
|
+
end
|
66
|
+
|
67
|
+
# Reset the entry array to a blank state
|
68
|
+
# @return [Void]
|
69
|
+
def reset
|
70
|
+
@collection = []
|
71
|
+
end
|
72
|
+
|
73
|
+
# A hash of all available entries
|
74
|
+
# @return [Hash]
|
75
|
+
def to_h
|
76
|
+
map(&:to_h)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Cts
|
2
|
+
module Mpx
|
3
|
+
# ORM style class to contain any entry from the data services.
|
4
|
+
class Entry
|
5
|
+
extend Creatable
|
6
|
+
|
7
|
+
attribute name: 'endpoint', kind_of: String
|
8
|
+
attribute name: 'fields', kind_of: Fields
|
9
|
+
attribute name: 'id', kind_of: String
|
10
|
+
attribute name: 'service', kind_of: String
|
11
|
+
|
12
|
+
# Load a Entry based on a long form ID
|
13
|
+
# @param [User] user user to make calls with
|
14
|
+
# @param [String] id long form id to look up
|
15
|
+
# @param [String] fields comma delimited list of fields to collect
|
16
|
+
# @return [Entry] the resulting entry
|
17
|
+
def self.load_by_id(user: nil, id: nil, fields: nil)
|
18
|
+
Driver::Helpers.required_arguments %i[user id], binding
|
19
|
+
|
20
|
+
Driver::Exceptions.raise_unless_argument_error? user, User
|
21
|
+
Driver::Exceptions.raise_unless_reference? id
|
22
|
+
|
23
|
+
e = new
|
24
|
+
e.id = id
|
25
|
+
e.load user: user, fields: nil
|
26
|
+
e
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return the id of the entry.
|
30
|
+
# @return [Entry] the resulting entry
|
31
|
+
def id
|
32
|
+
fields['id']
|
33
|
+
end
|
34
|
+
|
35
|
+
# Set the id of the entry, will check if it's a valid reference.
|
36
|
+
# @param [String] account_id account_id to set the entry to
|
37
|
+
# @return [Entry] the resulting entry
|
38
|
+
def id=(account_id)
|
39
|
+
Driver::Exceptions.raise_unless_reference? account_id
|
40
|
+
result = Services.from_url account_id
|
41
|
+
fields['id'] = account_id
|
42
|
+
|
43
|
+
@service = result[:service]
|
44
|
+
@endpoint = result[:endpoint]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Initialize an entry.
|
48
|
+
# Currently only instantiates fields.
|
49
|
+
def initialize
|
50
|
+
@fields = Fields.new
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return a [Hash] of the entry.
|
54
|
+
# @return [Hash] includes keys xmlns: [Hash] and entries: [Fields]
|
55
|
+
def to_h
|
56
|
+
{
|
57
|
+
xmlns: fields.xmlns,
|
58
|
+
entry: fields.to_h
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
# Load data from the remote services based on the id.
|
63
|
+
# @param [User] user user to make calls with
|
64
|
+
# @param [String] fields comma delimited list of fields to collect
|
65
|
+
# @return [Driver::Response] Response of the call.
|
66
|
+
def load(user: nil, fields: nil)
|
67
|
+
Driver::Helpers.required_arguments %i[user], binding
|
68
|
+
|
69
|
+
Driver::Exceptions.raise_unless_argument_error? user, User
|
70
|
+
Driver::Exceptions.raise_unless_argument_error? fields, String if fields
|
71
|
+
Driver::Exceptions.raise_unless_reference? id
|
72
|
+
|
73
|
+
response = Services::Data.get user: user, service: service, endpoint: endpoint, fields: fields, ids: id.split("/").last
|
74
|
+
self.fields.parse data: response.data['entries'].first, xmlns: response.data['xmlns']
|
75
|
+
response
|
76
|
+
end
|
77
|
+
|
78
|
+
# Save the entry to the remote services.
|
79
|
+
# @param [User] user user to make calls with
|
80
|
+
# @return [Driver::Response] Response of the call.
|
81
|
+
def save(user: nil)
|
82
|
+
Driver::Helpers.required_arguments %i[user], binding
|
83
|
+
Driver::Exceptions.raise_unless_argument_error? user, User
|
84
|
+
|
85
|
+
p = Driver::Page.create entries: [fields.to_h], xmlns: fields.xmlns
|
86
|
+
|
87
|
+
if id
|
88
|
+
response = Services::Data.put user: user, service: service, endpoint: endpoint, page: p
|
89
|
+
else
|
90
|
+
raise ArgumentError, "service is a required keyword" unless service
|
91
|
+
raise ArgumentError, "endpoint is a required keyword" unless endpoint
|
92
|
+
|
93
|
+
response = Services::Data.post user: user, service: service, endpoint: endpoint, page: p
|
94
|
+
end
|
95
|
+
|
96
|
+
response
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Cts
|
2
|
+
module Mpx
|
3
|
+
# Indivudal field, contains the name, value, and an optional namespace
|
4
|
+
# @attribute name name of the field
|
5
|
+
# @return [String]
|
6
|
+
# @attribute value value of the field
|
7
|
+
# @return [Object]
|
8
|
+
# @attribute xmlns namespace of the field
|
9
|
+
# @return [Hash]
|
10
|
+
class Field
|
11
|
+
extend Creatable
|
12
|
+
|
13
|
+
attribute name: 'name', kind_of: String
|
14
|
+
attribute name: 'value'
|
15
|
+
attribute name: 'xmlns', kind_of: Hash
|
16
|
+
|
17
|
+
# Return just the name value as key/value
|
18
|
+
# @return [Hash]
|
19
|
+
def to_h
|
20
|
+
{ name => value }
|
21
|
+
end
|
22
|
+
|
23
|
+
# Determines if this field is a custom field or not
|
24
|
+
# @return [Symbol] :internal or :custom if it is a custom field
|
25
|
+
def type
|
26
|
+
return :custom if name.include? "$"
|
27
|
+
:internal
|
28
|
+
end
|
29
|
+
|
30
|
+
# Set the namespace of the field
|
31
|
+
# @param [Hash] xmlns namespace of the fields
|
32
|
+
# @return [Void]
|
33
|
+
def xmlns=(xmlns)
|
34
|
+
@xmlns = xmlns if name.include? '$'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module Cts
|
2
|
+
module Mpx
|
3
|
+
# Enumerable collection that can store an entry field in it
|
4
|
+
# @attribute collection storage for the individual field
|
5
|
+
# @return [Field[]]
|
6
|
+
class Fields
|
7
|
+
include Enumerable
|
8
|
+
extend Creatable
|
9
|
+
|
10
|
+
attribute name: 'collection', kind_of: Array
|
11
|
+
|
12
|
+
# Create a new fields collection from a data hash
|
13
|
+
# @param [Hash] data raw fields to add
|
14
|
+
# @param [Hash] xmlns namespace of the fields
|
15
|
+
# @raise [ArgumentError] if :data or :xmlns are not provided
|
16
|
+
# @return [Fields] a new fields collection
|
17
|
+
def self.create_from_data(data: nil, xmlns: nil)
|
18
|
+
Driver::Helpers.required_arguments([:data], binding)
|
19
|
+
obj = new
|
20
|
+
obj.parse(data: data, xmlns: xmlns)
|
21
|
+
obj
|
22
|
+
end
|
23
|
+
|
24
|
+
# Addressable method, indexed by field name
|
25
|
+
# @param [String] key name of the field
|
26
|
+
# @return [Self.collection,Field,nil] Can return the collection, a single field, or nil if nothing found
|
27
|
+
def [](key = nil)
|
28
|
+
return @collection unless key
|
29
|
+
result = @collection.find { |f| f.name == key }
|
30
|
+
return result.value if result
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# Addresable set method, indexed by field name
|
35
|
+
# @note will create a new copy if it is not found in the collection
|
36
|
+
# @param [String] key name of the field
|
37
|
+
# @param [Object] value value of the field
|
38
|
+
# @param [Hash] xmlns namespace of the field
|
39
|
+
# @example to include xmlns, you need to use the long format of this method
|
40
|
+
# fields.[]= 'id', 'value', xmlns: {}
|
41
|
+
# @return [Void]
|
42
|
+
def []=(key, value, xmlns: nil)
|
43
|
+
existing_field = find { |f| f.name == key }
|
44
|
+
if existing_field
|
45
|
+
existing_field.value = value
|
46
|
+
else
|
47
|
+
add Field.create name: key, value: value, xmlns: xmlns
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Add a field object to the collection
|
52
|
+
# @param [Field] field instantiated Field to include
|
53
|
+
# @raise [ArgumentError] if field is not a Field
|
54
|
+
# @return [Self]
|
55
|
+
def add(field)
|
56
|
+
return self if @collection.include? field
|
57
|
+
Driver::Exceptions.raise_unless_argument_error? field, Field
|
58
|
+
@collection.push field
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
# Iterator method for self
|
63
|
+
# @return [Field] next object in the list
|
64
|
+
def each
|
65
|
+
@collection.each { |c| yield c }
|
66
|
+
end
|
67
|
+
|
68
|
+
# Reset the field array to a blank state
|
69
|
+
# @return [Void]
|
70
|
+
def initialize
|
71
|
+
reset
|
72
|
+
end
|
73
|
+
|
74
|
+
# Parse two hashes into a field array
|
75
|
+
# @note this will also set the collection
|
76
|
+
# @param [Hash] xmlns namespace
|
77
|
+
# @param [Hash] data fields in hash form
|
78
|
+
# @raise [ArgumentError] if xmlns is not a Hash
|
79
|
+
# @return [Field[]] returns a collection of fields
|
80
|
+
def parse(xmlns: nil, data: nil)
|
81
|
+
Driver::Exceptions.raise_unless_argument_error? data, Hash
|
82
|
+
data.delete :service
|
83
|
+
data.delete :endpoint
|
84
|
+
reset
|
85
|
+
@collection = data.map { |k, v| Field.create name: k.to_s, value: v, xmlns: xmlns }
|
86
|
+
end
|
87
|
+
|
88
|
+
# Remove a field object from the collection
|
89
|
+
# @param [String] name instantiated Field to remove
|
90
|
+
# @return [Self]
|
91
|
+
def remove(name)
|
92
|
+
@collection.delete_if { |f| f.name == name }
|
93
|
+
end
|
94
|
+
|
95
|
+
# Reset the field array to a blank state
|
96
|
+
# @return [Void]
|
97
|
+
def reset
|
98
|
+
@collection = []
|
99
|
+
end
|
100
|
+
|
101
|
+
# return the fields as a hash
|
102
|
+
# @return [Hash] key is name, value is value
|
103
|
+
def to_h
|
104
|
+
h = {}
|
105
|
+
each { |f| h.store f.name, f.value }
|
106
|
+
h
|
107
|
+
end
|
108
|
+
|
109
|
+
# Return the cumulative namespace of all Field's in the collection
|
110
|
+
# @return [Hash] key is the namespace key, value is the value
|
111
|
+
def xmlns
|
112
|
+
a = collection.map(&:xmlns).uniq
|
113
|
+
a.delete nil
|
114
|
+
h = {}
|
115
|
+
a.each { |e| h.merge! e }
|
116
|
+
h
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|