opera-mobile-store-sdk 0.1.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 (34) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/CODE_OF_CONDUCT.md +13 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +39 -0
  9. data/Rakefile +2 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +7 -0
  12. data/lib/opera-mobile-store-sdk.rb +69 -0
  13. data/lib/opera-mobile-store-sdk/version.rb +5 -0
  14. data/lib/opera/mobile_store/author.rb +31 -0
  15. data/lib/opera/mobile_store/build.rb +88 -0
  16. data/lib/opera/mobile_store/build_file.rb +27 -0
  17. data/lib/opera/mobile_store/category.rb +31 -0
  18. data/lib/opera/mobile_store/developer.rb +70 -0
  19. data/lib/opera/mobile_store/payment_info.rb +105 -0
  20. data/lib/opera/mobile_store/product.rb +157 -0
  21. data/lib/opera/mobile_store/product_image.rb +42 -0
  22. data/lib/opera/mobile_store/product_localization.rb +35 -0
  23. data/lib/opera/mobile_store_sdk/api_accessible.rb +44 -0
  24. data/lib/opera/mobile_store_sdk/api_object_list.rb +174 -0
  25. data/lib/opera/mobile_store_sdk/config.rb +71 -0
  26. data/lib/opera/mobile_store_sdk/errors.rb +10 -0
  27. data/lib/opera/mobile_store_sdk/faraday_middleware.rb +4 -0
  28. data/lib/opera/mobile_store_sdk/faraday_middleware/authentication.rb +76 -0
  29. data/lib/opera/mobile_store_sdk/faraday_middleware/required_response_format.rb +14 -0
  30. data/lib/opera/mobile_store_sdk/faraday_middleware/response_parser.rb +45 -0
  31. data/lib/opera/mobile_store_sdk/faraday_middleware/sdk_benchmark.rb +47 -0
  32. data/lib/opera/mobile_store_sdk/identity_mapable.rb +35 -0
  33. data/opera-mobile-store-sdk.gemspec +35 -0
  34. metadata +174 -0
@@ -0,0 +1,71 @@
1
+ module Opera
2
+ module MobileStoreSDK
3
+ class Config
4
+
5
+ include ActiveSupport::Configurable
6
+
7
+ DEFAULT_API_URL = "https://publishers.apps.opera.com/administrator/mng_contpartners/export_partner_software.php".freeze
8
+
9
+ config_accessor :username do
10
+ ENV.fetch "OPERA_MOBILE_STORE_USERNAME", nil
11
+ end
12
+
13
+ config_accessor :password do
14
+ ENV.fetch "OPERA_MOBILE_STORE_PASSWORD", nil
15
+ end
16
+
17
+ # API host:
18
+ config_accessor :api_host do
19
+ api_uri = URI(ENV.fetch "OPERA_MOBILE_STORE_API_URL", DEFAULT_API_URL)
20
+ api_uri.path = ""
21
+ api_uri.to_s
22
+ end
23
+
24
+ # API path:
25
+ config_accessor :api_path do
26
+ api_uri = URI(ENV.fetch "OPERA_MOBILE_STORE_API_URL", DEFAULT_API_URL)
27
+ api_uri.path
28
+ end
29
+
30
+ # API Call Timeout:
31
+ config_accessor :api_call_timeout do
32
+ ENV.fetch("OPERA_MOBILE_STORE_API_CALL_TIMEOUT", 15).to_i
33
+ end
34
+
35
+ # API Call Open Timeout:
36
+ config_accessor :api_call_open_timeout do
37
+ ENV.fetch("OPERA_MOBILE_STORE_API_CALL_OPEN_TIMEOUT", 2).to_i
38
+ end
39
+
40
+ # Logger:
41
+ config_accessor :logger do
42
+ Logger.new($stdout)
43
+ end
44
+
45
+ # Authentication method:
46
+ config_accessor :authentication do
47
+ if ENV["OPERA_MOBILE_STORE_AUTH"].present?
48
+ ENV["OPERA_MOBILE_STORE_AUTH"].to_sym
49
+ else
50
+ :password
51
+ end
52
+ end
53
+
54
+ protected
55
+
56
+ # def auto_conf
57
+ # # Cargar configuracion dentro del folder de config en Rails:
58
+ # if defined?(Rails)
59
+ # yml_path = File.join(Rails.root, 'config', 'narai.yml')
60
+ # load_config_from_yml(yml_path, Rails.env)
61
+ #
62
+ # # Use the Rails logger:
63
+ # @logger = Rails.logger
64
+ # elsif File.exists?('./narai.yml')
65
+ # load_config_from_yml('./narai.yml')
66
+ # end
67
+ # end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,10 @@
1
+ module Opera
2
+ module MobileStoreSDK
3
+ module Errors
4
+
5
+ class APIParamsError < StandardError
6
+ end
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,4 @@
1
+ require "opera/mobile_store_sdk/faraday_middleware/authentication"
2
+ require "opera/mobile_store_sdk/faraday_middleware/required_response_format"
3
+ require "opera/mobile_store_sdk/faraday_middleware/response_parser"
4
+ require "opera/mobile_store_sdk/faraday_middleware/sdk_benchmark"
@@ -0,0 +1,76 @@
1
+ module Opera
2
+ module MobileStoreSDK
3
+ module FaradayMiddleware
4
+
5
+ # Adds the Opera Mobile Store Partner authentication parameters to the request
6
+ class Authentication < Faraday::Middleware
7
+
8
+ # Public: Initialize the middleware.
9
+ #
10
+ # app - the Faraday app to wrap
11
+ # username - The Partner's username
12
+ # password - The Partner's username
13
+ # options - (optional)
14
+ # :authentication - (:password | :signature)
15
+ def initialize(app, username, password, options = {})
16
+ super(app)
17
+
18
+ @username, @password = username, password
19
+
20
+ options = options.with_indifferent_access
21
+
22
+ @authentication = if options.key?(:authentication) && [:password, :signature].include?(options[:authentication])
23
+ options[:authentication]
24
+ else
25
+ :signature
26
+ end
27
+ end
28
+
29
+ def call(env)
30
+
31
+ auth_params = { login: @username }
32
+
33
+ case @authentication
34
+ when :password then
35
+ auth_params[:pwd] = @password
36
+ else
37
+ auth_params[:sign] = get_signature(env)
38
+ end
39
+
40
+ # Add the generated params to the url query:
41
+ auth_query = auth_params.inject([]) { |arr, kv| arr + [kv.join('=')] }.join('&')
42
+ env.url.query = [auth_query, env.url.query].join('&')
43
+
44
+ env[:url] = env.url
45
+
46
+ @app.call(env)
47
+ end
48
+
49
+ # Uses the partner password to generate the HMAC SHA1 key:
50
+ def signature_key
51
+ @_signature_key ||= [@password].pack("H*")
52
+ end
53
+
54
+ # Generates the required HMAC Hash using the request's GET params processed
55
+ # using Opera's "special algorithm":
56
+ def get_signature(env)
57
+
58
+ params_string = env.url.query.split('&').inject({}) do |hash, keyval|
59
+ key, val = keyval.split('=')
60
+ hash[key] = val
61
+ hash
62
+ end.except("login").sort.inject "" do |concatenated_string, keyval|
63
+ concatenated_string += keyval.map(&:downcase).join
64
+ end
65
+
66
+ # Return the SHA1 HMAC Hash:
67
+ OpenSSL::HMAC.hexdigest(
68
+ OpenSSL::Digest.new('sha1'), signature_key, params_string
69
+ )
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,14 @@
1
+ module Opera
2
+ module MobileStoreSDK
3
+ module FaradayMiddleware
4
+ # Adds the required response format to the request parameters, in order for
5
+ # the SDK to work:
6
+ class RequiredResponseFormat < Faraday::Middleware
7
+ def call(env)
8
+ env.url.query = ["format=xml", env.url.query].join('&')
9
+ @app.call(env)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,45 @@
1
+ require "nokogiri"
2
+ require "benchmark"
3
+
4
+ module Opera
5
+ module MobileStoreSDK
6
+ module FaradayMiddleware
7
+ # Parses the responses to models:
8
+ class ResponseParser < Faraday::Middleware
9
+
10
+ def call(request_env)
11
+ # do something with the request
12
+ # request_env[:request_headers].merge!(...)
13
+
14
+ @app.call(request_env).on_complete do |response_env|
15
+
16
+ benchmark = Benchmark.measure "api_response_parsing" do
17
+ # Parse to XML:
18
+ xml_data = Nokogiri::XML(response_env[:body])
19
+
20
+ response_env[:found_rows] = xml_data.xpath("string(/xml/*/@found_rows)").to_i
21
+ response_env[:timestamp] = xml_data.xpath("string(/xml/*/@timestamp)").to_i
22
+
23
+ real_root_name = xml_data.xpath("name(/xml/*)")
24
+
25
+ parser_class = "Opera::MobileStore::#{real_root_name.classify}".safe_constantize
26
+
27
+ # Parse each node:
28
+ collection_path = "/xml/#{real_root_name}/#{real_root_name.singularize}"
29
+
30
+ parsed_data = xml_data.xpath(collection_path).map do |item_node|
31
+ parser_class.build_from_nokogiri_node item_node
32
+ end
33
+
34
+ # replace body with parsed_data:
35
+ response_env[:body] = parsed_data
36
+ end
37
+
38
+ response_env[:opera_api_response_parsing_tms] = benchmark
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,47 @@
1
+ require "benchmark"
2
+
3
+ module Opera
4
+ module MobileStoreSDK
5
+ module FaradayMiddleware
6
+ # Parses the responses to models:
7
+ class SDKBenchmark < Faraday::Middleware
8
+
9
+ def call(request_env)
10
+
11
+ # Get the start times:
12
+ t0 = Process.times
13
+ r0 = if defined?(Benchmark::BENCHMARK_CLOCK)
14
+ Process.clock_gettime(Benchmark::BENCHMARK_CLOCK)
15
+ else
16
+ Time.now
17
+ end
18
+
19
+ @app.call(request_env).on_complete do |response_env|
20
+
21
+ response_env[:opera_api_response_datetime] = Time.parse(
22
+ response_env.response_headers["Date"]
23
+ )
24
+
25
+ # Get the finish times:
26
+ t1 = Process.times
27
+ r1 = if defined?(Benchmark::BENCHMARK_CLOCK)
28
+ Process.clock_gettime(Benchmark::BENCHMARK_CLOCK)
29
+ else
30
+ Time.now
31
+ end
32
+
33
+ response_env[:opera_api_calling_tms] = ::Benchmark::Tms.new(
34
+ t1.utime - t0.utime,
35
+ t1.stime - t0.stime,
36
+ t1.cutime - t0.cutime,
37
+ t1.cstime - t0.cstime,
38
+ r1 - r0,
39
+ "api_calling"
40
+ )
41
+ end
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,35 @@
1
+ module Opera
2
+ module MobileStoreSDK
3
+ module IdentityMapable
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+
9
+ def identity_map
10
+ @_identity_map ||= {}
11
+ end
12
+
13
+ def find(given_id, hint_options = {})
14
+ if identity_map.key?(given_id)
15
+ identity_map[given_id]
16
+ else
17
+ raise "Not Implemented"
18
+ end
19
+ end
20
+
21
+ def registered?(object_id)
22
+ identity_map.key? object_id
23
+ end
24
+
25
+ def register(given_attributes)
26
+ obj = self.new given_attributes
27
+ identity_map[obj.id] = obj
28
+ identity_map[obj.id]
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'opera-mobile-store-sdk/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "opera-mobile-store-sdk"
8
+ spec.version = Opera::MobileStoreSDK::VERSION
9
+ spec.authors = ["Roberto Quintanilla"]
10
+ spec.email = ["roberto.quintanilla@naranya.com"]
11
+
12
+ spec.summary = %q{SDK for communicating with the Opera Mobile Store Publisher API}
13
+ spec.description = %q{SDK for communicating with the Opera Mobile Store Publisher API.}
14
+ spec.homepage = "http://www.example.com"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ #if spec.respond_to?(:metadata)
23
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com' to prevent pushes to rubygems.org, or delete to allow pushes to any server."
24
+ #end
25
+
26
+ spec.add_runtime_dependency "activesupport", "~> 4.0"
27
+ spec.add_runtime_dependency "activemodel", "~> 4.0"
28
+ spec.add_runtime_dependency "nokogiri", "~> 1.6"
29
+ spec.add_runtime_dependency "faraday", "~> 0.9"
30
+ spec.add_runtime_dependency "htmlentities", "~> 4.3"
31
+
32
+ spec.add_development_dependency "bundler", "~> 1.8"
33
+ spec.add_development_dependency "rake", "~> 10.0"
34
+
35
+ end
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: opera-mobile-store-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Roberto Quintanilla
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-04-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activemodel
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: faraday
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.9'
69
+ - !ruby/object:Gem::Dependency
70
+ name: htmlentities
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.3'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.8'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.8'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '10.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '10.0'
111
+ description: SDK for communicating with the Opera Mobile Store Publisher API.
112
+ email:
113
+ - roberto.quintanilla@naranya.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rspec"
120
+ - ".travis.yml"
121
+ - CODE_OF_CONDUCT.md
122
+ - Gemfile
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
126
+ - bin/console
127
+ - bin/setup
128
+ - lib/opera-mobile-store-sdk.rb
129
+ - lib/opera-mobile-store-sdk/version.rb
130
+ - lib/opera/mobile_store/author.rb
131
+ - lib/opera/mobile_store/build.rb
132
+ - lib/opera/mobile_store/build_file.rb
133
+ - lib/opera/mobile_store/category.rb
134
+ - lib/opera/mobile_store/developer.rb
135
+ - lib/opera/mobile_store/payment_info.rb
136
+ - lib/opera/mobile_store/product.rb
137
+ - lib/opera/mobile_store/product_image.rb
138
+ - lib/opera/mobile_store/product_localization.rb
139
+ - lib/opera/mobile_store_sdk/api_accessible.rb
140
+ - lib/opera/mobile_store_sdk/api_object_list.rb
141
+ - lib/opera/mobile_store_sdk/config.rb
142
+ - lib/opera/mobile_store_sdk/errors.rb
143
+ - lib/opera/mobile_store_sdk/faraday_middleware.rb
144
+ - lib/opera/mobile_store_sdk/faraday_middleware/authentication.rb
145
+ - lib/opera/mobile_store_sdk/faraday_middleware/required_response_format.rb
146
+ - lib/opera/mobile_store_sdk/faraday_middleware/response_parser.rb
147
+ - lib/opera/mobile_store_sdk/faraday_middleware/sdk_benchmark.rb
148
+ - lib/opera/mobile_store_sdk/identity_mapable.rb
149
+ - opera-mobile-store-sdk.gemspec
150
+ homepage: http://www.example.com
151
+ licenses:
152
+ - MIT
153
+ metadata: {}
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubyforge_project:
170
+ rubygems_version: 2.4.5
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: SDK for communicating with the Opera Mobile Store Publisher API
174
+ test_files: []