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,115 @@
1
+ module Cts
2
+ module Mpx
3
+ # Query method, allows you to build and send a query to the data services.
4
+ # @attribute account
5
+ # @return [String] account account context, can be id or name
6
+ # @attribute endpoint
7
+ # @return [String] endpoint of the service
8
+ # @attribute extra_path
9
+ # @return [String] any extra_path
10
+ # @attribute fields
11
+ # @return [String] Fields to gather
12
+ # @attribute ids
13
+ # @return [Array] Ids to search through
14
+ # @attribute page
15
+ # @return [Page] Page of the search results
16
+ # @attribute query
17
+ # @return [Hash] Additional query to add
18
+ # @attribute range
19
+ # @return [String] String range in the service shell style
20
+ # @attribute return_count
21
+ # @return [Boolean] should this query return count (generally, no)
22
+ # @attribute return_entries
23
+ # @return [Boolean] should this query return entries
24
+ # @attribute service
25
+ # @return [String] service the query is for
26
+ # @attribute sort
27
+ # @return [String] string to sort in the service shell style
28
+ class Query
29
+ extend Creatable
30
+ attr_accessor :sort
31
+
32
+ attribute name: 'account', kind_of: String
33
+ attribute name: 'endpoint', kind_of: String
34
+ attribute name: 'extra_path', kind_of: String
35
+ attribute name: 'fields', kind_of: String
36
+ attribute name: 'ids', kind_of: Array
37
+ attribute name: 'page', kind_of: Driver::Page
38
+ attribute name: 'query', kind_of: Hash
39
+ attribute name: 'range', kind_of: String
40
+ attribute name: 'return_count', kind_of: FalseClass
41
+ attribute name: 'return_entries', kind_of: TrueClass
42
+ attribute name: 'service', kind_of: String
43
+ attribute name: 'sort', kind_of: String
44
+
45
+ # List of attributes availble
46
+ # @return [Symbol[]]
47
+ def attributes
48
+ %i[account endpoint extra_path fields ids query range return_count return_entries service sort]
49
+ end
50
+
51
+ # Instiatiate a page and query, set return's to false.
52
+ def initialize
53
+ @page = Driver::Page.new
54
+
55
+ @return_entries = true
56
+ @return_count = false
57
+ @query = {}
58
+ end
59
+
60
+ # List of entries created from the page
61
+ # @return [Entries] populated Entries object
62
+ def entries
63
+ Entries.create_from_page @page
64
+ end
65
+
66
+ # Run the query
67
+ # @param [User] user user to make calls with
68
+ # @return [Self]
69
+ def run(user: nil)
70
+ Driver::Helpers.required_arguments %i[user], binding
71
+ Driver::Exceptions.raise_unless_argument_error? user, User
72
+
73
+ raise "service must be set" unless service
74
+ raise "endpoint must be set" unless endpoint
75
+
76
+ response = Services::Data.get params.merge(user: user)
77
+ @page = response.page
78
+ self
79
+ end
80
+
81
+ # Hash representation of the query data. Has a key for params and for entries.
82
+ # @param [Boolean] include_entries include the entries array or not
83
+ # @return [Hash]
84
+ def to_h(include_entries: true)
85
+ h = {
86
+ params: params
87
+ }
88
+ h[:entries] = entries.to_h if include_entries
89
+ h
90
+ end
91
+
92
+ private
93
+
94
+ # List of parameters that are currently set in the query
95
+ # @return [Hash]
96
+ def params
97
+ output = {}
98
+
99
+ attributes.each do |attribute|
100
+ output.store attribute, instance_variable_get("@#{attribute}") unless instance_variable_get("@#{attribute}").nil?
101
+ end
102
+
103
+ unless output[:return_count].nil?
104
+ output[:count] = output.delete :return_count
105
+ end
106
+
107
+ unless output[:return_entries].nil?
108
+ output[:entries] = output.delete :return_entries
109
+ end
110
+
111
+ output
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,60 @@
1
+ module Cts
2
+ module Mpx
3
+ # Set of procedural functions to interact with the Registry.
4
+ module Registry
5
+ module_function
6
+
7
+ # Collection of domains stored in memory
8
+ # @return [Hash] key is an account_id, value is a hash of results
9
+ def domains
10
+ @domains
11
+ end
12
+
13
+ # Call fetch and store domain in sequence.
14
+ # @param [User] user user to make calls with
15
+ # @param [String] account_id long form account id (ownerId)
16
+ # @raise (see #fetch_domain)
17
+ # @return [Hash] hash of the newly fetched domain
18
+ def fetch_and_store_domain(user, account_id = 'urn:theplatform:auth:root')
19
+ result = fetch_domain user, account_id
20
+ store_domain result, account_id
21
+ domains[account_id]
22
+ end
23
+
24
+ # Fetch a domain from the registry.
25
+ # @param [User] user user to make calls with
26
+ # @param [String] account_id long form account id (ownerId)
27
+ # @raise [ArgumentError] if the user is not a user object
28
+ # @raise [ArgumentError] if the account_id is not valid
29
+ # @return [Hash] hash of the newly fetched domain
30
+ def fetch_domain(user, account_id = 'urn:theplatform:auth:root')
31
+ return domains['urn:theplatform:auth:root'] if account_id == 'urn:theplatform:auth:root'
32
+ Driver::Exceptions.raise_unless_argument_error?(user, 'User') { user.is_a? User }
33
+ Driver::Exceptions.raise_unless_argument_error?(account_id, 'account_id') { Validators.account_id? account_id }
34
+ user.token!
35
+
36
+ response = Services::Web.post user: user, service: 'Access Data Service', endpoint: 'Registry', method: 'resolveDomain', arguments: { 'accountId' => account_id }
37
+ response.data['resolveDomainResponse']
38
+ end
39
+
40
+ # Store the domain in memory
41
+ # @param [Hash] data collection received from Registry
42
+ # @param [String] account_id long form account id (ownerId)
43
+ # @raise [ArgumentError] if the data is not a valid hash
44
+ # @raise [ArgumentError] if the account_id is not valid
45
+ # @return [Void]
46
+ def store_domain(data, account_id = 'urn:theplatform:auth:root')
47
+ raise ArgumentError, "#{account_id} is not a valid account_id" unless Validators.account_id? account_id
48
+ raise ArgumentError, "#{data} is not a valid Hash" unless data.is_a? Hash
49
+ @domains.store account_id, data
50
+ nil
51
+ end
52
+
53
+ # find and store the root registry from the US
54
+ def initialize
55
+ @domains = {}
56
+ store_domain(Driver.load_json_file("#{Driver.config_dir}/root_registry_sea1.json")['resolveDomainResponse'], 'urn:theplatform:auth:root')
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,70 @@
1
+ module Cts
2
+ module Mpx
3
+ module Driver
4
+ # Class to wrap a service and what is available to interact with
5
+ # @attribute name
6
+ # @return [String] Title of the service, must be identical to the registry entry
7
+ # @attribute uri_hint
8
+ # @return [String] partial string of the uri, this allows for a reverse lookup from url
9
+ # @attribute path
10
+ # @return [String] prepended path statement attached per service
11
+ # @attribute form
12
+ # @return [String] type of http schema to use, can be json or cjson
13
+ # @attribute schema
14
+ # @return [String] version of the service schema
15
+ # @attribute search_schema
16
+ # @return [String] version of the search schema
17
+ # @attribute read_only
18
+ # @return [Boolean] is this a read only service or not
19
+ # @attribute endpoints
20
+ # @return [Array] Available endpoints to communicate with
21
+ # @attribute type
22
+ # @return [String] the type of service this is
23
+ class Service
24
+ attr_accessor :name
25
+ attr_accessor :uri_hint
26
+ attr_accessor :path
27
+ attr_accessor :form
28
+ attr_accessor :schema
29
+ attr_accessor :search_schema
30
+ attr_accessor :read_only
31
+ attr_accessor :endpoints
32
+ attr_accessor :type
33
+
34
+ # Set all values to something
35
+ def initialize
36
+ @name = ""
37
+ @uri_hint = ""
38
+ @path = ""
39
+ @form = ""
40
+ @schema = ""
41
+ @search_schema = ""
42
+ @read_only = false
43
+ @endpoints = []
44
+ @type = nil
45
+ @url = nil
46
+ end
47
+
48
+ # Return a given url of a service, will look in the local registry
49
+ # @param [String] account_id long form account id (ownerId)
50
+ # @return [String] the url string or nil if none available
51
+ def url(account_id = 'urn:theplatform:auth:root')
52
+ Exceptions.raise_unless_account_id account_id
53
+ reg = Registry.domains[account_id]
54
+ return reg[name] if reg
55
+ nil
56
+ end
57
+
58
+ # checks if we have a given entry in the local registry
59
+ # @param [String] account_id long form account id (ownerId)
60
+ # @return [Boolean] true if it is available, false if it is not
61
+ def url?(account_id = 'urn:theplatform:auth:root')
62
+ Exceptions.raise_unless_account_id account_id
63
+ u = url account_id
64
+ return true if u
65
+ false
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,113 @@
1
+ module Cts
2
+ module Mpx
3
+ # Container style module for the collection of services available.
4
+ module Services
5
+ module_function
6
+
7
+ # Addressable method, indexed by service title
8
+ # @param [String] key service title to look up the service object
9
+ # @raise [ArgumentError] if the key is not a service name
10
+ # @raise [ArgumentError] if the key is not a string
11
+ # @return [Service[]] if no key, return the entire array of services
12
+ # @return [Service] a service
13
+ def [](key = nil)
14
+ return @services unless key
15
+ raise 'key must be a string' unless key.is_a? String
16
+ service = @services.find { |e| e.name == key }
17
+ raise "#{key} must be a service name." unless service
18
+ service
19
+ end
20
+
21
+ # return a service from the supplied url
22
+ # @param [String] url url to parse
23
+ # @return [Hash] including service and endpoint as string.
24
+ def from_url(url)
25
+ service = Services[].find { |s| url.include? s.uri_hint if s.uri_hint }
26
+ return nil unless service
27
+
28
+ {
29
+ service: service.name,
30
+ endpoint: /data\/([A-Z].*)\//.match(url)[1]
31
+ }
32
+ end
33
+
34
+ # Load references and services from disk.
35
+ def initialize
36
+ load_references
37
+ load_services
38
+ end
39
+
40
+ # Load the specified reference file into the container
41
+ # @param [<Type>] file file to load
42
+ # @param [<Type>] type type of service the file contains
43
+ # @return [Void]
44
+ def load_reference_file(file: nil, type: nil)
45
+ raise ArgumentError, 'type must be supplied' unless type
46
+ raise ArgumentError, 'file must be supplied' unless file
47
+ @raw_reference.store(type, Driver.load_json_file(file))
48
+ true
49
+ end
50
+
51
+ # Load all available reference files into memory
52
+ # @return [Void]
53
+ def load_references
54
+ @raw_reference = {}
55
+ Services.types.each do |type|
56
+ gemdir = if Gem::Specification.find_all.map(&:name).include? 'cts-mpx'
57
+ Gem::Specification.find_by_name('cts-mpx').gem_dir
58
+ else
59
+ # :nocov:
60
+ Dir.pwd
61
+ # :nocov:
62
+ end
63
+
64
+ Services.load_reference_file(file: "#{gemdir}/config/#{type}_services.json", type: type.to_s)
65
+ end
66
+ end
67
+
68
+ # Convert the raw reference into a service and add it to the stack of available serrvices
69
+ # @return [Void]
70
+ def load_services
71
+ @services = []
72
+ raw_reference.each do |type, services|
73
+ services.each do |name, data|
74
+ s = Driver::Service.new
75
+ s.name = name
76
+ s.uri_hint = data['uri_hint']
77
+ s.path = data['path']
78
+ s.form = data['form']
79
+ s.schema = data['schema']
80
+ s.search_schema = data['search_schema']
81
+ s.read_only = data['read_only'] ? true : false
82
+ s.endpoints = data['endpoints']
83
+ s.type = type
84
+ s.instance_variable_set :@url, data['url'] if data['url']
85
+ @services.push s
86
+ end
87
+ end
88
+ end
89
+
90
+ # Raw copy of the reference files
91
+ # @return [Hash] key is name, value is the data
92
+ def raw_reference
93
+ @raw_reference
94
+ end
95
+
96
+ # Single reference from the raw collection.
97
+ # @param [String] key service title
98
+ # @return [Hash] values of the reference
99
+ def reference(key = nil)
100
+ return @raw_reference unless key
101
+ raise 'key must be a string' unless key.is_a? String
102
+ raise "#{key} is not in the reference library." unless @raw_reference.include? key
103
+ @raw_reference[key]
104
+ end
105
+
106
+ # list of possible types of services
107
+ # @return [Symbol[]] List of all types
108
+ def types
109
+ %i[web data ingest]
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,124 @@
1
+ module Cts
2
+ module Mpx
3
+ module Services
4
+ # Collection of procedural methods to interact with the Data services
5
+ # All of these methods mimic the DSS clients as close as possible
6
+ # If your operation does not work in the DSS client, it will not work here
7
+ module Data
8
+ module_function
9
+
10
+ # Addressable method, indexed by data service title
11
+ # @param [String] key service title to look up the service object
12
+ # @raise [ArgumentError] if the key is not a service name
13
+ # @raise [ArgumentError] if the key is not a string
14
+ # @return [Service[]] if no key, return the entire array of services
15
+ # @return [Service] a service
16
+ def [](key = nil)
17
+ services = Services[].select { |s| s.type == 'data' }
18
+ return services unless key
19
+ raise ArgumentError, 'key must be a string' unless key.is_a? String
20
+ service = services.find { |e| e.name == key }
21
+ raise ArgumentError, "#{key} must be a service name." unless service
22
+ service
23
+ end
24
+
25
+ # Procedural method to DELETE data from the data services
26
+ # @raise (see #get)
27
+ # @param (see #get)
28
+ # @return (see #get)
29
+ def delete(user: nil, account: nil, service: nil, endpoint: nil, sort: nil, extra_path: nil, range: nil, ids: nil, query: {}, headers: {}, count: nil, entries: nil)
30
+ get(user: user, account: account, service: service, endpoint: endpoint, sort: sort, extra_path: extra_path, range: range, ids: ids, query: query, headers: headers, count: count, entries: entries, method: :delete)
31
+ end
32
+
33
+ # Procedural method to GET data from the data services
34
+ # @param [Boolean] count ask for a count of objects from the services
35
+ # @param [Boolean] entries return an array of entries
36
+ # @param [User] user user to make calls with
37
+ # @param [Hash] query additional parameters to add to the http call
38
+ # @param [Hash] headers additional headers to attach to the http call
39
+ # @param [String] account context account id or name
40
+ # @param [String] endpoint endpoint to make the call against
41
+ # @param [String] extra_path additional part to add to the path
42
+ # @param [String] fields comma delimited list of fields to collect
43
+ # @param [String] ids comma delimited list of short id's to add to the path
44
+ # @param [String] range string (service) format of a range
45
+ # @param [String] service title of a service
46
+ # @param [String] sort set the sort field
47
+ # @raise (see #prep_call)
48
+ # @return [Response] Response of the call
49
+ def get(user: nil, account: nil, service: nil, fields: nil, endpoint: nil, sort: nil, extra_path: nil, range: nil, ids: nil, query: {}, headers: {}, count: nil, entries: nil, method: :get)
50
+ prep_call(user: user, account: account, service: service, query: query, headers: headers, required_arguments: ['user', 'service', 'endpoint'], binding: binding)
51
+
52
+ host = Driver::Assemblers.host user: user, service: service
53
+ path = Driver::Assemblers.path service: service, endpoint: endpoint, extra_path: extra_path, ids: ids
54
+ query = Driver::Assemblers.query user: user, account: account, service: service, endpoint: endpoint, query: query
55
+
56
+ if Services[service].type == 'data'
57
+ query.merge! Driver::Assemblers.query_data range: range, count: count, entries: entries, sort: sort
58
+ query[:fields] = fields if fields
59
+ end
60
+ request = Driver::Request.create(method: method, url: [host, path].join, query: query, headers: headers)
61
+ request.call
62
+ end
63
+
64
+ # Procedural method to POST data to the data services
65
+ # @param [Driver::Page] page formated page to send to the data services
66
+ # @param [User] user user to make calls with
67
+ # @param [Hash] query additional parameters to add to the http call
68
+ # @param [Query] headers additional headers to attach to the http call
69
+ # @param [String] account account context, can be id or name
70
+ # @param [String] endpoint endpoint to make the call against
71
+ # @param [String] extra_path additional part to add to the path
72
+ # @param [String] service title of a service
73
+ # @raise (see #prep_call)
74
+ # @return [Response] Response of the call
75
+ def post(user: nil, account: nil, service: nil, endpoint: nil, extra_path: nil, query: {}, page: nil, headers: {}, method: :post)
76
+ prep_call(user: user, account: account, service: service, query: query, headers: headers, required_arguments: ['user', 'service', 'endpoint', 'page'], page: page, binding: binding)
77
+
78
+ host = Driver::Assemblers.host user: user, service: service
79
+ path = Driver::Assemblers.path service: service, endpoint: endpoint, extra_path: extra_path
80
+ query = Driver::Assemblers.query user: user, account: account, service: service, endpoint: endpoint, query: query
81
+
82
+ request = Driver::Request.create(method: method, url: [host, path].join, query: query, headers: headers, payload: page.to_s)
83
+ request.call
84
+ end
85
+
86
+ # Procedural method to PUT data to the data services
87
+ # @param (see #post)
88
+ # @raise (see #post)
89
+ # @return (see #post)
90
+ def put(user: nil, account: nil, service: nil, endpoint: nil, extra_path: nil, query: {}, page: nil, headers: {})
91
+ post(user: user, account: account, service: service, endpoint: endpoint, extra_path: extra_path, query: query, page: page, headers: headers, method: :put)
92
+ end
93
+
94
+ # Helper method to assure that everything is is ok to call the methods above
95
+ # @param [Hash] args params to assure are correct
96
+ # @option args [Symbol] :account account to apply to account_context lookups
97
+ # @option args [Symbol] :binding local binding (goes with required arguments)
98
+ # @option args [Symbol] :headers header object to check
99
+ # @option args [Symbol] :page page to send to the data service
100
+ # @option args [Symbol] :query query object to test
101
+ # @option args [Symbol] :required_arguments list of arguments required
102
+ # @option args [Symbol] :service title of the service
103
+ # @option args [Symbol] :user user to make calls with
104
+ # @raise [ArgumentError] if :query or :headers values are not a Hash
105
+ # @raise [ArgumentError] if the :page value is not a Page
106
+ # @raise [ArgumentError] if the list of :required_arguments are not set
107
+ # @raise [ArgumentError] if the :user does not have a token
108
+ # @raise (see Registry#fetch_domain)
109
+ # @raise (see Registry#store_domain)
110
+ # @return [Response] Response of the call
111
+ # @private
112
+ def prep_call(args = {})
113
+ Driver::Helpers.required_arguments args[:required_arguments], args[:binding]
114
+ args[:user].token!
115
+ Driver::Helpers.raise_if_not_a_hash [args[:query], args[:headers]]
116
+
117
+ Driver::Helpers.raise_if_not_a([args[:page]], Driver::Page) if args[:page]
118
+
119
+ Registry.fetch_and_store_domain(args[:user], args[:account]) unless self[args[:service]].url?
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end