helix 0.0.2.7.pre → 0.0.2.8.pre

Sign up to get free protection for your applications and to get access to all the features.
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
- ####Current models
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.
@@ -1,3 +1,5 @@
1
+ require 'helix/restful'
2
+ require 'helix/uploadable'
1
3
  require 'helix/durationed_media'
2
4
  require 'helix/video'
3
5
  require 'helix/track'
@@ -24,7 +24,7 @@ module Helix
24
24
 
25
25
  def self.known_attributes
26
26
  [:title, :description]
27
- end
27
+ end
28
28
 
29
29
  end
30
30
 
@@ -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: self.plural_resource_label)
56
+ resource_label: label)
54
57
  # We allow opts[:sig_type] for internal negative testing only.
55
- raw_response = config.get_response(url, {sig_type: :view}.merge(opts))
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
@@ -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] opts a hash of options for building URL additions
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 = RestClient.get(url, params: params)
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
- # Doc reference: /doc/api/track/import
9
- # Doc reference: /doc/api/video/import
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 = '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}" }
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))
@@ -2,7 +2,9 @@ require 'helix/media'
2
2
 
3
3
  module Helix
4
4
 
5
- class Library < Media
5
+ class Library < Base
6
+
7
+ include RESTful
6
8
 
7
9
  # The class name, to be used by supporting classes. Such as Config which uses
8
10
  # this method as a way to build URLs.
@@ -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
- # Finds and returns a record in instance form for a class, through
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
- # Deletes the record of the Helix::Base instance.
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