talis 0.12.0

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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +2 -0
  5. data/.travis.yml +24 -0
  6. data/.yardopts +1 -0
  7. data/CONTRIBUTING.md +28 -0
  8. data/Gemfile +4 -0
  9. data/Guardfile +5 -0
  10. data/README.md +76 -0
  11. data/Rakefile +8 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/lib/talis.rb +25 -0
  15. data/lib/talis/analytics.rb +31 -0
  16. data/lib/talis/analytics/event.rb +67 -0
  17. data/lib/talis/authentication.rb +14 -0
  18. data/lib/talis/authentication/client.rb +82 -0
  19. data/lib/talis/authentication/login.rb +169 -0
  20. data/lib/talis/authentication/public_key.rb +53 -0
  21. data/lib/talis/authentication/token.rb +172 -0
  22. data/lib/talis/bibliography.rb +52 -0
  23. data/lib/talis/bibliography/ebook.rb +50 -0
  24. data/lib/talis/bibliography/manifestation.rb +141 -0
  25. data/lib/talis/bibliography/result_set.rb +34 -0
  26. data/lib/talis/bibliography/work.rb +164 -0
  27. data/lib/talis/constants.rb +9 -0
  28. data/lib/talis/errors.rb +10 -0
  29. data/lib/talis/errors/authentication_failed_error.rb +4 -0
  30. data/lib/talis/errors/client_errors.rb +19 -0
  31. data/lib/talis/errors/server_communication_error.rb +4 -0
  32. data/lib/talis/errors/server_error.rb +4 -0
  33. data/lib/talis/extensions/object.rb +11 -0
  34. data/lib/talis/feeds.rb +8 -0
  35. data/lib/talis/feeds/annotation.rb +129 -0
  36. data/lib/talis/feeds/feed.rb +58 -0
  37. data/lib/talis/hierarchy.rb +9 -0
  38. data/lib/talis/hierarchy/asset.rb +265 -0
  39. data/lib/talis/hierarchy/node.rb +200 -0
  40. data/lib/talis/hierarchy/resource.rb +159 -0
  41. data/lib/talis/oauth_service.rb +18 -0
  42. data/lib/talis/resource.rb +68 -0
  43. data/lib/talis/user.rb +112 -0
  44. data/lib/talis/version.rb +3 -0
  45. data/talis.gemspec +39 -0
  46. metadata +327 -0
@@ -0,0 +1,9 @@
1
+ require_relative 'hierarchy/resource'
2
+ require_relative 'hierarchy/asset'
3
+ require_relative 'hierarchy/node'
4
+
5
+ module Talis
6
+ # Encompasses all classes associated with hierarchies
7
+ module Hierarchy
8
+ end
9
+ end
@@ -0,0 +1,265 @@
1
+ require 'blueprint_ruby_client'
2
+
3
+ module Talis
4
+ module Hierarchy
5
+ # Represents hierarchy asset API operations provided by the Blueprint gem:
6
+ # {https://github.com/talis/blueprint_rb}
7
+ #
8
+ # In order to perform remote operations, the client must be configured
9
+ # with a valid OAuth client that is allowed to query assets:
10
+ #
11
+ # Talis::Authentication.client_id = 'client_id'
12
+ # Talis::Authentication.client_secret = 'client_secret'
13
+ #
14
+ # @example Create an asset with attributes.
15
+ # node_options = {
16
+ # namespace: 'mynamespace',
17
+ # type: 'module',
18
+ # id: '1'
19
+ # }
20
+ # node = Talis::Hierarchy::Node.get(node_options)
21
+ # asset_options = {
22
+ # namespace: 'mynamespace',
23
+ # type: 'list',
24
+ # id: '1',
25
+ # nodes: [ node ]
26
+ # }
27
+ # asset = Talis::Hierarchy::Asset.new(asset_options)
28
+ # asset.save # Will raise an exception if this fails
29
+ # asset.attributes = { attr_key: 'my_attr_value' }
30
+ # asset.update
31
+ # @example Create an asset and associate it with multiple nodes.
32
+ # node1_options = {
33
+ # namespace: 'mynamespace',
34
+ # type: 'module',
35
+ # id: '1'
36
+ # }
37
+ # node2_options = {
38
+ # namespace: 'mynamespace',
39
+ # type: 'module',
40
+ # id: '2'
41
+ # }
42
+ # node1 = Talis::Hierarchy::Node.get(node1_options)
43
+ # node2 = Talis::Hierarchy::Node.get(node2_options)
44
+ # asset_options = {
45
+ # namespace: 'mynamespace',
46
+ # type: 'list',
47
+ # id: '1',
48
+ # nodes: [ node1, node2 ]
49
+ # }
50
+ # asset = Talis::Hierarchy::Asset.new(asset_options)
51
+ # asset.save
52
+ class Asset < Talis::Resource
53
+ extend Talis::OAuthService
54
+ include Talis::Hierarchy::Resource
55
+
56
+ base_uri Talis::BLUEPRINT_HOST
57
+
58
+ # @return [Array<BlueprintClient::Node>] An array of nodes an
59
+ # asset can belong to.
60
+ attr_accessor :nodes
61
+
62
+ # Create a non-persisted asset.
63
+ # @param namespace [String] the namespace of the hierarchy.
64
+ # @param type [String] the type of asset.
65
+ # @param id [String] the ID of the asset.
66
+ # @param nodes [Array<BlueprintClient::Node>] an array of nodes
67
+ # an asset can belong to.
68
+ # @param attributes [Hash]({}) key-value pair attributes belonging to the
69
+ # asset.
70
+ def initialize(namespace:, type:, id:, nodes: [], attributes: {})
71
+ @namespace = namespace
72
+ @id = id
73
+ @type = type
74
+ @nodes = nodes
75
+ @attributes = attributes
76
+ @new_resource = true
77
+ end
78
+
79
+ # Persist the asset to the hierarchy.
80
+ # @param request_id [String] ('uuid') unique ID for the remote request.
81
+ # @return [Array<BlueprintClient::Asset>] the created asset.
82
+ # @raise [Talis::ClientError] if the request was invalid.
83
+ # @raise [Talis::ServerError] if the save failed on the
84
+ # server.
85
+ # @raise [Talis::ServerCommunicationError] for network issues.
86
+ def save(request_id: self.class.new_req_id)
87
+ add_to_nodes request_id
88
+ mark_persisted if @nodes.count > 1
89
+ rescue BlueprintClient::ApiError => error
90
+ self.class.handle_response(error)
91
+ end
92
+
93
+ # Update an existing asset.
94
+ # @param request_id [String] ('uuid') unique ID for the remote request.
95
+ # @raise [Talis::ClientError] if the request was invalid.
96
+ # @raise [Talis::ServerError] if the update failed on the server.
97
+ # @raise [Talis::ServerCommunicationError] for network issues.
98
+ def update(request_id: self.class.new_req_id)
99
+ body = BlueprintClient::AssetBody.new(data: {
100
+ id: @id,
101
+ type: @type,
102
+ attributes: @attributes
103
+ })
104
+ self.class.api_client(request_id).replace_asset(@namespace, stored_id,
105
+ stored_type, body: body)
106
+ mark_persisted
107
+ rescue BlueprintClient::ApiError => error
108
+ self.class.handle_response(error)
109
+ end
110
+
111
+ # Delete an existing asset.
112
+ # @param request_id [String] ('uuid') unique ID for the remote request.
113
+ # @raise [Talis::ClientError] if the request was invalid.
114
+ # @raise [Talis::ServerError] if the delete failed on the server.
115
+ # @raise [Talis::ServerCommunicationError] for network issues.
116
+ def delete(request_id: self.class.new_req_id)
117
+ self.class.api_client(request_id).delete_asset(@namespace, stored_id,
118
+ stored_type)
119
+ mark_deleted
120
+ rescue BlueprintClient::ApiError => error
121
+ self.class.handle_response(error)
122
+ end
123
+
124
+ private
125
+
126
+ # Internal part of save method. Adds asset to nodes
127
+ # @param request_id [String] ('uuid') unique ID for the remote request.
128
+ def add_to_nodes(request_id)
129
+ @nodes.each { |node| add_to_node(request_id, node) }
130
+ end
131
+
132
+ # Internal part of save method. Adds asset to node
133
+ # @param request_id [String] ('uuid') unique ID for the remote request.
134
+ # @param node [BlueprintClient::Node] The node the asset should be
135
+ # added to.
136
+ def add_to_node(request_id, node)
137
+ self.class.api_client(request_id).add_asset_to_node(@namespace,
138
+ node.type,
139
+ node.id,
140
+ @type,
141
+ @id)
142
+ rescue BlueprintClient::ApiError => error
143
+ raise error unless error.code == 409
144
+ # Already associated with node - do not error
145
+ end
146
+
147
+ # rubocop:disable Metrics/LineLength
148
+ class << self
149
+ # Search for assets in the hierarchy for the given namespace and node.
150
+ # @param request_id [String] ('uuid') unique ID for the remote request.
151
+ # @param namespace [String] the namespace of the hierarchy.
152
+ # @param type [String] the type of node the assets belong to.
153
+ # @param id [String] the ID of the node the assets belong to.
154
+ # @param opts [Hash] ({}) optional filter and pagination criteria.
155
+ # see {https://github.com/talis/blueprint_rb/blob/master/docs/AssetsApi.md#get_assets_in_node}
156
+ # @return [Array<Talis::Hierarchy::Asset>] or an empty array if no
157
+ # assets are found.
158
+ # @raise [Talis::ClientError] if the request was invalid.
159
+ # @raise [Talis::ServerError] if the search failed on the
160
+ # server.
161
+ # @raise [Talis::ServerCommunicationError] for network issues.
162
+ def find_by_node(request_id: new_req_id, namespace:, type:, id:, opts: {})
163
+ data = api_client(request_id).get_assets_in_node(namespace, type,
164
+ id, opts).data
165
+ data.map! { |asset| build(asset, namespace) }
166
+ rescue BlueprintClient::ApiError => error
167
+ handle_blueprint_api_error(error)
168
+ end
169
+
170
+ # Search for assets in the hierarchy for the given namespace.
171
+ # @param request_id [String] ('uuid') unique ID for the remote request.
172
+ # @param namespace [String] the namespace of the hierarchy.
173
+ # @param opts [Hash] ({}) optional filter and pagination criteria.
174
+ # see {https://github.com/talis/blueprint_rb/blob/master/docs/AssetsApi.md#search_assets}
175
+ # One exception to the options listed above are filters which take
176
+ # the following format, for example:
177
+ # Return assets that are related to any nodes specified in the array.
178
+ #
179
+ # filter_node: ['type/id', 'type/id']
180
+ #
181
+ # As above but explicitly requesting an any match:
182
+ #
183
+ # filter_node: { any: ['type/id', 'type/id'] }
184
+ #
185
+ # Return assets that are related to all nodes specified in the array.
186
+ #
187
+ # filter_node: { all: ['type/id', 'type/id'] }
188
+ # @return [Array<Talis::Hierarchy::Asset>] or an empty array if no
189
+ # assets are found.
190
+ # @raise [Talis::ClientError] if the request was invalid.
191
+ # @raise [Talis::ServerError] if the search failed on the server.
192
+ # @raise [Talis::ServerCommunicationError] for network issues.
193
+ def where(request_id: new_req_id, namespace:, opts: {})
194
+ # search_assets method in resource module uses HTTParty not
195
+ # blueprint_rb to call the API to get around the Swagger limitation
196
+ # of not being able to choose between AND and IN queries.
197
+ data = search_assets(request_id, namespace, opts)
198
+ data.map! { |asset| build(asset, namespace) }
199
+ rescue Talis::NotFoundError
200
+ []
201
+ end
202
+
203
+ # Return all assets in the hierarchy for the given namespace.
204
+ # @param request_id [String] ('uuid') unique ID for the remote request.
205
+ # @param namespace [String] the namespace of the hierarchy.
206
+ # @return [Array<Talis::Hierarchy::Asset>] or an empty array if no
207
+ # assets are found.
208
+ # @raise [Talis::ClientError] if the request was invalid.
209
+ # @raise [Talis::ServerError] if the search failed on the server.
210
+ # @raise [Talis::ServerCommunicationError] for network issues.
211
+ def all(request_id: new_req_id, namespace:)
212
+ where(request_id: request_id, namespace: namespace)
213
+ end
214
+
215
+ # Fetch a single asset from the hierarchy for the given namespace.
216
+ # @param request_id [String] ('uuid') unique ID for the remote request.
217
+ # @param namespace [String] the namespace of the hierarchy.
218
+ # @param type [String] the type of asset to fetch.
219
+ # @param id [String] the ID of the asset to fetch.
220
+ # @return Talis::Hierarchy::Asset or nil if the asset cannot be found.
221
+ # @raise [Talis::ClientError] if the request was invalid.
222
+ # @raise [Talis::ServerError] if the fetch failed on the
223
+ # server.
224
+ # @raise [Talis::ServerCommunicationError] for network issues.
225
+ def find(request_id: new_req_id, namespace:, type:, id:)
226
+ data = api_client(request_id).get_asset(namespace, type, id).data
227
+ build(data, namespace)
228
+ rescue BlueprintClient::ApiError => error
229
+ handle_blueprint_api_error(error, false)
230
+ end
231
+
232
+ # Exposes the underlying Blueprint assets API client.
233
+ # @param request_id [String] ('uuid') unique ID for remote requests.
234
+ # @return BlueprintClient::AssetsApi
235
+ def api_client(request_id = new_req_id)
236
+ configure_blueprint
237
+
238
+ api_client = BlueprintClient::ApiClient.new
239
+ api_client.default_headers = {
240
+ 'X-Request-Id' => request_id,
241
+ 'User-Agent' => "talis-ruby-client/#{Talis::VERSION} "\
242
+ "ruby/#{RUBY_VERSION}"
243
+ }
244
+
245
+ BlueprintClient::AssetsApi.new(api_client)
246
+ end
247
+
248
+ private
249
+
250
+ def build(data, namespace)
251
+ asset = new(namespace: namespace, type: data.type, id: data.id,
252
+ attributes: data.attributes ? data.attributes : {})
253
+ asset.instance_variable_set(:@new_resource, false)
254
+ asset
255
+ end
256
+
257
+ def handle_blueprint_api_error(error, return_empty_array = true)
258
+ handle_response(error)
259
+ rescue Talis::NotFoundError
260
+ return_empty_array ? [] : nil
261
+ end
262
+ end
263
+ end
264
+ end
265
+ end
@@ -0,0 +1,200 @@
1
+ require 'blueprint_ruby_client'
2
+
3
+ module Talis
4
+ module Hierarchy
5
+ # Represents hierarchy node API operations provided by the Blueprint gem:
6
+ # {https://github.com/talis/blueprint_rb}
7
+ #
8
+ # In order to perform remote operations, the client must be configured
9
+ # with a valid OAuth client that is allowed to query nodes:
10
+ #
11
+ # Talis::Authentication.client_id = 'client_id'
12
+ # Talis::Authentication.client_secret = 'client_secret'
13
+ #
14
+ class Node < Talis::Resource
15
+ extend Talis::OAuthService
16
+ include Talis::Hierarchy::Resource
17
+
18
+ base_uri Talis::BLUEPRINT_HOST
19
+
20
+ def initialize(id:, type:, namespace:, attributes: {})
21
+ @id = id
22
+ @type = type
23
+ @namespace = namespace
24
+ @attributes = attributes
25
+ end
26
+
27
+ # rubocop:disable Metrics/LineLength
28
+ class << self
29
+ # Search for nodes in the hierarchy for the given namespace.
30
+ # @param request_id [String] ('uuid') unique ID for the remote request.
31
+ # @param namespace [String] the namespace of the hierarchy.
32
+ # @param opts [Hash] ({}) optional filter and pagination criteria.
33
+ # see {https://github.com/talis/blueprint_rb/blob/master/docs/HierarchyApi.md#search_nodes}
34
+ # @return [Hash] containing data and meta attributes. The structure
35
+ # as follows:
36
+ # {
37
+ # data: [node1, node2, node3, node4, node5],
38
+ # meta: { offset: 0, count: 20, limit: 5 }
39
+ # }
40
+ # where nodes are of type BlueprintClient::Node
41
+ # @raise [Talis::ClientError] if the request was invalid.
42
+ # @raise [Talis::ServerError] if the search failed on the
43
+ # server.
44
+ # @raise [Talis::ServerCommunicationError] for network issues.
45
+ def find(request_id: new_req_id, namespace:, opts: {})
46
+ api_client(request_id).search_nodes(namespace, opts)
47
+ rescue BlueprintClient::ApiError => error
48
+ handle_response(error)
49
+ end
50
+
51
+ # Fetch a single node from the hierarchy for the given namespace.
52
+ # @param request_id [String] ('uuid') unique ID for the remote request.
53
+ # @param namespace [String] the namespace of the hierarchy.
54
+ # @param type [String] the type of node to fetch.
55
+ # @param id [String] the ID of the node to fetch.
56
+ # @return BlueprintClient::Node or nil if the node cannot be found.
57
+ # @raise [Talis::ClientError] if the request was invalid.
58
+ # @raise [Talis::ServerError] if the fetch failed on the
59
+ # server.
60
+ # @raise [Talis::ServerCommunicationError] for network issues.
61
+ def get(request_id: new_req_id, namespace:, type:, id:)
62
+ api_client(request_id).get_node(namespace, id, type).data
63
+ rescue BlueprintClient::ApiError => error
64
+ begin
65
+ handle_response(error)
66
+ rescue Talis::NotFoundError
67
+ nil
68
+ end
69
+ end
70
+
71
+ # Fetch all parents belonging to the specified node from the hierarchy
72
+ # for the given namespace.
73
+ # @param request_id [String] ('uuid') unique ID for the remote request.
74
+ # @param namespace [String] the namespace of the hierarchy.
75
+ # @param type [String] the type of node whose parents are to be fetched.
76
+ # @param id [String] the ID of the node whose parents are to be fetched.
77
+ # @param opts [Hash] ({}) optional filter and pagination criteria.
78
+ # see {https://github.com/talis/blueprint_rb/blob/master/docs/HierarchyApi.md#get_parents}
79
+ # @return BlueprintClient::Node or nil if the node cannot be found.
80
+ # @raise [Talis::ClientError] if the request was invalid.
81
+ # @raise [Talis::ServerError] if the fetch failed on the
82
+ # server.
83
+ # @raise [Talis::ServerCommunicationError] for network issues.
84
+ def parents(request_id: new_req_id, namespace:, type:, id:, opts: {})
85
+ api_client(request_id).get_parents(id, namespace, type, opts).data
86
+ rescue BlueprintClient::ApiError => error
87
+ handle_response(error)
88
+ end
89
+
90
+ # Fetch all children belonging to the specified node from the hierarchy
91
+ # for the given namespace.
92
+ # @param request_id [String] ('uuid') unique ID for the remote request.
93
+ # @param namespace [String] the namespace of the hierarchy.
94
+ # @param type [String] the type of node whose children are to be
95
+ # fetched.
96
+ # @param id [String] the ID of the node whose children are to be
97
+ # fetched.
98
+ # @param opts [Hash] ({}) optional filter and pagination criteria.
99
+ # see {https://github.com/talis/blueprint_rb/blob/master/docs/HierarchyApi.md#get_children}
100
+ # @return BlueprintClient::Node or nil if the node cannot be found.
101
+ # @raise [Talis::ClientError] if the request was invalid.
102
+ # @raise [Talis::ServerError] if the fetch failed on the
103
+ # server.
104
+ # @raise [Talis::ServerCommunicationError] for network issues.
105
+ def children(request_id: new_req_id, namespace:, type:, id:, opts: {})
106
+ api_client(request_id).get_children(id, namespace, type, opts).data
107
+ rescue BlueprintClient::ApiError => error
108
+ handle_response(error)
109
+ end
110
+
111
+ # Fetch all ancestors belonging to the specified node from the hierarchy
112
+ # for the given namespace.
113
+ # @param request_id [String] ('uuid') unique ID for the remote request.
114
+ # @param namespace [String] the namespace of the hierarchy.
115
+ # @param type [String] the type of node whose ancestors are to be
116
+ # fetched.
117
+ # @param id [String] the ID of the node whose ancestors are to be
118
+ # fetched.
119
+ # @param opts [Hash] ({}) optional filter and pagination criteria.
120
+ # see {https://github.com/talis/blueprint_rb/blob/master/docs/HierarchyApi.md#get_ancestors}
121
+ # @return BlueprintClient::Node or nil if the node cannot be found.
122
+ # @raise [Talis::ClientError] if the request was invalid.
123
+ # @raise [Talis::ServerError] if the fetch failed on the
124
+ # server.
125
+ # @raise [Talis::ServerCommunicationError] for network issues.
126
+ def ancestors(request_id: new_req_id, namespace:, type:, id:, opts: {})
127
+ api_client(request_id).get_ancestors(id, namespace, type, opts).data
128
+ rescue BlueprintClient::ApiError => error
129
+ handle_response(error)
130
+ end
131
+
132
+ # Fetch all descendants belonging to the specified node from the hierarchy
133
+ # for the given namespace.
134
+ # @param request_id [String] ('uuid') unique ID for the remote request.
135
+ # @param namespace [String] the namespace of the hierarchy.
136
+ # @param type [String] the type of node whose descendants are to be
137
+ # fetched.
138
+ # @param id [String] the ID of the node whose descendants are to be
139
+ # fetched.
140
+ # @param opts [Hash] ({}) optional filter and pagination criteria.
141
+ # see {https://github.com/talis/blueprint_rb/blob/master/docs/HierarchyApi.md#get_descendants}
142
+ # @return BlueprintClient::Node or nil if the node cannot be found.
143
+ # @raise [Talis::ClientError] if the request was invalid.
144
+ # @raise [Talis::ServerError] if the fetch failed on the
145
+ # server.
146
+ # @raise [Talis::ServerCommunicationError] for network issues.
147
+ def descendants(request_id: new_req_id, namespace:, type:, id:, opts: {})
148
+ api_client(request_id).get_descendants(id, namespace, type, opts).data
149
+ rescue BlueprintClient::ApiError => error
150
+ handle_response(error)
151
+ end
152
+
153
+ # Create a new node
154
+ # @param request_id [String] ('uuid') unique ID for the remote request.
155
+ # @param namespace [String] the namespace of hierarchy.
156
+ # @param type [String]
157
+ # @param id [String]
158
+ # @param attributes [Hash]
159
+ # see {https://github.com/talis/blueprint_rb/blob/master/docs/HierarchyApi.md#add_node}
160
+ # @return [Talis::Hierarchy::Node]
161
+ def create(request_id: new_req_id, namespace:, type:, id:, attributes: {})
162
+ new_node = {
163
+ data: {
164
+ id: id,
165
+ type: type,
166
+ attributes: attributes
167
+ }
168
+ }
169
+
170
+ build(api_client(request_id).add_node(namespace, new_node, {}).data, namespace)
171
+ rescue BlueprintClient::ApiError => error
172
+ handle_response(error)
173
+ end
174
+
175
+ # Exposes the underlying Blueprint nodes API client.
176
+ # @param request_id [String] ('uuid') unique ID for remote requests.
177
+ # @return BlueprintClient::HierarchyApi
178
+ def api_client(request_id = new_req_id)
179
+ configure_blueprint
180
+
181
+ api_client = BlueprintClient::ApiClient.new
182
+ api_client.default_headers = {
183
+ 'X-Request-Id' => request_id,
184
+ 'User-Agent' => "talis-ruby-client/#{Talis::VERSION} "\
185
+ "ruby/#{RUBY_VERSION}"
186
+ }
187
+
188
+ BlueprintClient::HierarchyApi.new(api_client)
189
+ end
190
+
191
+ private
192
+
193
+ def build(data, namespace)
194
+ new(id: data.id, type: data.type, namespace: namespace,
195
+ attributes: data.attributes)
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end