cts-mpx 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +50 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +88 -0
  5. data/CONTRIBUTING +8 -0
  6. data/COPYRIGHT +10 -0
  7. data/EXAMPLES.md +81 -0
  8. data/Gemfile +4 -0
  9. data/Gemfile.lock +172 -0
  10. data/Guardfile +41 -0
  11. data/LICENSE +201 -0
  12. data/NOTICE +9 -0
  13. data/README.md +60 -0
  14. data/Rakefile +6 -0
  15. data/bin/console +14 -0
  16. data/bin/setup +8 -0
  17. data/config/data_services.json +423 -0
  18. data/config/ingest_services.json +14 -0
  19. data/config/root_registry_sea1.json +118 -0
  20. data/config/web_services.json +544 -0
  21. data/cts-mpx.gemspec +43 -0
  22. data/examples/basic_query.rb +23 -0
  23. data/examples/login.rb +7 -0
  24. data/examples/update_media.rb +16 -0
  25. data/examples/update_procedurally.rb +20 -0
  26. data/lib/cts/mpx.rb +42 -0
  27. data/lib/cts/mpx/driver.rb +47 -0
  28. data/lib/cts/mpx/driver/assemblers.rb +96 -0
  29. data/lib/cts/mpx/driver/connections.rb +41 -0
  30. data/lib/cts/mpx/driver/exceptions.rb +50 -0
  31. data/lib/cts/mpx/driver/helpers.rb +67 -0
  32. data/lib/cts/mpx/driver/page.rb +38 -0
  33. data/lib/cts/mpx/driver/request.rb +60 -0
  34. data/lib/cts/mpx/driver/response.rb +72 -0
  35. data/lib/cts/mpx/entries.rb +80 -0
  36. data/lib/cts/mpx/entry.rb +100 -0
  37. data/lib/cts/mpx/field.rb +38 -0
  38. data/lib/cts/mpx/fields.rb +120 -0
  39. data/lib/cts/mpx/query.rb +115 -0
  40. data/lib/cts/mpx/registry.rb +60 -0
  41. data/lib/cts/mpx/service.rb +70 -0
  42. data/lib/cts/mpx/services.rb +113 -0
  43. data/lib/cts/mpx/services/data.rb +124 -0
  44. data/lib/cts/mpx/services/ingest.rb +60 -0
  45. data/lib/cts/mpx/services/web.rb +90 -0
  46. data/lib/cts/mpx/user.rb +74 -0
  47. data/lib/cts/mpx/validators.rb +51 -0
  48. data/lib/cts/mpx/version.rb +6 -0
  49. data/sdk-ring-diagram.png +0 -0
  50. data/sdk-uml.png +0 -0
  51. data/uml.nomnoml +242 -0
  52. 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