7digital 0.0.2 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (220) hide show
  1. data/README.rdoc +132 -5
  2. data/lib/sevendigital.rb +1 -2
  3. data/lib/sevendigital/api_operator.rb +103 -12
  4. data/lib/sevendigital/api_operator_cached.rb +14 -8
  5. data/lib/sevendigital/api_request.rb +50 -9
  6. data/lib/sevendigital/client.rb +51 -89
  7. data/lib/sevendigital/client_configuration.rb +86 -0
  8. data/lib/sevendigital/client_digestors.rb +79 -0
  9. data/lib/sevendigital/client_managers.rb +34 -0
  10. data/lib/sevendigital/digestion_tract/api_response_digestor.rb +8 -3
  11. data/lib/sevendigital/digestion_tract/artist_digestor.rb +1 -1
  12. data/lib/sevendigital/digestion_tract/basket_digestor.rb +18 -0
  13. data/lib/sevendigital/digestion_tract/basket_item_digestor.rb +25 -0
  14. data/lib/sevendigital/digestion_tract/chart_item_digestor.rb +1 -1
  15. data/lib/sevendigital/digestion_tract/digestor.rb +7 -3
  16. data/lib/sevendigital/digestion_tract/download_url_digestor.rb +19 -0
  17. data/lib/sevendigital/digestion_tract/format_digestor.rb +1 -1
  18. data/lib/sevendigital/digestion_tract/label_digestor.rb +1 -1
  19. data/lib/sevendigital/digestion_tract/locker_digestor.rb +17 -0
  20. data/lib/sevendigital/digestion_tract/locker_release_digestor.rb +19 -0
  21. data/lib/sevendigital/digestion_tract/locker_track_digestor.rb +21 -0
  22. data/lib/sevendigital/digestion_tract/oauth_access_token_digestor.rb +14 -0
  23. data/lib/sevendigital/digestion_tract/oauth_request_token_digestor.rb +14 -0
  24. data/lib/sevendigital/digestion_tract/pager_digestor.rb +1 -1
  25. data/lib/sevendigital/digestion_tract/price_digestor.rb +3 -3
  26. data/lib/sevendigital/digestion_tract/release_digestor.rb +1 -1
  27. data/lib/sevendigital/digestion_tract/tag_digestor.rb +22 -0
  28. data/lib/sevendigital/digestion_tract/track_digestor.rb +1 -1
  29. data/lib/sevendigital/management/artist_manager.rb +71 -34
  30. data/lib/sevendigital/management/basket_manager.rb +29 -0
  31. data/lib/sevendigital/management/manager.rb +1 -1
  32. data/lib/sevendigital/management/oauth_manager.rb +23 -0
  33. data/lib/sevendigital/management/release_manager.rb +7 -14
  34. data/lib/sevendigital/management/tag_manager.rb +11 -0
  35. data/lib/sevendigital/management/track_manager.rb +9 -9
  36. data/lib/sevendigital/management/user_manager.rb +51 -0
  37. data/lib/sevendigital/model/api_response.rb +19 -3
  38. data/lib/sevendigital/model/artist.rb +27 -9
  39. data/lib/sevendigital/model/basket.rb +16 -0
  40. data/lib/sevendigital/model/basket_item.rb +15 -0
  41. data/lib/sevendigital/model/download_url.rb +7 -0
  42. data/lib/sevendigital/model/format.rb +0 -2
  43. data/lib/sevendigital/model/label.rb +1 -3
  44. data/lib/sevendigital/model/locker.rb +5 -0
  45. data/lib/sevendigital/model/locker_release.rb +9 -0
  46. data/lib/sevendigital/model/locker_track.rb +9 -0
  47. data/lib/sevendigital/model/price.rb +0 -2
  48. data/lib/sevendigital/model/release.rb +22 -8
  49. data/lib/sevendigital/model/sevendigital_error.rb +9 -1
  50. data/lib/sevendigital/model/sevendigital_object.rb +16 -11
  51. data/lib/sevendigital/model/tag.rb +7 -0
  52. data/lib/sevendigital/model/track.rb +4 -4
  53. data/lib/sevendigital/model/user.rb +34 -0
  54. data/lib/sevendigital/pager.rb +8 -2
  55. data/lib/sevendigital/proxy_police.rb +5 -1
  56. data/lib/sevendigital/version.rb +5 -0
  57. data/spec/api_operator_cached_spec.rb +62 -7
  58. data/spec/api_operator_spec.rb +245 -21
  59. data/spec/api_request_spec.rb +20 -15
  60. data/spec/client_configuration_spec.rb +75 -0
  61. data/spec/client_spec.rb +126 -48
  62. data/spec/coverage/assets/0.3.9/app.js +66 -0
  63. data/spec/coverage/assets/0.3.9/fancybox/blank.gif +0 -0
  64. data/spec/coverage/assets/0.3.9/fancybox/fancy_close.png +0 -0
  65. data/spec/coverage/assets/0.3.9/fancybox/fancy_loading.png +0 -0
  66. data/spec/coverage/assets/0.3.9/fancybox/fancy_nav_left.png +0 -0
  67. data/spec/coverage/assets/0.3.9/fancybox/fancy_nav_right.png +0 -0
  68. data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_e.png +0 -0
  69. data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_n.png +0 -0
  70. data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_ne.png +0 -0
  71. data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_nw.png +0 -0
  72. data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_s.png +0 -0
  73. data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_se.png +0 -0
  74. data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_sw.png +0 -0
  75. data/spec/coverage/assets/0.3.9/fancybox/fancy_shadow_w.png +0 -0
  76. data/spec/coverage/assets/0.3.9/fancybox/fancy_title_left.png +0 -0
  77. data/spec/coverage/assets/0.3.9/fancybox/fancy_title_main.png +0 -0
  78. data/spec/coverage/assets/0.3.9/fancybox/fancy_title_over.png +0 -0
  79. data/spec/coverage/assets/0.3.9/fancybox/fancy_title_right.png +0 -0
  80. data/spec/coverage/assets/0.3.9/fancybox/fancybox-x.png +0 -0
  81. data/spec/coverage/assets/0.3.9/fancybox/fancybox-y.png +0 -0
  82. data/spec/coverage/assets/0.3.9/fancybox/fancybox.png +0 -0
  83. data/spec/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.css +363 -0
  84. data/spec/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.pack.js +44 -0
  85. data/spec/coverage/assets/0.3.9/favicon.png +0 -0
  86. data/spec/coverage/assets/0.3.9/jquery-1.4.2.min.js +155 -0
  87. data/spec/coverage/assets/0.3.9/jquery.dataTables.min.js +152 -0
  88. data/spec/coverage/assets/0.3.9/jquery.timeago.js +141 -0
  89. data/spec/coverage/assets/0.3.9/jquery.url.js +174 -0
  90. data/spec/coverage/assets/0.3.9/loading.gif +0 -0
  91. data/spec/coverage/assets/0.3.9/magnify.png +0 -0
  92. data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  93. data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  94. data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  95. data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  96. data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  97. data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  98. data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  99. data/spec/coverage/assets/0.3.9/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  100. data/spec/coverage/assets/0.3.9/smoothness/images/ui-icons_222222_256x240.png +0 -0
  101. data/spec/coverage/assets/0.3.9/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  102. data/spec/coverage/assets/0.3.9/smoothness/images/ui-icons_454545_256x240.png +0 -0
  103. data/spec/coverage/assets/0.3.9/smoothness/images/ui-icons_888888_256x240.png +0 -0
  104. data/spec/coverage/assets/0.3.9/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  105. data/spec/coverage/assets/0.3.9/smoothness/jquery-ui-1.8.4.custom.css +295 -0
  106. data/spec/coverage/assets/0.3.9/stylesheet.css +341 -0
  107. data/spec/coverage/index.html +43412 -0
  108. data/spec/coverage/resultset.yml +3251 -0
  109. data/spec/data/configuration_override.yml +2 -1
  110. data/spec/digestion_tract/api_response_digestor_spec.rb +15 -1
  111. data/spec/digestion_tract/artist_digestor_spec.rb +3 -3
  112. data/spec/digestion_tract/basket_digestor_spec.rb +32 -0
  113. data/spec/digestion_tract/basket_item_digestor_spec.rb +58 -0
  114. data/spec/digestion_tract/chart_digestor_spec.rb +2 -2
  115. data/spec/digestion_tract/download_url_digestor_spec.rb +41 -0
  116. data/spec/digestion_tract/format_digestor_spec.rb +2 -2
  117. data/spec/digestion_tract/label_digestor_spec.rb +2 -2
  118. data/spec/digestion_tract/locker_digestor_spec.rb +31 -0
  119. data/spec/digestion_tract/locker_release_digestor_spec.rb +71 -0
  120. data/spec/digestion_tract/locker_track_digestor_spec.rb +56 -0
  121. data/spec/digestion_tract/oauth_access_token_digestor_spec.rb +35 -0
  122. data/spec/digestion_tract/oauth_request_token_digestor_spec.rb +35 -0
  123. data/spec/digestion_tract/pager_digestor_spec.rb +2 -2
  124. data/spec/digestion_tract/price_digestor_spec.rb +21 -5
  125. data/spec/digestion_tract/release_digestor_spec.rb +2 -2
  126. data/spec/digestion_tract/tag_digestor_spec.rb +46 -0
  127. data/spec/digestion_tract/track_digestor_spec.rb +1 -1
  128. data/spec/management/artist_manager_spec.rb +46 -41
  129. data/spec/management/basket_manager_spec.rb +78 -0
  130. data/spec/management/oauth_manager_spec.rb +73 -0
  131. data/spec/management/release_manager_spec.rb +33 -74
  132. data/spec/management/tag_manager_spec.rb +34 -0
  133. data/spec/management/track_manager_spec.rb +42 -25
  134. data/spec/management/user_manager_spec.rb +163 -0
  135. data/spec/model/api_response_spec.rb +69 -2
  136. data/spec/model/artist_spec.rb +1 -26
  137. data/spec/model/basket_spec.rb +63 -0
  138. data/spec/model/coverage/assets/0.3.9/app.js +66 -0
  139. data/spec/model/coverage/assets/0.3.9/fancybox/blank.gif +0 -0
  140. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_close.png +0 -0
  141. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_loading.png +0 -0
  142. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_nav_left.png +0 -0
  143. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_nav_right.png +0 -0
  144. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_e.png +0 -0
  145. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_n.png +0 -0
  146. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_ne.png +0 -0
  147. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_nw.png +0 -0
  148. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_s.png +0 -0
  149. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_se.png +0 -0
  150. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_sw.png +0 -0
  151. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_shadow_w.png +0 -0
  152. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_title_left.png +0 -0
  153. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_title_main.png +0 -0
  154. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_title_over.png +0 -0
  155. data/spec/model/coverage/assets/0.3.9/fancybox/fancy_title_right.png +0 -0
  156. data/spec/model/coverage/assets/0.3.9/fancybox/fancybox-x.png +0 -0
  157. data/spec/model/coverage/assets/0.3.9/fancybox/fancybox-y.png +0 -0
  158. data/spec/model/coverage/assets/0.3.9/fancybox/fancybox.png +0 -0
  159. data/spec/model/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.css +363 -0
  160. data/spec/model/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.pack.js +44 -0
  161. data/spec/model/coverage/assets/0.3.9/favicon.png +0 -0
  162. data/spec/model/coverage/assets/0.3.9/jquery-1.4.2.min.js +155 -0
  163. data/spec/model/coverage/assets/0.3.9/jquery.dataTables.min.js +152 -0
  164. data/spec/model/coverage/assets/0.3.9/jquery.timeago.js +141 -0
  165. data/spec/model/coverage/assets/0.3.9/jquery.url.js +174 -0
  166. data/spec/model/coverage/assets/0.3.9/loading.gif +0 -0
  167. data/spec/model/coverage/assets/0.3.9/magnify.png +0 -0
  168. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  169. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  170. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  171. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  172. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  173. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  174. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  175. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  176. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-icons_222222_256x240.png +0 -0
  177. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  178. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-icons_454545_256x240.png +0 -0
  179. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-icons_888888_256x240.png +0 -0
  180. data/spec/model/coverage/assets/0.3.9/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  181. data/spec/model/coverage/assets/0.3.9/smoothness/jquery-ui-1.8.4.custom.css +295 -0
  182. data/spec/model/coverage/assets/0.3.9/stylesheet.css +341 -0
  183. data/spec/model/coverage/index.html +8637 -0
  184. data/spec/model/coverage/resultset.yml +642 -0
  185. data/spec/model/release_spec.rb +15 -14
  186. data/spec/model/sevendigital_object_spec.rb +74 -0
  187. data/spec/model/track_spec.rb +8 -4
  188. data/spec/model/user_spec.rb +98 -0
  189. data/spec/pager_spec.rb +2 -2
  190. data/spec/proxy_police_spec.rb +1 -1
  191. data/spec/spec_helper.rb +11 -3
  192. data/spec/test-xml/methods/artist/browse.xml +22 -0
  193. data/spec/test-xml/methods/artist/chart.xml +31 -0
  194. data/spec/test-xml/methods/basket/additem.xml +24 -0
  195. data/spec/test-xml/methods/basket/create.xml +11 -0
  196. data/spec/test-xml/methods/basket/index.xml +24 -0
  197. data/spec/test-xml/methods/basket/removeitem.xml +11 -0
  198. data/spec/test-xml/methods/oauth/accesstoken.xml +6 -0
  199. data/spec/test-xml/methods/oauth/requesttoken.xml +6 -0
  200. data/spec/test-xml/methods/tag/index.xml +17 -0
  201. data/spec/test-xml/methods/user/locker.xml +50 -0
  202. data/spec/test-xml/methods/user/purchase/item.xml +49 -0
  203. data/spec/test-xml/objects/basket.xml +22 -0
  204. data/spec/test-xml/objects/basket_item.xml +12 -0
  205. data/spec/test-xml/objects/basket_item_list.xml +26 -0
  206. data/spec/test-xml/objects/basket_item_list_empty.xml +2 -0
  207. data/spec/test-xml/objects/download_url.xml +8 -0
  208. data/spec/test-xml/objects/locker.xml +48 -0
  209. data/spec/test-xml/objects/locker_release.xml +41 -0
  210. data/spec/test-xml/objects/locker_release_list.xml +87 -0
  211. data/spec/test-xml/objects/locker_release_list_empty.xml +5 -0
  212. data/spec/test-xml/objects/locker_release_one_item_list.xml +43 -0
  213. data/spec/test-xml/objects/locker_track.xml +25 -0
  214. data/spec/test-xml/objects/locker_track_list.xml +26 -0
  215. data/spec/test-xml/objects/locker_track_list_empty.xml +2 -0
  216. data/spec/test-xml/objects/oauth_access_token.xml +4 -0
  217. data/spec/test-xml/objects/oauth_request_token.xml +4 -0
  218. data/spec/test-xml/objects/tag.xml +5 -0
  219. metadata +395 -13
  220. data/lib/sevendigital/peachy_patch.rb +0 -19
data/README.rdoc CHANGED
@@ -1,9 +1,136 @@
1
- Ruby wrapper for 7digital API
1
+ =Ruby wrapper for 7digital API
2
+
3
+ This is a ruby wrapper for the 7digital API.
4
+
5
+ ==About 7digital
6
+
7
+ 7digital.com is an online music store operating in over 16 countries and offering more than 11 million high quality DRM free MP3s (320kbps) from all major labels and wide range of idependent labels and distributors. 7digital API will give you access to the full catalogue including high quality album art, 30s preview clips for all tracks, commissions on sales, integrated purchasing and full length streaming. More details at http://developer.7digital.net
8
+
9
+ ==Installation
10
+
11
+ gem install 7digital
12
+
13
+ ==Quick start example
14
+
2
15
 
3
- Example usage:
4
16
  require "sevendigital"
17
+ api_client = Sevendigital::Client.new(:oauth_consumer_key => "YOUR_KEY_HERE", :country => "GB")
18
+ an_artist = api_client.artist.search("radiohead").first
19
+ a_release = an_artist.releases(:page_size=>100).sort_by{|release| release.year}.last
20
+ puts "the latest #{an_artist.name} release is #{a_release.title} from #{a_release.year}"
21
+ puts "go and buy it at #{a_release.url} !"
22
+
23
+ ==Usage details
24
+
25
+ ===Initializing & configuring an API Client
26
+
27
+ To use the wrapper and access the 7digital API you need a configured instance of Sevendigital::Client. Create one using the standard new method:
28
+
29
+ client = Sevendigital::Client.new
30
+
31
+ This will get you an API client configured with default settings. At very least before making any API calls you will need to update the configuration with your own API key. You can adjust the client's configuration in several ways:
32
+
33
+ 1. In Rails app you can put _sevendigital.yml_ inside your app's config dir and this will be automatically picked up (for a template please see the examples directory)
34
+
35
+ 2. You can provide a custom location of configuration file when instantiating a client
36
+
37
+ client = Sevendigital::Client.new("dir/subdir/my_7d_configuration.yml")
38
+ 3. You can supply a hash of configuration settings when instantiating a client
39
+
40
+ client = Sevendigital::Client.new(:oauth_consumer_key => "YOUR_KEY_HERE", :country => "GB")
41
+ 4. You can update the configuration in block whilst instantiating a client
42
+
43
+ client = Sevendigital::Client.new { |config|
44
+ config.oauth_consumer_key => "YOUR_KEY_HERE"
45
+ config.verbose => true
46
+ }
47
+
48
+ You can also combine all of the above (if the same setting is specified multiple times the last one will be applied)
49
+ An extreme example:
50
+
51
+ client = Sevendigital::Client.new("7digital_default_settings.yml", :oauth_consumer_key => "MY_OTHER_KEY") { |conf|
52
+ conf.country = "SE"
53
+ conf.oauth_consumer_key = "ACTUALLY_USE_THIS_KEY"
54
+ }
55
+
56
+ ===Using the client
57
+
58
+ List of all available API methods and their return types
59
+
60
+ ----
61
+
62
+ Provided by Sevendigital::ArtistManager :
63
+
64
+ client.artist.*get_details*(artist_id, options={}) => Sevendigital::Artist
65
+
66
+ client.artist.*get_releases*(artist_id, options={}) => [ Sevendigital::Release ]
67
+
68
+ client.artist.*get_similar*(artist_id, options={}) => [ Sevendigital::Artist ]
69
+
70
+ client.artist.*get_top_by_tag*(tags, options={}) => [ Sevendigital::Artist ]
71
+
72
+ client.artist.*get_top_tracks*(artist_id, options={}) => [ Sevendigital::Track ]
73
+
74
+ client.artist.*search*(query, options={}) => [ Sevendigital::Artist ]
75
+
76
+ ----
77
+
78
+ Provided by Sevendigital::ReleaseManager :
79
+
80
+ client.release.*get_details*(release_id, options = {}) => Sevendigital::Release
81
+
82
+ client.release.*get_tracks*(release_id, options = {}) => [ Sevendigital::Track ]
83
+
84
+ client.release.*get_chart*(options={}) => [ Sevendigital::ChartItem ]
85
+
86
+ client.release.*get_by_date*(from_date = nil, to_date = nil, options = {}) => [ Sevendigital::Release ]
87
+
88
+ client.release.*get_recommendations*(release_id, options = {}) => [ Sevendigital::Release ]
89
+
90
+ client.release.*get_top_by_tag*(tags, options = {}) => [ Sevendigital::Release ]
91
+
92
+ client.release.*search*(query, options={}) => [ Sevendigital::Release ]
93
+
94
+ ----
95
+
96
+ client.track.*get_details*(id, options={}) => Sevendigital::Track
97
+
98
+ client.track.*get_details_from_release*(track_id, release_id, options={}) => Sevendigital::Track
99
+
100
+ client.track.*get_chart*(options={}) => [ Sevendigital::ChartItem ]
101
+
102
+ client.track.*build_preview_url*(id, options={}) => String
103
+
104
+ client.track.*search*(query, options={}) => [ Sevendigital::Track ]
105
+
106
+ ---
107
+
108
+ client.basket.*get*(basket_id, options={}) => Sevendigital::Basket
109
+
110
+ client.basket.*create*(options={}) => Sevendigital::Basket
111
+
112
+ client.basket.*add_item*(basket_id, release_id, track_id=nil, options={}) => Sevendigital::Basket
113
+
114
+ client.basket.*remove_item*(basket_id, item_id, options={}) => Sevendigital::Basket
115
+
116
+ ---
117
+
118
+ client.oauth.*get_request_token* => OAuth::RequestToken
119
+
120
+ client.oauth.*get_access_token*(request_token) => OAuth::AccessToken
121
+
122
+ ---
123
+
124
+ client.user.*login*(access_token) => Sevendigital::User
125
+
126
+ client.user.*authenticate*(email, password) => Sevendigital::User
127
+
128
+ client.user.*get_locker*(token, options={}) => Sevendgital::Locker
129
+
130
+ client.user.*purchase*(release_id, track_id, price, token, options={}) => Sevendgital::Locker
131
+
132
+ client.user.*get_stream_track_url*(release_id, track_id, token, options={}) => String
133
+
134
+ client.user.*get_add_card_url*(return_url, token, options={}) => String
5
135
 
6
- sevendigital_client = Sevendigital::Client.new(:oauth_consumer_key => "YOUR_KEY_HERE", :country => "GB")
7
- artist = sevendigital_client.artist.get_details(1)
8
- puts artist.name
9
136
 
data/lib/sevendigital.rb CHANGED
@@ -2,7 +2,6 @@
2
2
  module Sevendigital
3
3
 
4
4
  # :stopdoc:
5
- VERSION = '0.0.1'
6
5
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
7
6
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
8
7
  # :startdoc:
@@ -45,8 +44,8 @@ module Sevendigital
45
44
  end # module 7digital
46
45
 
47
46
  require 'peachy'
48
- require File.join( File.dirname( File.expand_path(__FILE__)), 'sevendigital', 'peachy_patch')
49
47
  Peachy.be_quiet
48
+ require File.join( File.dirname( File.expand_path(__FILE__)), 'sevendigital', 'client_configuration')
50
49
  require File.join( File.dirname( File.expand_path(__FILE__)), 'sevendigital', 'management', 'manager')
51
50
  require File.join( File.dirname( File.expand_path(__FILE__)), 'sevendigital', 'digestion_tract', 'digestor')
52
51
  require File.join( File.dirname( File.expand_path(__FILE__)), 'sevendigital', 'model', 'sevendigital_object')
@@ -1,32 +1,123 @@
1
1
  module Sevendigital
2
2
 
3
3
  require 'net/http'
4
-
5
- class ApiOperator
4
+ require 'net/https'
5
+ require 'oauth'
6
+ require 'uri'
7
+ require 'cgi'
8
+
9
+ #internal class used for translating ApiRequests into http calls
10
+ #deals with OAuth signing requests that require signature, making sure parameters are in correct format etc
11
+ class ApiOperator # :nodoc:
12
+
13
+ RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~]/
6
14
 
7
15
  def initialize(client)
8
16
  @client = client
9
17
  end
10
18
 
11
19
  def call_api(api_request)
12
- api_response = make_http_request_and_digest(create_request_uri(api_request))
13
- puts api_response if @client.very_verbose?
20
+ api_response = make_http_request_and_digest(api_request)
21
+ puts api_response.content.to_s if @client.very_verbose?
14
22
  api_response
15
23
  end
16
24
 
17
- def make_http_request_and_digest(uri)
18
- puts "ApiOperator: Calling #{uri}" if @client.verbose?
19
- http_response = Net::HTTP.get_response(uri)
25
+ def get_request_uri(api_request)
26
+ api_request.signature_scheme = :query_string if api_request.requires_signature?
27
+ http_client, http_request = create_http_request(api_request)
28
+ path = http_request.instance_variable_get("@path")
29
+ host = http_client.instance_variable_get("@address")
30
+ port = http_client.instance_variable_get("@port")
31
+ scheme = port == 443 ? "https" : "http"
32
+ return "#{scheme}://#{host}#{path}"
33
+ end
34
+
35
+ def make_http_request_and_digest(api_request)
36
+ digest_http_response(make_http_request(api_request))
37
+ end
38
+
39
+ def make_http_request(api_request)
40
+
41
+ http_client, http_request = create_http_request(api_request)
42
+
43
+ http_client.set_debug_output($stdout) if @client.very_verbose?
44
+ log_request(http_request) if @client.verbose?
45
+
46
+ http_client.request(http_request)
47
+ end
48
+
49
+ def digest_http_response(http_response)
20
50
  api_response = @client.api_response_digestor.from_http_response(http_response)
21
- raise Sevendigital::SevendigitalError, "#{api_response.error_code} - #{api_response.error_message}" if !api_response.ok?
51
+ raise Sevendigital::SevendigitalError.new(api_response.error_code, api_response.error_message), "#{api_response.error_code} - #{api_response.error_message}" if !api_response.ok?
22
52
  api_response
23
53
  end
24
54
 
55
+ def create_http_request(api_request)
56
+ http_client, http_request = create_standard_http_request(api_request)
57
+ if (api_request.requires_signature?) then
58
+ oauth_sign_request(http_client, http_request, api_request)
59
+ else
60
+ end
61
+ return http_client, http_request
62
+ end
63
+
64
+ def oauth_sign_request(http_client, http_request, api_request)
65
+ http_request.oauth!( \
66
+ http_client, \
67
+ @client.oauth_consumer, \
68
+ api_request.token, \
69
+ {:scheme => api_request.signature_scheme}
70
+ )
71
+ return http_request
72
+ end
73
+
74
+ def create_standard_http_request(api_request)
75
+ request_uri = create_request_uri(api_request)
76
+ http_client = Net::HTTP.new(request_uri.host, request_uri.port)
77
+
78
+ request_uri.query += '&oauth_consumer_key=' + @client.configuration.oauth_consumer_key unless api_request.requires_signature?
79
+
80
+ http_request = new_http_request(request_uri.request_uri, api_request.http_method)
81
+
82
+ ensure_secure_connection(http_client) if api_request.requires_secure_connection?
83
+ add_form_parameters(http_request, api_request)
84
+
85
+ return http_client, http_request
86
+ end
87
+
88
+ def ensure_secure_connection(http_client)
89
+ http_client.use_ssl = true
90
+ http_client.verify_mode = OpenSSL::SSL::VERIFY_NONE
91
+ end
92
+
25
93
  def create_request_uri(api_request)
26
- api_request.ensure_country_is_set(@client.country)
27
- params = api_request.parameters.collect{ |a,v| "&#{a}=#{v}" }.join
28
- URI.parse("http://#{@client.configuration.api_url}/#{@client.configuration.api_version}/#{api_request.api_method}"+
29
- "?oauth_consumer_key=#{@client.configuration.oauth_consumer_key}#{params}")
94
+ host, version = @client.api_host_and_version(api_request.api_service)
95
+ path = "/#{version}/#{api_request.api_method}"
96
+ query = api_request.parameters.map{ |k,v| "#{escape(k)}=#{escape(v)}" }.join("&")
97
+ if api_request.requires_secure_connection? then
98
+ URI::HTTPS.build(:host => host, :path => path, :query =>query)
99
+ else
100
+ URI::HTTP.build(:host => host, :path => path, :query =>query)
101
+ end
102
+ end
103
+
104
+ def escape(value)
105
+ URI::escape(value.to_s, RESERVED_CHARACTERS)
106
+ rescue ArgumentError
107
+ URI::escape(value.to_s.force_encoding(Encoding::UTF_8), RESERVED_CHARACTERS)
108
+ end
109
+
110
+ def new_http_request(request_uri, http_method)
111
+ request_type = Kernel.const_get("Net").const_get("HTTP").const_get(http_method.to_s.capitalize)
112
+ request_type.new(request_uri, {"user-agent" => @client.user_agent_info})
113
+ end
114
+
115
+ def add_form_parameters(http_request, api_request)
116
+ http_request.set_form_data(api_request.form_parameters)
117
+ end
118
+
119
+ def log_request(request)
120
+ puts "ApiOperator: Calling #{request.inspect}"
30
121
  end
31
122
 
32
123
  end
@@ -1,6 +1,10 @@
1
1
  module Sevendigital
2
2
 
3
- class ApiOperatorCached < ApiOperator
3
+ #Cached version of ApiOperator
4
+ #If response for an API request is already in cache and
5
+ #and it hasn't expired returns the cached response is returned instead of making an API call
6
+ #otherwise uses methods inherited from ApiOperator to make an HTTP call to the API
7
+ class ApiOperatorCached < ApiOperator # :nodoc:
4
8
 
5
9
  def initialize(client, cache)
6
10
  @cache = cache
@@ -8,16 +12,18 @@ class ApiOperatorCached < ApiOperator
8
12
  end
9
13
 
10
14
  def call_api(api_request)
11
- uri = create_request_uri(api_request)
12
- api_response = @cache.get(uri.to_s)
13
- puts "ApiOperatorCached: Got from cache #{uri}" if api_response if @client.verbose?
14
- if (!api_response) then
15
- api_response = make_http_request_and_digest(uri)
16
- @cache.set(uri.to_s, api_response)
15
+ request_cache_key = create_request_uri(api_request)
16
+ api_response = @cache.get(request_cache_key.to_s) if !api_request.requires_signature?
17
+ puts "ApiOperatorCached: Got from cache #{request_cache_key}" if @client.verbose? && api_response
18
+ puts "but the response is out of date" if @client.verbose? && api_response && api_response.out_of_date?
19
+ if (!api_response || api_response.out_of_date?) then
20
+ api_response = make_http_request_and_digest(api_request)
21
+ @cache.set(request_cache_key.to_s, api_response) if !api_request.requires_signature?
17
22
  end
18
- puts api_response if @client.very_verbose?
23
+ p api_response if @client.very_verbose?
19
24
  api_response
20
25
  end
26
+
21
27
  end
22
28
 
23
29
  end
@@ -1,24 +1,65 @@
1
1
  module Sevendigital
2
2
 
3
- class ApiRequest
3
+ #Abstraction of a HTTP API request, ApiOperator uses this ApiRequest to build a real HTTP requests
4
+ class ApiRequest # :nodoc:
4
5
 
5
- attr_reader :api_method, :parameters
6
+ attr_reader :api_method, :parameters, :signed
7
+ attr_accessor :token, :api_service, :http_method
8
+ attr_accessor :signature_scheme
9
+ attr_writer :form_parameters
6
10
 
7
- def initialize(api_method, parameters, options = {})
11
+ def initialize(api_method, parameters, options={})
8
12
  @api_method = api_method
9
- @parameters = comb_parameters(options.merge(parameters))
13
+ @parameters = parameters
14
+ @signature_scheme = :header
15
+ @http_method = :GET
16
+ comb_parameters(parameters)
17
+ @form_parameters = Hash.new
18
+ end
19
+
20
+ def form_parameters
21
+ comb_parameters(@form_parameters)
22
+ end
23
+
24
+ def requires_signature?
25
+ @signed == true
26
+ end
27
+
28
+ def require_signature
29
+ @signed = true
30
+ end
31
+
32
+ def requires_secure_connection?
33
+ @secure == true
34
+ end
35
+
36
+ def require_secure_connection
37
+ @secure = true
10
38
  end
11
39
 
12
40
  def comb_parameters(parameters)
13
- page_size = parameters[:page_size] || parameters[:per_page]
14
- parameters[:pageSize] ||= page_size if page_size
15
- return parameters
41
+ comb_parameter(parameters, :pageSize, [:page_size, :per_page])
42
+ comb_parameter(parameters, :shopId, :shop_id)
43
+ comb_parameter(parameters, :imageSize, :image_size)
44
+ remove_empty_parameters(parameters)
45
+ parameters
16
46
  end
17
47
 
18
- def ensure_country_is_set(country)
19
- @parameters[:country] ||= country
48
+ def comb_parameter(parameters, correct_name, alternative_names)
49
+ param_value = nil
50
+ alternative_names = [alternative_names] unless alternative_names.is_a?(Array)
51
+ alternative_names.each do |alternative_name|
52
+ param_value ||= parameters[alternative_name]
53
+ parameters.delete(alternative_name)
54
+ end
55
+ parameters[correct_name] ||= param_value if param_value
20
56
  end
21
57
 
58
+ def remove_empty_parameters(parameters)
59
+ parameters.delete_if { |key, value| value.nil? }
60
+ end
61
+
62
+
22
63
  end
23
64
 
24
65
  end
@@ -1,108 +1,82 @@
1
- require 'ostruct'
2
- require 'yaml'
3
-
4
-
5
1
  module Sevendigital
6
2
 
7
- DEFAULT_CONFIGURATION = {
8
- :api_url => "api.7digital.com",
9
- :api_version => "1.2"
10
- }
11
-
12
3
  class Client
13
4
 
14
- def load_configuration_from_yml(file_name, environment=nil)
15
- plain_settings = YAML.load_file(file_name)
16
- if (plain_settings["common"] || (environment && plain_settings[environment])) then
17
- environment_settings = plain_settings["common"] || {}
18
- environment_settings.update(plain_settings[environment]) if environment
19
- environment_settings
20
- else
21
- plain_settings
22
- end
23
- end
24
-
25
- def load_configurations(configuration)
26
-
27
- default_settings = Sevendigital::DEFAULT_CONFIGURATION
5
+ COMMON_REQUEST_PARAMETERS = [:shop_id, :country, :page, :page_size, :image_size]
28
6
 
29
- if (configuration.kind_of? String) then
30
- yml_configuration_file = configuration
31
- else
32
- yml_configuration_file ="#{RAILS_ROOT}/config/sevendigital.yml" if defined?(RAILS_ROOT)
33
- explicit_settings = configuration if configuration.kind_of? Hash
34
- explicit_settings = configuration.marshal_dump if configuration.kind_of? OpenStruct
7
+ def initialize(*args)
8
+ @configuration = Sevendigital::ClientConfiguration.new(*args)
9
+ yield @configuration if block_given?
10
+ @api_operator = hire_api_operator
35
11
  end
36
12
 
37
- environment = defined?(RAILS_ENV) ? RAILS_ENV : nil
38
- yml_settings = load_configuration_from_yml(yml_configuration_file, environment) if yml_configuration_file
39
-
40
- settings = default_settings
41
- settings.update(yml_settings) if yml_settings
42
- settings.update(explicit_settings) if explicit_settings
43
-
44
- return OpenStruct.new(settings)
45
- end
46
-
47
- #Code here
48
-
49
- def initialize(configuration=nil, api_operator=nil)
50
- @configuration = load_configurations(configuration)
51
- @api_operator = api_operator || hire_api_operator
13
+ def default_parameters
14
+ params = {}
15
+ COMMON_REQUEST_PARAMETERS.each do |param|
16
+ value = @configuration.send(param)
17
+ params[param] = value if value
18
+ end
19
+ params
52
20
  end
53
21
 
54
22
  def hire_api_operator
55
23
  @configuration.cache ? ApiOperatorCached.new(self, @configuration.cache) : ApiOperator.new(self)
56
24
  end
57
25
 
58
- def artist
59
- @artist_manager ||= ArtistManager.new(self)
26
+ def user_agent_info
27
+ app_info = @configuration.app_name ? "/#{@configuration.app_name}" : nil
28
+ app_info += " #{@configuration.app_version}" if app_info && @configuration.app_version
29
+ "#{Sevendigital::NAME} Gem #{Sevendigital::VERSION}#{app_info}"
60
30
  end
61
31
 
62
- def artist_digestor
63
- @artist_digestor ||= ArtistDigestor.new(self)
64
- end
65
-
66
- def release
67
- @release_manager ||= ReleaseManager.new(self)
32
+ def create_api_request(api_method, parameters, options = {})
33
+ parameters = options.merge(parameters)
34
+ parameters = add_default_parameters(parameters)
35
+ ApiRequest.new(api_method, parameters)
68
36
  end
69
37
 
70
- def release_digestor
71
- @release_digestor ||= ReleaseDigestor.new(self)
38
+ def make_api_request(api_method, parameters, options = {})
39
+ api_request = create_api_request(api_method, parameters, options)
40
+ operator.call_api(api_request)
72
41
  end
73
42
 
74
- def label_digestor
75
- @label_digestor ||= LabelDigestor.new(self)
76
- end
43
+ def make_signed_api_request(api_method, parameters, options = {}, token = nil)
44
+ api_request = create_api_request(api_method, parameters, options)
45
+ api_request.require_signature
46
+ api_request.require_secure_connection
47
+ api_request.token = token
77
48
 
78
- def format_digestor
79
- @format_digestor ||= FormatDigestor.new(self)
80
- end
81
-
82
- def price_digestor
83
- @price_digestor ||= PriceDigestor.new(self)
49
+ operator.call_api(api_request)
84
50
  end
85
51
 
86
- def pager_digestor
87
- @pager_digestor ||= PagerDigestor.new(self)
52
+ def add_default_parameters(parameters)
53
+ params = parameters
54
+ default_parameters.each do |name, value|
55
+ params[name] ||= value
56
+ end
57
+ params
88
58
  end
89
59
 
90
- def track
91
- @track_manager ||= TrackManager.new(self)
60
+ def api_host_and_version(api_service=nil)
61
+ service = api_service && !api_service.to_s.empty? ? "#{api_service}_" : ""
62
+ return configuration.send("#{service}api_url".to_sym), configuration.send("#{service}api_version".to_sym)
92
63
  end
93
64
 
94
- def track_digestor
95
- @track_digestor ||= TrackDigestor.new(self)
96
- end
65
+ def oauth_consumer
66
+ host, version = api_host_and_version(:account)
97
67
 
98
- def api_response_digestor
99
- @api_response_digestor ||= ApiResponseDigestor.new(self)
100
- end
101
-
102
- def chart_item_digestor
103
- @chart_item_digestor ||= ChartItemDigestor.new(self)
68
+ consumer_options = {
69
+ :authorize_path => "https://#{host}/#{version}/oauth/authorise",
70
+ :http_method => :get
71
+ }
72
+
73
+ @oauth_consumer ||= OAuth::Consumer.new( \
74
+ @configuration.oauth_consumer_key, \
75
+ @configuration.oauth_consumer_secret, \
76
+ consumer_options \
77
+ )
104
78
  end
105
-
79
+
106
80
  def configuration
107
81
  return @configuration
108
82
  end
@@ -111,14 +85,6 @@ module Sevendigital
111
85
  @api_operator
112
86
  end
113
87
 
114
- def country
115
- @country || @configuration.country
116
- end
117
-
118
- def country=(country_code)
119
- @country = country_code
120
- end
121
-
122
88
  def verbose?
123
89
  !(@verbose || @configuration.verbose).nil?
124
90
  end
@@ -127,10 +93,6 @@ module Sevendigital
127
93
  verbose? && (@verbose || @configuration.verbose).to_s == "very_verbose"
128
94
  end
129
95
 
130
- def verbose=(verbosity)
131
- @verbose = verbosity
132
- end
133
-
134
96
  end
135
97
 
136
98
  end