opera-mobile-store-sdk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []