helix 0.0.2.7.pre → 0.0.2.8.pre
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.
- data/README.md +11 -74
- data/lib/helix.rb +2 -0
- data/lib/helix/album.rb +1 -1
- data/lib/helix/base.rb +23 -3
- data/lib/helix/config.rb +38 -4
- data/lib/helix/durationed_media.rb +5 -5
- data/lib/helix/library.rb +3 -1
- data/lib/helix/media.rb +3 -62
- data/lib/helix/restful.rb +89 -0
- data/lib/helix/track.rb +2 -0
- data/lib/helix/uploadable.rb +52 -0
- data/lib/helix/video.rb +42 -16
- data/spec/album_spec.rb +2 -1
- data/spec/base_spec.rb +50 -73
- data/spec/config_spec.rb +82 -1
- data/spec/durationed_media_spec.rb +2 -1
- data/spec/image_spec.rb +2 -1
- data/spec/library_spec.rb +14 -9
- data/spec/media_spec.rb +80 -43
- data/spec/tag_spec.rb +1 -1
- data/spec/track_spec.rb +117 -5
- data/spec/video_spec.rb +188 -8
- metadata +24 -23
data/README.md
CHANGED
@@ -44,11 +44,10 @@ rake reinstall_helix_rvm
|
|
44
44
|
|
45
45
|
Using gem in a Gemfile
|
46
46
|
```shell
|
47
|
-
gem 'helix', :git => git@github.com:Twistage/helix.git
|
47
|
+
gem 'helix', :git => 'git@github.com:Twistage/helix.git'
|
48
48
|
```
|
49
49
|
|
50
50
|
|
51
|
-
|
52
51
|
Supported Ruby versions
|
53
52
|
-----------------------
|
54
53
|
|
@@ -57,88 +56,26 @@ Supported Ruby versions
|
|
57
56
|
|
58
57
|
How To
|
59
58
|
------
|
60
|
-
Warning: How To is not currently finished, it may be inaccurate.
|
61
59
|
###Setup YAML
|
62
60
|
```yaml
|
63
61
|
site: 'http://service.twistage.com'
|
64
|
-
user: 'my_account@twistage.com'
|
65
|
-
password: 'password123'
|
66
62
|
company: 'my_company'
|
67
|
-
license_key: '141a86b5c4091
|
63
|
+
license_key: '141a86b5c4091'
|
64
|
+
library_id: 'development'
|
65
|
+
```
|
66
|
+
Boot up IRB in your console
|
67
|
+
```shell
|
68
|
+
irb
|
68
69
|
```
|
69
70
|
Load the YAML file as your config.
|
70
71
|
```ruby
|
72
|
+
require 'helix'
|
71
73
|
Helix::Config.load("path/to/yaml.yml")
|
74
|
+
videos = Helix::Video.find_all
|
72
75
|
```
|
73
|
-
####Current CRUD methods supported by all models
|
74
|
-
.create
|
75
|
-
.find
|
76
|
-
\#update
|
77
|
-
\#destroy
|
78
76
|
|
79
|
-
|
80
|
-
Videos, Images, Albums, Tracks, Playlists
|
77
|
+
If no file is passed in Helix with default to './helix.yml'
|
81
78
|
|
82
|
-
###Videos
|
83
|
-
#####Required fields: title, description, library, company, and source.
|
84
|
-
```ruby
|
85
|
-
video = Helix::Video.create!( title: 'New Video',
|
86
|
-
description: 'A video of new things',
|
87
|
-
source: 'http://somesource.com/source.mp4'
|
88
|
-
company: 'some_company',
|
89
|
-
library: 'some_library')
|
90
|
-
video.update({title: "New Title"})
|
91
|
-
another_video = Helix::Video.find(some_guid)
|
92
|
-
another_video.destroy
|
93
|
-
```
|
94
|
-
###Albums
|
95
|
-
#####Required fields: title, library, company.
|
96
|
-
```ruby
|
97
|
-
album = Helix::Album.create!( title: 'New Album',
|
98
|
-
description: 'A album of new things',
|
99
|
-
source: 'http://somesource.com/source.mp4'
|
100
|
-
company: 'some_company',
|
101
|
-
library: 'some_library')
|
102
|
-
#Update for album is not currently supported
|
103
|
-
another_album = Helix::Album.find(some_guid)
|
104
|
-
another_album.destroy
|
105
|
-
```
|
106
|
-
###Images
|
107
|
-
#####Required fields: title, description, library, company, and source.
|
108
|
-
```ruby
|
109
|
-
image = Helix::Image.create!( title: 'New Image',
|
110
|
-
description: 'A image of new things',
|
111
|
-
source: 'http://somesource.com/source.jpg'
|
112
|
-
company: 'some_company',
|
113
|
-
library: 'some_library')
|
114
|
-
image.update({title: "New Title"})
|
115
|
-
another_image = Helix::Image.find(some_guid)
|
116
|
-
another_image.destroy
|
117
|
-
```
|
118
|
-
###Tracks
|
119
|
-
#####Required fields: title, description, library, company, and source.
|
120
|
-
```ruby
|
121
|
-
track = Helix::Track.create!( title: 'New Track',
|
122
|
-
description: 'A track of new things',
|
123
|
-
source: 'http://somesource.com/source.mp3'
|
124
|
-
company: 'some_company',
|
125
|
-
library: 'some_library')
|
126
|
-
track.update({title: "New Title"})
|
127
|
-
another_track = Helix::Track.find(some_guid)
|
128
|
-
another_track.destroy
|
129
|
-
```
|
130
|
-
###Playlists
|
131
|
-
#####Required fields: title, library, company.
|
132
|
-
```ruby
|
133
|
-
playlist = Helix::Playlist.create!( title: 'New Playlist',
|
134
|
-
description: 'A playlist of new things',
|
135
|
-
source: 'http://somesource.com/source.mp4'
|
136
|
-
company: 'some_company',
|
137
|
-
library: 'some_library')
|
138
|
-
playlist.update({title: "New Title"})
|
139
|
-
another_playlist = Helix::Playlist.find(some_guid)
|
140
|
-
another_playlist.destroy
|
141
|
-
```
|
142
79
|
|
143
80
|
More Information
|
144
81
|
----------------
|
@@ -163,4 +100,4 @@ The names and logos for twistage are trademarks of Twistage, Inc.
|
|
163
100
|
License
|
164
101
|
-------
|
165
102
|
|
166
|
-
Helix is Copyright © 2008-2012 Twistage, Inc.
|
103
|
+
Helix is Copyright © 2008-2012 Twistage, Inc.
|
data/lib/helix.rb
CHANGED
data/lib/helix/album.rb
CHANGED
data/lib/helix/base.rb
CHANGED
@@ -3,6 +3,7 @@ require 'json'
|
|
3
3
|
require 'yaml'
|
4
4
|
require 'nori'
|
5
5
|
require 'time'
|
6
|
+
require 'helix/exceptions'
|
6
7
|
|
7
8
|
module Helix
|
8
9
|
class Base
|
@@ -23,6 +24,7 @@ module Helix
|
|
23
24
|
# @param [Hash] opts a hash of options for parameters passed into the HTTP GET
|
24
25
|
# @return [Array] The array of instance objects for a class.
|
25
26
|
def self.find_all(original_opts={})
|
27
|
+
raise Helix::NoConfigurationLoaded.new if config.nil?
|
26
28
|
opts = original_opts.clone
|
27
29
|
RestClient.log = 'helix.log' if opts.delete(:log)
|
28
30
|
data_sets = get_data_sets(opts)
|
@@ -49,11 +51,11 @@ module Helix
|
|
49
51
|
# @param [Hash] opts a hash of options for parameters passed into the HTTP GET
|
50
52
|
# @return [Array] The array of attributes (for a model) in hash form.
|
51
53
|
def self.get_data_sets(opts)
|
54
|
+
label = self.plural_resource_label
|
52
55
|
url = config.build_url(content_type: opts[:content_type] || :xml,
|
53
|
-
resource_label:
|
56
|
+
resource_label: label)
|
54
57
|
# We allow opts[:sig_type] for internal negative testing only.
|
55
|
-
|
56
|
-
data_sets = raw_response[plural_resource_label]
|
58
|
+
data_sets = config.get_aggregated_data_sets(url, label, {sig_type: :view}.merge(opts))
|
57
59
|
end
|
58
60
|
|
59
61
|
# Creates a string that associates to the class id.
|
@@ -120,6 +122,14 @@ module Helix
|
|
120
122
|
end
|
121
123
|
alias_method :reload, :load
|
122
124
|
|
125
|
+
def to_json
|
126
|
+
{resource_label_sym => @attributes}.to_json
|
127
|
+
end
|
128
|
+
|
129
|
+
def to_xml
|
130
|
+
modified_attributes.to_xml({root: resource_label_sym})
|
131
|
+
end
|
132
|
+
|
123
133
|
# Raises an error for missing method calls.
|
124
134
|
#
|
125
135
|
# @param [Symbol] method_sym The method attempting to be called.
|
@@ -171,6 +181,16 @@ module Helix
|
|
171
181
|
attrs.merge({'custom_fields' => cfs})
|
172
182
|
end
|
173
183
|
|
184
|
+
def modified_attributes
|
185
|
+
custom_fields = @attributes['custom_fields']
|
186
|
+
return @attributes if custom_fields.nil?
|
187
|
+
return @attributes if custom_fields.first['name'].nil?
|
188
|
+
new_cfs = custom_fields.inject({}) do |memo,cf|
|
189
|
+
memo.merge(cf['name'] => cf['value'])
|
190
|
+
end
|
191
|
+
@attributes.merge('custom_fields' => new_cfs)
|
192
|
+
end
|
193
|
+
|
174
194
|
def self.resource_label_sym
|
175
195
|
to_s.split('::').last.singularize.downcase.to_sym
|
176
196
|
end
|
data/lib/helix/config.rb
CHANGED
@@ -12,14 +12,16 @@ module Helix
|
|
12
12
|
|
13
13
|
unless defined?(self::DEFAULT_FILENAME)
|
14
14
|
DEFAULT_FILENAME = './helix.yml'
|
15
|
+
ITEMS_PER_PAGE = 100
|
15
16
|
SCOPES = [:reseller, :company, :library]
|
16
17
|
SIG_DURATION = 1200 # in minutes
|
18
|
+
STARTING_PAGE = 1
|
17
19
|
TIME_OFFSET = 1000 * 60 # 1000 minutes, lower to give some margin of error
|
18
20
|
VALID_SIG_TYPES = [ :ingest, :update, :view ]
|
19
21
|
end
|
20
22
|
|
21
23
|
attr_accessor :credentials
|
22
|
-
attr_reader :signature_for, :signature_expiration_for
|
24
|
+
attr_reader :response, :signature_for, :signature_expiration_for
|
23
25
|
|
24
26
|
# Creates a singleton of itself, setting the config
|
25
27
|
# to a specified YAML file. If no file is specified the default
|
@@ -72,6 +74,25 @@ module Helix
|
|
72
74
|
@signature_expiration_for = {}
|
73
75
|
end
|
74
76
|
|
77
|
+
# Makes aggregated calls to get_response with pagination
|
78
|
+
# folding/injecting/accumulating the results into a single output set.
|
79
|
+
#
|
80
|
+
# @param [String] url the base part of the URL to be used
|
81
|
+
# @param [String] plural_resource_label: "videos", "tracks", etc.
|
82
|
+
# @param [Hash] original_opts a hash of options for building URL additions
|
83
|
+
# @return [Array] The accumulated attribute Hashes for ORM instances
|
84
|
+
def get_aggregated_data_sets(url, plural_resource_label, original_opts={})
|
85
|
+
data_sets, page, per_page = [], STARTING_PAGE
|
86
|
+
until last_page?
|
87
|
+
aggregation_opts = original_opts.merge(page: page, per_page: ITEMS_PER_PAGE)
|
88
|
+
raw_response = get_response(url, {sig_type: :view}.merge(aggregation_opts))
|
89
|
+
data_set = raw_response[plural_resource_label]
|
90
|
+
data_sets += data_set if data_set
|
91
|
+
page += 1
|
92
|
+
end
|
93
|
+
data_sets
|
94
|
+
end
|
95
|
+
|
75
96
|
# Creates the base url with information collected from credentials.
|
76
97
|
#
|
77
98
|
# @param [Hash] opts a hash of options for building URL
|
@@ -93,19 +114,31 @@ module Helix
|
|
93
114
|
# with the base_url to create RESTful URLs
|
94
115
|
#
|
95
116
|
# @param [String] url the base part of the URL to be used
|
96
|
-
# @param [Hash]
|
117
|
+
# @param [Hash] original_opts a hash of options for building URL additions
|
97
118
|
# @return [String] The full RESTful URL string object
|
98
119
|
def get_response(url, original_opts={})
|
99
120
|
opts = original_opts.clone
|
100
121
|
sig_type = opts.delete(:sig_type)
|
101
122
|
params = opts.merge(signature: signature(sig_type, opts))
|
102
|
-
response
|
103
|
-
parse_response_by_url_format(response, url)
|
123
|
+
@response = RestClient.get(url, params: params)
|
124
|
+
parse_response_by_url_format(@response, url)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Reports whether the most recent response's headers have a true :is_last_page value
|
128
|
+
#
|
129
|
+
# @return [Boolean] As above. Returns false if no such header is found,
|
130
|
+
# or if there is an explictly false value.
|
131
|
+
def last_page?
|
132
|
+
return false unless @response
|
133
|
+
return false unless @response.headers
|
134
|
+
@response.headers.has_key?(:is_last_page) and
|
135
|
+
@response.headers[:is_last_page] == "true"
|
104
136
|
end
|
105
137
|
|
106
138
|
# Fetches the signature for a specific license key.
|
107
139
|
#
|
108
140
|
# @param [Symbol] sig_type The type of signature required for calls.
|
141
|
+
# @param [Hash] opts allows you to overide contributor and license_id
|
109
142
|
# @return [String] The signature needed to pass around for calls.
|
110
143
|
def signature(sig_type, opts={})
|
111
144
|
prepare_signature_memoization
|
@@ -181,6 +214,7 @@ module Helix
|
|
181
214
|
|
182
215
|
def url_for(sig_type, opts={})
|
183
216
|
contributor, library_id = [:contributor, :library_id].map { |key| opts[key] }
|
217
|
+
contributor ||= credentials[:contributor]
|
184
218
|
url = "#{credentials[:site]}/api/#{sig_type}_key?licenseKey=#{credentials[:license_key]}&duration=#{SIG_DURATION}"
|
185
219
|
url += "&contributor=#{contributor}" if contributor
|
186
220
|
url += "&library_id=#{library_id}" if library_id
|
@@ -5,8 +5,8 @@ module Helix
|
|
5
5
|
module ClassMethods
|
6
6
|
|
7
7
|
# Used to import tracks from a URL into the Twistage system.
|
8
|
-
#
|
9
|
-
#
|
8
|
+
# API doc reference: /doc/api/track/import
|
9
|
+
# API doc reference: /doc/api/video/import
|
10
10
|
#
|
11
11
|
# @example
|
12
12
|
# track = Helix::Track.import(src: "www.google.com/track.mp4",
|
@@ -62,9 +62,9 @@ module Helix
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def rest_post(api_call, attrs)
|
65
|
-
RestClient.log
|
66
|
-
content_type
|
67
|
-
content_type_hash
|
65
|
+
RestClient.log = 'helix.log' if attrs.delete(:log)
|
66
|
+
content_type = url_opts_for[api_call][:content_type]
|
67
|
+
content_type_hash = { content_type: "text/#{content_type}" }
|
68
68
|
RestClient.post(get_url_for(api_call, attrs),
|
69
69
|
get_xml(attrs),
|
70
70
|
get_params(attrs).merge(content_type_hash))
|
data/lib/helix/library.rb
CHANGED
data/lib/helix/media.rb
CHANGED
@@ -1,70 +1,11 @@
|
|
1
1
|
require 'helix/base'
|
2
2
|
|
3
3
|
module Helix
|
4
|
-
class Media < Base
|
5
|
-
# Creates a new record via API and then returns an instance of that record.
|
6
|
-
#
|
7
|
-
# Example is using Video class since Video inherits from Base. This won't
|
8
|
-
# normally be called as Helix::Base.create
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
# Helix::Album.create({title: "My new album"})
|
12
|
-
#
|
13
|
-
# @param [Hash] attributes a hash containing the attributes used in the create
|
14
|
-
# @return [Base] An instance of Helix::Base
|
15
|
-
def self.create(attributes={})
|
16
|
-
url = config.build_url(resource_label: plural_resource_label,
|
17
|
-
content_type: :xml)
|
18
|
-
response = RestClient.post(url, attributes.merge(signature: config.signature(:update)))
|
19
|
-
attrs = Hash.from_xml(response)
|
20
|
-
self.new(attributes: attrs[resource_label_sym.to_s], config: config)
|
21
|
-
end
|
22
4
|
|
23
|
-
|
24
|
-
# guid lookup.
|
25
|
-
#
|
26
|
-
# @example
|
27
|
-
# video_guid = "8e0701c142ab1"
|
28
|
-
# video = Helix::Video.find(video_guid)
|
29
|
-
#
|
30
|
-
# @param [String] guid an id in guid form.
|
31
|
-
# @return [Base] An instance of Helix::Base
|
32
|
-
def self.find(guid)
|
33
|
-
raise ArgumentError.new("find requires a non-nil guid argument - received a nil argument.") if guid.nil?
|
34
|
-
item = self.new(attributes: { guid_name => guid }, config: config)
|
35
|
-
item.load
|
36
|
-
end
|
5
|
+
class Media < Base
|
37
6
|
|
38
|
-
|
39
|
-
#
|
40
|
-
# @example
|
41
|
-
# video = Helix::Video.create({title: "Some Title"})
|
42
|
-
# video.destroy
|
43
|
-
#
|
44
|
-
# @return [String] The response from the HTTP DELETE call.
|
45
|
-
def destroy
|
46
|
-
url = config.build_url(content_type: :xml, guid: guid, resource_label: plural_resource_label)
|
47
|
-
RestClient.delete(url, params: {signature: config.signature(:update)})
|
48
|
-
end
|
7
|
+
include RESTful, Uploadable
|
49
8
|
|
50
|
-
# Updates instance and record with attributes passed in.
|
51
|
-
#
|
52
|
-
# @example
|
53
|
-
# video = Helix::Video.find(video_guid)
|
54
|
-
# video.update({title: "My new title"})
|
55
|
-
#
|
56
|
-
# @param [Hash] opts a hash of attributes to update the instance with.
|
57
|
-
# @return [Base] Returns an instance of the class after update.
|
58
|
-
def update(original_opts={})
|
59
|
-
opts = original_opts.clone
|
60
|
-
RestClient.log = 'helix.log' if opts.delete(:log)
|
61
|
-
memo_cfg = config
|
62
|
-
url = memo_cfg.build_url(content_type: :xml,
|
63
|
-
guid: guid,
|
64
|
-
resource_label: plural_resource_label)
|
65
|
-
params = {signature: memo_cfg.signature(:update)}.merge(resource_label_sym => opts)
|
66
|
-
RestClient.put(url, params)
|
67
|
-
self
|
68
|
-
end
|
69
9
|
end
|
10
|
+
|
70
11
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Helix
|
2
|
+
|
3
|
+
# Mixed-in to ORM classes to provide basic RESTful CRUD operations.
|
4
|
+
|
5
|
+
module RESTful
|
6
|
+
|
7
|
+
# Deletes the record of the Helix::Base instance.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# video = Helix::Video.create({title: "Some Title"})
|
11
|
+
# video.destroy
|
12
|
+
#
|
13
|
+
# @return [String] The response from the HTTP DELETE call.
|
14
|
+
def destroy
|
15
|
+
url = config.build_url(build_url_opts)
|
16
|
+
RestClient.delete(url, params: {signature: config.signature(:update)})
|
17
|
+
end
|
18
|
+
|
19
|
+
# Updates instance and record with attributes passed in.
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# video = Helix::Video.find(video_guid)
|
23
|
+
# video.update({title: "My new title"})
|
24
|
+
#
|
25
|
+
# @param [Hash] opts a hash of attributes to update the instance with.
|
26
|
+
# @return [Base] Returns an instance of the class after update.
|
27
|
+
def update(original_opts={})
|
28
|
+
opts = original_opts.clone
|
29
|
+
RestClient.log = 'helix.log' if opts.delete(:log)
|
30
|
+
memo_cfg = config
|
31
|
+
url = memo_cfg.build_url(build_url_opts)
|
32
|
+
params = {signature: memo_cfg.signature(:update)}.merge(resource_label_sym => opts)
|
33
|
+
RestClient.put(url, params)
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def build_url_opts
|
40
|
+
self.class.build_url_opts.merge({guid: guid, resource_label: plural_resource_label})
|
41
|
+
end
|
42
|
+
|
43
|
+
module ClassMethods
|
44
|
+
|
45
|
+
# Creates a new record via API and then returns an instance of that record.
|
46
|
+
#
|
47
|
+
# Example is using Video class since Video inherits from Base. This won't
|
48
|
+
# normally be called as Helix::Base.create
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# Helix::Album.create({title: "My new album"})
|
52
|
+
#
|
53
|
+
# @param [Hash] attributes a hash containing the attributes used in the create
|
54
|
+
# @return [Base] An instance of Helix::Base
|
55
|
+
def create(attributes={})
|
56
|
+
raise Helix::NoConfigurationLoaded.new if config.nil?
|
57
|
+
url = config.build_url(build_url_opts)
|
58
|
+
response = RestClient.post(url, attributes.merge(signature: config.signature(:update)))
|
59
|
+
attrs = Hash.from_xml(response)
|
60
|
+
self.new(attributes: attrs[resource_label_sym.to_s], config: config)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Finds and returns a record in instance form for a class, through
|
64
|
+
# guid lookup.
|
65
|
+
#
|
66
|
+
# @example
|
67
|
+
# video_guid = "8e0701c142ab1"
|
68
|
+
# video = Helix::Video.find(video_guid)
|
69
|
+
#
|
70
|
+
# @param [String] guid an id in guid form.
|
71
|
+
# @return [Base] An instance of Helix::Base
|
72
|
+
def find(guid)
|
73
|
+
raise ArgumentError.new("find requires a non-nil guid argument - received a nil argument.") if guid.nil?
|
74
|
+
raise Helix::NoConfigurationLoaded.new if config.nil?
|
75
|
+
item = self.new(attributes: { guid_name => guid }, config: config)
|
76
|
+
item.load
|
77
|
+
end
|
78
|
+
|
79
|
+
def build_url_opts
|
80
|
+
{content_type: :xml, resource_label: plural_resource_label}
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.included(klass); klass.extend(ClassMethods); end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|