sem4r 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. data/Gemfile +13 -2
  2. data/Gemfile.lock +13 -7
  3. data/README.rdoc +44 -7
  4. data/Rakefile +2 -122
  5. data/VERSION.yml +1 -1
  6. data/bin/sem +1 -0
  7. data/examples_sem4r/01_get_account.rb +1 -0
  8. data/examples_sem4r/02_get_info.rb +1 -0
  9. data/examples_sem4r/03_list_ad.rb +1 -0
  10. data/examples_sem4r/04_list_keywords.rb +1 -0
  11. data/examples_sem4r/05_request_report.rb +25 -14
  12. data/examples_sem4r/{05_request_report_2010.rb → 06_request_report_definition.rb} +2 -4
  13. data/examples_sem4r/{06_create_campaigns.rb → 07_create_campaigns.rb} +1 -0
  14. data/examples_sem4r/{07_create_campaigns_block.rb → 08_create_campaigns_block.rb} +1 -0
  15. data/examples_sem4r/{07_create_campaigns_simple.rb → 09_create_campaigns_simple.rb} +1 -0
  16. data/examples_sem4r/{08_ad_params.rb → 10_ad_params.rb} +1 -0
  17. data/examples_sem4r/{09_targeting_idea.rb → 11_targeting_idea.rb} +1 -0
  18. data/examples_sem4r/{10_get_location.rb → 12_get_location.rb} +1 -0
  19. data/examples_sem4r/{11_submit_bulk_job.rb → 13_submit_bulk_job.rb} +1 -1
  20. data/examples_sem4r/{12_list_bulk_job.rb → 14_list_bulk_job.rb} +3 -0
  21. data/examples_sem4r/30_prune_empty_adgroup.rb +1 -0
  22. data/examples_sem4r/31_empty_accounts.rb +1 -0
  23. data/examples_sem4r/example_helper.rb +2 -1
  24. data/lib/sem4r/ad_group/ad_group.rb +22 -7
  25. data/lib/sem4r/ad_group/ad_group_bids.rb +1 -1
  26. data/lib/sem4r/ad_group/ad_group_service.rb +12 -5
  27. data/lib/sem4r/ad_group_ad/ad_group_ad.rb +1 -0
  28. data/lib/sem4r/ad_group_ad/ad_group_ad_operations.rb +1 -0
  29. data/lib/sem4r/ad_group_ad/ad_group_ad_service.rb +14 -9
  30. data/lib/sem4r/ad_group_ad/ad_group_mobile_ad.rb +16 -25
  31. data/lib/sem4r/ad_group_ad/ad_group_text_ad.rb +18 -14
  32. data/lib/sem4r/ad_group_criterion/ad_group_criterion.rb +27 -19
  33. data/lib/sem4r/ad_group_criterion/ad_group_criterion_bids.rb +2 -1
  34. data/lib/sem4r/ad_group_criterion/ad_group_criterion_operations.rb +1 -0
  35. data/lib/sem4r/ad_group_criterion/ad_group_criterion_service.rb +9 -4
  36. data/lib/sem4r/ad_group_criterion/criterion.rb +1 -0
  37. data/lib/sem4r/ad_group_criterion/criterion_keyword.rb +1 -0
  38. data/lib/sem4r/ad_group_criterion/criterion_placement.rb +1 -0
  39. data/lib/sem4r/ad_param/ad_param.rb +24 -8
  40. data/lib/sem4r/ad_param/ad_param_service.rb +8 -5
  41. data/lib/sem4r/adwords.rb +232 -76
  42. data/lib/sem4r/base.rb +1 -1
  43. data/lib/sem4r/bulk_mutate_job/bulk_mutate_job.rb +41 -35
  44. data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_account_extension.rb +49 -15
  45. data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_selector.rb +29 -20
  46. data/lib/sem4r/bulk_mutate_job/bulk_mutate_job_service.rb +13 -14
  47. data/lib/sem4r/bulk_mutate_job/job_operations.rb +1 -1
  48. data/lib/sem4r/campaign/campaign.rb +1 -0
  49. data/lib/sem4r/campaign/campaign_account_extension.rb +2 -1
  50. data/lib/sem4r/campaign/campaign_service.rb +9 -5
  51. data/lib/sem4r/credentials.rb +11 -5
  52. data/lib/sem4r/geo_location/address.rb +56 -0
  53. data/lib/sem4r/geo_location/geo_location_account_extension.rb +27 -6
  54. data/lib/sem4r/geo_location/geo_location_selector.rb +57 -0
  55. data/lib/sem4r/geo_location/geo_location_service.rb +9 -16
  56. data/lib/sem4r/info/info_account_extension.rb +3 -2
  57. data/lib/sem4r/info/info_selector.rb +2 -1
  58. data/lib/sem4r/info/info_service.rb +10 -3
  59. data/lib/sem4r/operation.rb +39 -20
  60. data/lib/sem4r/report_definition/report_definition.rb +37 -19
  61. data/lib/sem4r/report_definition/report_definition_account_extension.rb +66 -16
  62. data/lib/sem4r/report_definition/report_definition_operation.rb +2 -2
  63. data/lib/sem4r/report_definition/report_definition_selector.rb +1 -1
  64. data/lib/sem4r/report_definition/report_definition_service.rb +11 -7
  65. data/lib/sem4r/report_definition/report_field.rb +3 -2
  66. data/lib/sem4r/sem4r_templates.rb +77 -0
  67. data/lib/sem4r/{services/service.rb → service.rb} +23 -23
  68. data/lib/sem4r/targeting_idea/targeting_idea.rb +4 -4
  69. data/lib/sem4r/targeting_idea/targeting_idea_account_extension.rb +1 -1
  70. data/lib/sem4r/targeting_idea/targeting_idea_selector.rb +6 -6
  71. data/lib/sem4r/targeting_idea/targeting_idea_service.rb +7 -5
  72. data/lib/sem4r/v13_account/account_account_extension.rb +7 -10
  73. data/lib/sem4r/v13_account/account_service.rb +10 -4
  74. data/lib/sem4r/v13_account/billing_address.rb +2 -2
  75. data/lib/sem4r/v13_report/report_service.rb +11 -9
  76. data/lib/sem4r.rb +46 -31
  77. data/lib/{sem4r/cli → sem4r_cli}/cli_helpers.rb +3 -2
  78. data/lib/{sem4r/cli/cli_command.rb → sem4r_cli/cli_mini_framework.rb} +77 -32
  79. data/lib/{sem4r/cli/cli_common_args.rb → sem4r_cli/cli_sem.rb} +177 -157
  80. data/lib/{sem4r/cli/commands/cli_list_ads.rb → sem4r_cli/commands/cli_ads.rb} +7 -9
  81. data/lib/sem4r_cli/commands/cli_campaign.rb +69 -0
  82. data/lib/{sem4r/cli/commands/cli_list_client.rb → sem4r_cli/commands/cli_clients.rb} +2 -2
  83. data/lib/{sem4r/cli → sem4r_cli}/commands/cli_ideas.rb +35 -27
  84. data/lib/{sem4r/cli → sem4r_cli}/commands/cli_info.rb +3 -4
  85. data/lib/{sem4r/cli/commands/cli_repdef.rb → sem4r_cli/commands/cli_job.rb} +57 -55
  86. data/lib/{sem4r/cli/commands/cli_list_keywords.rb → sem4r_cli/commands/cli_keywords.rb} +14 -13
  87. data/lib/sem4r_cli/commands/cli_profile.rb +138 -0
  88. data/lib/{sem4r/cli/commands/cli_report.rb → sem4r_cli/commands/cli_repdef.rb} +67 -20
  89. data/lib/{sem4r/cli/commands/cli_request_report.rb → sem4r_cli/commands/cli_report.rb} +82 -19
  90. data/lib/sem4r_cli.rb +5 -7
  91. data/lib/sem4r_soap/http_connector.rb +206 -0
  92. data/lib/{soap_helpers → sem4r_soap}/soap_attributes.rb +8 -3
  93. data/lib/{sem4r/services → sem4r_soap}/soap_dumper.rb +36 -20
  94. data/lib/{sem4r/services → sem4r_soap}/soap_error.rb +5 -2
  95. data/lib/sem4r_soap/soap_response.rb +75 -0
  96. data/lib/sem4r_soap/soap_service.rb +137 -0
  97. data/lib/{sem4r/cli/cli_sem.rb → sem4r_soap/soap_service_v13.rb} +27 -28
  98. data/lib/sem4r_soap/soap_service_v2010.rb +80 -0
  99. data/lib/sem4r_soap.rb +17 -0
  100. data/sem4r.gemspec +93 -58
  101. data/spec/build_fixtures.rb +49 -42
  102. data/spec/fixtures/password.example.yml +3 -0
  103. data/spec/fixtures/sem4r.example.yml +6 -0
  104. data/spec/fixtures/{services/error.xml → soap_error.xml} +0 -0
  105. data/spec/fixtures/soap_error2.xml +29 -0
  106. data/spec/helpers/dump_interceptor.rb +90 -0
  107. data/spec/helpers/fixtures_bulk_mutate_job.rb +48 -0
  108. data/spec/helpers/fixtures_geo_location.rb +45 -0
  109. data/{lib/sem4r/campaign_criterion/campaign_criterion_service.rb → spec/helpers/fixtures_info.rb} +10 -6
  110. data/spec/helpers/fixtures_report_definition.rb +65 -0
  111. data/spec/{rspec_hash.rb → helpers/rspec_hash.rb} +1 -0
  112. data/spec/{rspec_matchers.rb → helpers/rspec_matchers.rb} +46 -19
  113. data/spec/{rspec_sem4r_helper.rb → helpers/rspec_sem4r_helper.rb} +19 -16
  114. data/spec/{sem4r_stubs.rb → helpers/sem4r_stubs.rb} +5 -4
  115. data/spec/rspec_helper.rb +4 -4
  116. data/spec/sem4r/account_spec.rb +2 -3
  117. data/spec/sem4r/ad_group/ad_group_service_spec.rb +1 -1
  118. data/spec/sem4r/ad_group/ad_group_spec.rb +1 -1
  119. data/spec/sem4r/ad_group_ad/ad_group_ad_operation_spec.rb +3 -3
  120. data/spec/sem4r/adwords_spec.rb +62 -39
  121. data/{lib/sem4r/cli/commands/cli_list_campaign.rb → spec/sem4r/bulk_mutate_job/bulk_mutate_job_selector_spec.rb} +14 -11
  122. data/spec/sem4r/bulk_mutate_job/bulk_mutate_job_service_spec.rb +2 -3
  123. data/spec/sem4r/bulk_mutate_job/bulk_mutate_job_spec.rb +23 -17
  124. data/spec/sem4r/bulk_mutate_job/fixtures/get-list_job-req.xml +35 -0
  125. data/spec/sem4r/bulk_mutate_job/fixtures/get-list_job-res.xml +417 -0
  126. data/spec/sem4r/bulk_mutate_job/fixtures/mutate-add_job-req.xml +106 -0
  127. data/spec/sem4r/bulk_mutate_job/fixtures/mutate-add_job-res.xml +48 -0
  128. data/spec/sem4r/bulk_mutate_job/job_operation_spec.rb +5 -7
  129. data/spec/sem4r/campaign/campaign_service_spec.rb +2 -2
  130. data/spec/sem4r/credentials_spec.rb +10 -8
  131. data/spec/sem4r/geo_location/address_spec.rb +62 -0
  132. data/spec/sem4r/geo_location/fixtures/get-req.xml +42 -0
  133. data/spec/sem4r/geo_location/fixtures/get-res.xml +60 -0
  134. data/spec/sem4r/info/fixtures/get-req.xml +34 -0
  135. data/spec/sem4r/info/fixtures/get-res.xml +27 -0
  136. data/spec/sem4r/nokogiri_parsing_spec.rb +1 -0
  137. data/spec/sem4r/operation_spec.rb +72 -0
  138. data/spec/sem4r/report_definition/fixtures/get-list-repdef-req.xml +22 -0
  139. data/spec/sem4r/report_definition/fixtures/get-list-repdef-res.xml +73 -0
  140. data/spec/sem4r/report_definition/fixtures/getReportFields-req.xml +24 -0
  141. data/spec/sem4r/report_definition/fixtures/getReportFields-res.xml +1199 -0
  142. data/spec/sem4r/report_definition/fixtures/mutate-add-report-req.xml +63 -0
  143. data/spec/sem4r/report_definition/fixtures/mutate-add-report-res.xml +68 -0
  144. data/spec/sem4r/report_definition/report_definition_service_spec.rb +5 -5
  145. data/spec/sem4r/report_definition/report_definition_spec.rb +28 -43
  146. data/{lib/sem4r/cli/commands/cli_list_report.rb → spec/sem4r/report_definition/report_field_spec.rb} +12 -10
  147. data/spec/sem4r/rexml_parsing_spec.rb +1 -0
  148. data/spec/sem4r/{services/service_spec.rb → service_spec.rb} +1 -1
  149. data/spec/sem4r/targeting_idea/targeting_idea_selector_spec.rb +1 -1
  150. data/spec/sem4r/targeting_idea/targeting_idea_service_spec.rb +1 -1
  151. data/spec/sem4r/targeting_idea/targeting_idea_spec.rb +1 -1
  152. data/spec/sem4r/v13_account/account_service_spec.rb +2 -2
  153. data/spec/sem4r/v13_report/report_service_spec.rb +2 -2
  154. data/spec/{sem4r/cli → sem4r_cli}/cli_spec.rb +22 -27
  155. data/spec/{soap_helpers → sem4r_soap}/soap_attributes_spec.rb +3 -3
  156. data/spec/{sem4r/services/soap_message_v13_spec.rb → sem4r_soap/soap_response_spec.rb} +10 -15
  157. data/spec/{sem4r/services/soap_call_spec.rb → sem4r_soap/soap_service_spec.rb} +35 -54
  158. data/tasks/jeweler.rake +66 -0
  159. data/tasks/rspec.rake +21 -0
  160. data/tasks/sem4r.rake +25 -0
  161. data/tasks/yard.rake +31 -0
  162. metadata +173 -76
  163. data/lib/sem4r/ad_extension_override/ad_extension_override_service.rb +0 -30
  164. data/lib/sem4r/api_counters.rb +0 -8
  165. data/lib/sem4r/campaign_target/campaign_target_service.rb +0 -30
  166. data/lib/sem4r/cli/commands/cli_download_report.rb +0 -82
  167. data/lib/sem4r/services/http_connector.rb +0 -93
  168. data/lib/sem4r/services/soap_call.rb +0 -122
  169. data/lib/sem4r/services/soap_connector.rb +0 -139
  170. data/lib/sem4r/services/soap_message_v13.rb +0 -135
  171. data/lib/sem4r/services/soap_message_v2010.rb +0 -184
  172. data/lib/sem4r/v13_traffic_estimator/traffic_estimator_service.rb +0 -30
  173. data/spec/aggregates_rspec_helper.rb +0 -59
  174. data/spec/sem4r/report_definition/fixtures/mutate_add-req.xml +0 -24
  175. data/spec/sem4r/report_definition/fixtures/mutate_add-req_orig.xml +0 -45
data/lib/sem4r_cli.rb CHANGED
@@ -23,16 +23,14 @@
23
23
  # -------------------------------------------------------------------
24
24
 
25
25
  require 'optparse'
26
- require 'ostruct'
27
- # require "highline/import" # to ask password on command line
26
+ require "highline/import" # to ask password on command line
28
27
 
29
28
  require 'sem4r'
30
- require 'sem4r/cli/cli_sem'
31
- require 'sem4r/cli/cli_common_args'
32
- require 'sem4r/cli/cli_command'
33
- require 'sem4r/cli/cli_helpers'
29
+ require 'sem4r_cli/cli_mini_framework'
30
+ require 'sem4r_cli/cli_sem'
31
+ require 'sem4r_cli/cli_helpers'
34
32
 
35
33
  # commands
36
- Dir[File.join( File.dirname(__FILE__), "sem4r", "cli", "commands", "*.rb" )].each do |f|
34
+ Dir[File.join( File.dirname(__FILE__), "sem4r_cli", "commands", "*.rb" )].each do |f|
37
35
  require f
38
36
  end
@@ -0,0 +1,206 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -------------------------------------------------------------------------
3
+ # Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ #
24
+ # -------------------------------------------------------------------------
25
+
26
+ module Sem4rSoap
27
+
28
+ module HttpConnector
29
+
30
+ def self.get(logger = nil, type = :http_client)
31
+ case type
32
+ when :http_client
33
+ ConnectorHttpClient.new(logger)
34
+ when :net_http
35
+ ConnectorNetHttp.new(logger)
36
+ else
37
+ raise "unknow connector type"
38
+ end
39
+ end
40
+
41
+ #
42
+ # use Net::HTTP standard library http client
43
+ #
44
+ class ConnectorNetHttp
45
+ include SoapDumper
46
+
47
+ def initialize(logger = nil)
48
+ @logger = logger
49
+ end
50
+
51
+ def logger=(log)
52
+ @logger = log
53
+ end
54
+
55
+ #
56
+ # Send a soap request
57
+ #
58
+ # @raise [URI::InvalidURIError] when service_url is incorrect
59
+ #
60
+ def send(service_url, soap_action, soap_request_xml)
61
+ uri = URI.parse(service_url) # might raise URI::InvalidURIError
62
+
63
+ headers = {
64
+ "Content-Type" => "text/xml; charset=utf-8",
65
+ "Content-Length" => soap_request_xml.length.to_s,
66
+ "SOAPAction" => soap_action}
67
+
68
+ @logger.info("Post to #{uri.path} (#{soap_action})") if @logger
69
+ dump_soap_request(service_url, soap_request_xml)
70
+ response = post(uri, soap_request_xml, headers)
71
+ unless response
72
+ raise Sem4rError, "Connection Error"
73
+ end
74
+ response_xml = response.body
75
+ dump_soap_response(service_url, response_xml)
76
+ response_xml
77
+ end
78
+
79
+ #
80
+ # Downloads content at url in path_name
81
+ #
82
+ def download(url, path_name)
83
+ uri = URI.parse(url)
84
+ http = Net::HTTP.new(uri.host, uri.port)
85
+ request = Net::HTTP::Get.new(uri.request_uri)
86
+ request.initialize_http_header({"User-Agent" => "My Ruby Script"})
87
+ response = http.request(request)
88
+ File.open(path_name, "w") { |f| f.write(response.body) }
89
+ end
90
+
91
+ def post(uri, str, headers)
92
+ unless uri.respond_to? :path
93
+ uri = URI.parse(uri) # might raise URI::InvalidURIError
94
+ end
95
+ retries = 0; response = nil
96
+ while retries <= MAXRETRIES and response.nil?
97
+ retries += 1
98
+ begin
99
+ client = client_for_uri(uri)
100
+ response = client.post(uri.path, str, headers)
101
+ status = response.code.to_i
102
+ # pp response.class.to_s
103
+ # pp "status: #{status}"
104
+ rescue StandardError => e
105
+ @logger.warn("request_post retries!!! #{e.to_s}") if @logger
106
+ invalidate_client_for_uri(uri)
107
+ sleep(1 * retries) # wait
108
+ end
109
+ end
110
+
111
+ unless response
112
+ raise "Connection Error, Network is down?? :-((("
113
+ end
114
+ response
115
+ end
116
+
117
+ private
118
+
119
+ MAXRETRIES = 2
120
+
121
+ def client_for_uri(uri)
122
+ @clients ||= {}
123
+ key = uri.scheme + "://" + uri.host
124
+ client = @clients[key]
125
+ unless client
126
+ client = Net::HTTP.new(uri.host, uri.port)
127
+ if uri.scheme == "https"
128
+ client.use_ssl = (uri.scheme == "https")
129
+ client.verify_mode = OpenSSL::SSL::VERIFY_NONE
130
+ end
131
+ @clients[key] = client
132
+ end
133
+ client
134
+ end
135
+
136
+ def invalidate_client_for_uri(uri)
137
+ key = uri.scheme + "://" + uri.host
138
+ @clients[uri.host] = nil if @clients[key]
139
+ end
140
+
141
+ end
142
+
143
+ class ConnectorHttpClient
144
+ include SoapDumper
145
+
146
+ def initialize(logger = nil)
147
+ @logger = logger
148
+ end
149
+
150
+ def logger=(log)
151
+ @logger = log
152
+ end
153
+
154
+ #
155
+ # Send a soap request
156
+ # @return [String] soap xml response
157
+ # @raise [URI::InvalidURIError] when service_url is incorrect
158
+ #
159
+ def send(service_url, soap_action, request_xml)
160
+ uri = URI.parse(service_url)
161
+
162
+ headers = {
163
+ "Content-Type" => "text/xml; charset=utf-8",
164
+ "Content-Length" => request_xml.length.to_s,
165
+ "SOAPAction" => soap_action}
166
+
167
+ @logger.info("Post to #{uri.path} (#{soap_action})") if @logger
168
+ dump_soap_request(service_url, request_xml)
169
+ response = post(service_url, request_xml, headers)
170
+ unless response
171
+ raise Sem4rError, "Connection Error"
172
+ end
173
+ response_xml = response.content
174
+ dump_soap_response(service_url, response_xml)
175
+ response_xml
176
+ end
177
+
178
+ #
179
+ # Downloads content at url in path_name
180
+ #
181
+ def download(url, path_name)
182
+ client = HTTPClient.new(:agent_name => 'Ruby') # agentname
183
+ File.open(path_name, "w") do |file|
184
+ client.get_content(url) do |chunk|
185
+ file.write chunk
186
+ end
187
+ end
188
+ end
189
+
190
+ #
191
+ # @return [Object] must respond to :status and :body
192
+ #
193
+ def post(service_url, body, headers)
194
+ client = HTTPClient.new(:agent_name => 'Ruby') # agentname
195
+ response = client.post(service_url, body, headers)
196
+ unless response
197
+ raise "Connection Error, Network is down?? :-((("
198
+ end
199
+ response.instance_eval { def body; content; end}
200
+ response
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+ end # module Sem4rSoap
@@ -22,7 +22,7 @@
22
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  # -------------------------------------------------------------------
24
24
 
25
- module Sem4r
25
+ module Sem4rSoap
26
26
 
27
27
  class MetaSoapAttribute
28
28
  attr_reader :name, :xpath
@@ -31,7 +31,7 @@ module Sem4r
31
31
  if xpath
32
32
  @xpath = xpath
33
33
  else
34
- @xpath = name.to_s.camel_case
34
+ @xpath = name.to_s.camel_case
35
35
  end
36
36
  end
37
37
 
@@ -68,6 +68,12 @@ module Sem4r
68
68
  self
69
69
  end
70
70
 
71
+ def _to_s
72
+ self.class.attributes.map do |a|
73
+ if a.enum? then "" else self.send(a.name) end
74
+ end.join(' ')
75
+ end
76
+
71
77
  module ClassMethods
72
78
 
73
79
  def enum(set, values)
@@ -91,7 +97,6 @@ module Sem4r
91
97
  attr_reader name
92
98
  end
93
99
 
94
-
95
100
  #
96
101
  # constraints
97
102
  # :values_in
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  # -------------------------------------------------------------------------
2
3
  # Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
3
4
  #
@@ -22,27 +23,36 @@
22
23
  #
23
24
  # -------------------------------------------------------------------------
24
25
 
25
- module Sem4r
26
+ module Sem4rSoap
26
27
 
27
28
  module SoapDumper
28
29
 
29
30
  def initialize
30
- @soap_dump = false
31
+ @soap_dump = false
31
32
  @soap_dump_log = nil
32
33
  end
33
34
 
34
- def dump_soap_options( dump_options )
35
- @soap_dump = true
35
+ #
36
+ # set the options for the dumping soap message
37
+ #
38
+ # @param [Hash] options
39
+ # @option options [String] :directory
40
+ # @option options [String] :file
41
+ # @option options [String] :format
42
+ # @option options [String] :interceptor
43
+ #
44
+ def dump_soap_options(options)
45
+ @soap_dump = true
36
46
  @soap_dump_log = nil
37
47
 
38
- if dump_options[:directory]
39
- @soap_dump_dir = dump_options[:directory]
48
+ if options[:directory]
49
+ @soap_dump_dir = options[:directory]
40
50
  else
41
- @soap_dump_log = File.open( dump_options[:file], "w" )
51
+ @soap_dump_log = File.open(options[:file], "w")
42
52
  end
43
- @soap_dump_format = false || dump_options[:format]
53
+ @soap_dump_format = false || options[:format]
44
54
 
45
- @soap_dump_interceptor = dump_options[:interceptor] if dump_options[:interceptor]
55
+ @soap_dump_interceptor = options[:interceptor] if options[:interceptor]
46
56
  end
47
57
 
48
58
  def dump_soap_request(service_url, request_xml)
@@ -60,9 +70,9 @@ module Sem4r
60
70
  return unless @soap_dump
61
71
  response_xml.gsub(/<email[^>]*>.+<\/email>/, "<email>**censured**</email>")
62
72
  str = ""
63
- str << "<!-- response -->\n" unless @soap_dump_dir
73
+ str << "<!-- response -->\n" unless @soap_dump_dir
64
74
  str << xml_to_s(response_xml) << "\n"
65
- str << "<!-- end -->" unless @soap_dump_dir
75
+ str << "<!-- end -->" unless @soap_dump_dir
66
76
  dump(service_url, "res", str)
67
77
  end
68
78
 
@@ -73,12 +83,12 @@ module Sem4r
73
83
  @soap_dump_interceptor.call(service_url, type, str) if @soap_dump_interceptor
74
84
 
75
85
  if @soap_dump_dir
76
- service = service_url.match(/\/([^\/]*)$/)[1]
86
+ service = service_url.match(/\/([^\/]*)$/)[1]
77
87
  filename = Time.now.strftime "%Y%m%d-%H%M%S-%L-#{service}-#{type}.xml"
78
88
 
79
89
  FileUtils.mkdir_p(@soap_dump_dir) unless File.directory?(@soap_dump_dir)
80
90
  pathname = File.join(@soap_dump_dir, filename)
81
- File.open(pathname, "w") {|f|
91
+ File.open(pathname, "w") { |f|
82
92
  f.puts str
83
93
  }
84
94
  else
@@ -93,13 +103,19 @@ module Sem4r
93
103
  else
94
104
  # TODO: using nokogiri also for pretty print xml ?
95
105
  require 'rexml/document'
96
- xml_document = REXML::Document.new(xml)
97
- f = REXML::Formatters::Pretty.new
98
- out = String.new
99
- f.write(xml_document, out)
100
- # remove xml directive
101
- out.gsub("<?xml version='1.0' encoding='UTF-8'?>","")
106
+ begin
107
+ xml_document = REXML::Document.new(xml)
108
+ f = REXML::Formatters::Pretty.new
109
+ out = String.new
110
+ f.write(xml_document, out)
111
+ # remove xml directive
112
+ out.gsub("<?xml version='1.0' encoding='UTF-8'?>", "")
113
+ rescue
114
+ puts xml
115
+ raise
116
+ end
102
117
  end
103
118
  end
104
119
  end
105
- end
120
+
121
+ end # module Sem4rSoap
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  # -------------------------------------------------------------------
2
3
  # Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
3
4
  #
@@ -21,8 +22,9 @@
21
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23
  # -------------------------------------------------------------------
23
24
 
24
- module Sem4r
25
- class SoapError < Sem4rError
25
+ module Sem4rSoap
26
+
27
+ class SoapError # < Sem4r::Sem4rError
26
28
  # attr_reader :fault_code
27
29
  # attr_reader :fault_string
28
30
  #
@@ -35,4 +37,5 @@ module Sem4r
35
37
  # "#{@fault_code}: '#{@fault_string}'"
36
38
  # end
37
39
  end
40
+
38
41
  end
@@ -0,0 +1,75 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -------------------------------------------------------------------------
3
+ # Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ #
24
+ # -------------------------------------------------------------------------
25
+
26
+ module Sem4rSoap
27
+ class SoapResponse
28
+
29
+ attr_reader :response
30
+ attr_reader :counters
31
+
32
+ def parse_response(response_xml)
33
+ # erase namespace so it more simple parsing the xml
34
+ response_xml.gsub!(/\b(ns\d:|xsi:|s:|soapenv:|env:|soap:)/, "")
35
+ response_xml.gsub!(/xmlns=["'].*?['"]/, '')
36
+ @response = Nokogiri::XML::Document.parse(response_xml)
37
+
38
+ #
39
+ # extract information from header
40
+ #
41
+ header = @response.at_xpath("/Envelope/Header/ResponseHeader") # v2010xx
42
+ if header
43
+ @counters = {
44
+ :operations => header.at_xpath("operations").text.to_i,
45
+ :response_time => header.at_xpath("responseTime").text.to_i,
46
+ :units => header.at_xpath("units").text.to_i
47
+ }
48
+ else
49
+ header = @response.at_xpath("/Envelope/Header") # v13
50
+ if header
51
+ @counters = {
52
+ :operations => header.at_xpath("operations").text.to_i,
53
+ :response_time => header.at_xpath("responseTime").text.to_i,
54
+ :units => header.at_xpath("units").text.to_i
55
+ }
56
+ end
57
+ end
58
+ #
59
+ # check soap fault
60
+ #
61
+ fault_el = @response.at_xpath("//Fault")
62
+ if fault_el
63
+ # fault_code = fault_el.at_xpath('faultcode').text
64
+ # fault_string = fault_el.at_xpath('faultstring').text
65
+ # raise SoapError, "#{fault_code}: '#{fault_string}'"
66
+
67
+ fault_string = fault_el.at_xpath('faultstring').text
68
+ @logger.error("soap error: #{fault_string}") if @logger
69
+ raise fault_string
70
+ end
71
+ self
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,137 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -------------------------------------------------------------------
3
+ # Copyright (c) 2009-2010 Sem4r sem4ruby@gmail.com
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ # -------------------------------------------------------------------
24
+
25
+ module Sem4rSoap
26
+
27
+ class SoapService
28
+
29
+ def initialize
30
+ @soap_namespaces = {}
31
+ end
32
+
33
+ def init(header_namespace, service_namespace)
34
+ @soap_namespaces = {}
35
+
36
+ @header_namespace = header_namespace
37
+ @soap_namespaces['xmlns'] = header_namespace if header_namespace
38
+
39
+ @service_namespace = service_namespace
40
+ @soap_namespaces['xmlns:s'] = service_namespace if service_namespace
41
+ end
42
+
43
+ def build_soap_message(soap_header, soap_body)
44
+ soap_message = '<?xml version="1.0" encoding="utf-8" ?>'
45
+ soap_message +=<<-EOFS
46
+ <env:Envelope
47
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
48
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
49
+ xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
50
+ EOFS
51
+
52
+ @soap_namespaces.each do |name, value|
53
+ soap_message += " #{name}=\"#{value}\""
54
+ end
55
+ soap_message += ">"
56
+
57
+ soap_message += soap_header
58
+ soap_message += "<env:Body>"
59
+ soap_message += soap_body
60
+ soap_message += "</env:Body>"
61
+
62
+ soap_message += "</env:Envelope>"
63
+ soap_message
64
+ end
65
+
66
+ def helper_call(api_version, credentials, soap_body)
67
+ soap_action = ""
68
+
69
+ case api_version
70
+ when "v13"
71
+ match_data = soap_body.match(/<(\w+)/m)
72
+ if match_data
73
+ soap_action = match_data[1]
74
+ else
75
+ raise "Soapaction not found in #{soap_body}"
76
+ end
77
+ when "v2010"
78
+ else
79
+ raise "unkwnow api version #{api_version}"
80
+ end
81
+
82
+ soap_xml = build_soap_message(build_soap_header(credentials), soap_body)
83
+ if credentials.sandbox?
84
+ _send(@sandbox_service_url, soap_action, soap_xml)
85
+ else
86
+ _send(@production_service_url, soap_action, soap_xml)
87
+ end
88
+ end
89
+
90
+ def helper_call_raw(credentials, xml_message)
91
+ soap_message = SoapMessageV2010.new(@connector, credentials)
92
+ soap_message.init( @header_namespace, @service_namespace )
93
+ if credentials.sandbox?
94
+ soap_message.send_raw(@sandbox_service_url, xml_message)
95
+ else
96
+ soap_message.send_raw(@production_service_url, xml_message)
97
+ end
98
+ end
99
+
100
+ def self._soap_call(api_version, method, options = {})
101
+ options.assert_valid_keys(:mutate)
102
+ mutate = options.delete :mutate
103
+ if mutate.nil? or mutate
104
+ smutate = "credentials.mutable?"
105
+ else
106
+ smutate = "true"
107
+ end
108
+ rubystr =<<-EOFS
109
+ define_method :#{method.to_sym} do |*args|
110
+ credentials = args.shift
111
+ if #{smutate}
112
+ soap_body = send("_#{method}", *args)
113
+ helper_call('#{api_version}', credentials, soap_body)
114
+ else
115
+ raise "mutate methods '#{method}' cannot be called on read_only profile"
116
+ end
117
+ end
118
+ EOFS
119
+ eval rubystr
120
+
121
+ rubystr =<<-EOFS
122
+ define_method :#{(method.to_s + "_raw").to_sym} do |*args|
123
+ credentials = args.shift
124
+ soap_message = args.shift
125
+ if #{smutate}
126
+ helper_call_raw('#{api_version}', credentials, soap_message)
127
+ else
128
+ raise "mutate methods '#{method}' cannot be called on read_only profile"
129
+ end
130
+ end
131
+ EOFS
132
+ eval rubystr
133
+ end
134
+
135
+ end
136
+
137
+ end # module Sem4rSoap
@@ -22,42 +22,41 @@
22
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  # -------------------------------------------------------------------
24
24
 
25
- # stdlib
25
+ module Sem4rSoap
26
26
 
27
- module Sem4r
27
+ class SoapServiceV13 < SoapService
28
28
 
29
- class CliSem
30
-
31
- def self.run
32
- cli = self.new
33
- cli.parse_and_run(ARGV)
29
+ def initialize
30
+ super
34
31
  end
35
32
 
36
- def parse_and_run( argv )
37
- common_args, command, command_args = CliCommand.split_args(argv)
38
-
39
- # $stderr.puts "debug -------------------"
40
- # $stderr.puts "common_args: #{common_args}"
41
- # $stderr.puts "command: #{command}"
42
- # $stderr.puts "command_args: #{command_args}"
43
- # $stderr.puts "debug -------------------"
33
+ def self.soap_call(method, options = {})
34
+ _soap_call("v13", method, options)
35
+ end
44
36
 
45
- cli_common_args = CliCommonArgs.new
46
- success = cli_common_args.parse_and_run(common_args)
47
- return false unless success
37
+ private
38
+
39
+ def build_soap_header(credentials)
40
+ str= <<-EOFS
41
+ <env:Header>
42
+ <email env:mustUnderstand="0">#{credentials.email}</email>
43
+ <password env:mustUnderstand="0">#{credentials.password}</password>
44
+ <useragent env:mustUnderstand="0">#{credentials.useragent}</useragent>
45
+ <developerToken env:mustUnderstand="0">#{credentials.developer_token}</developerToken>
46
+ EOFS
48
47
 
49
- if command.nil?
50
- puts "missing command try sem -h for help"
51
- return false
48
+ if credentials.client_email
49
+ str += "<clientEmail env:mustUnderstand=\"0\">#{credentials.client_email}</clientEmail>"
52
50
  end
53
51
 
54
- begin
55
- cmd = CliCommand.commands[command].new(cli_common_args)
56
- return cmd.parse_and_run(command_args)
57
- rescue Sem4rError
58
- puts "I am so sorry! Something went wrong! (exception #{$!.to_s})"
59
- return false
60
- end
52
+ str += "</env:Header>"
53
+ str
54
+ end
55
+
56
+ def _send(service_url, soap_action, soap_xml)
57
+ response_xml = @connector.send(service_url, soap_action, soap_xml)
58
+ soap_response = SoapResponse.new.parse_response(response_xml)
59
+ soap_response
61
60
  end
62
61
 
63
62
  end