shout-mouth-communicator 1.0.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 (43) hide show
  1. data/.gitignore +6 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +4 -0
  4. data/README.rdoc +7 -0
  5. data/Rakefile +2 -0
  6. data/lib/shout-mouth-communicator/shout-mouth-communicator.rb +241 -0
  7. data/lib/shout-mouth-communicator/version.rb +7 -0
  8. data/lib/shout-mouth-communicator.rb +1 -0
  9. data/shout-mouth-communicator.gemspec +25 -0
  10. data/specs/.gitkeep +0 -0
  11. data/specs/fakes/xmlrpc_server.rb +71 -0
  12. data/specs/fakes/xmlrpc_server_responses/add_user.xml +10 -0
  13. data/specs/fakes/xmlrpc_server_responses/bad_authentication.xml +30 -0
  14. data/specs/fakes/xmlrpc_server_responses/delete_page.xml +10 -0
  15. data/specs/fakes/xmlrpc_server_responses/delete_post.xml +10 -0
  16. data/specs/fakes/xmlrpc_server_responses/delete_user.xml +10 -0
  17. data/specs/fakes/xmlrpc_server_responses/edit_category.xml +10 -0
  18. data/specs/fakes/xmlrpc_server_responses/edit_comment.xml +10 -0
  19. data/specs/fakes/xmlrpc_server_responses/edit_page.xml +10 -0
  20. data/specs/fakes/xmlrpc_server_responses/edit_post.xml +11 -0
  21. data/specs/fakes/xmlrpc_server_responses/edit_tag.xml +10 -0
  22. data/specs/fakes/xmlrpc_server_responses/edit_user.xml +10 -0
  23. data/specs/fakes/xmlrpc_server_responses/get_authors.xml +41 -0
  24. data/specs/fakes/xmlrpc_server_responses/get_categories.xml +197 -0
  25. data/specs/fakes/xmlrpc_server_responses/get_comments.xml +101 -0
  26. data/specs/fakes/xmlrpc_server_responses/get_comments_all.xml +189 -0
  27. data/specs/fakes/xmlrpc_server_responses/get_comments_spam.xml +12 -0
  28. data/specs/fakes/xmlrpc_server_responses/get_options.xml +573 -0
  29. data/specs/fakes/xmlrpc_server_responses/get_page.xml +182 -0
  30. data/specs/fakes/xmlrpc_server_responses/get_pages.xml +188 -0
  31. data/specs/fakes/xmlrpc_server_responses/get_post.xml +193 -0
  32. data/specs/fakes/xmlrpc_server_responses/get_recent_posts.xml +385 -0
  33. data/specs/fakes/xmlrpc_server_responses/get_tags.xml +173 -0
  34. data/specs/fakes/xmlrpc_server_responses/get_user_info.xml +41 -0
  35. data/specs/fakes/xmlrpc_server_responses/new_category.xml +10 -0
  36. data/specs/fakes/xmlrpc_server_responses/new_media_object.xml +23 -0
  37. data/specs/fakes/xmlrpc_server_responses/new_page.xml +10 -0
  38. data/specs/fakes/xmlrpc_server_responses/new_post.xml +10 -0
  39. data/specs/fakes/xmlrpc_server_responses/set_options.xml +36 -0
  40. data/specs/fakes/xmlrpc_server_responses/validation_error.xml +30 -0
  41. data/specs/helpers/spec_helper.rb +9 -0
  42. data/specs/shout_mout_client_specification.rb +172 -0
  43. metadata +161 -0
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.sw?
6
+ .DS_Store
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create ruby-1.9.2@shout_mouth_communicator
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in shout-mouth-communicator.gemspec
4
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,7 @@
1
+ ===Shout Mouth Communicator
2
+
3
+ @shout_mouth_client = ShoutMouthCommunicator.new("http://0.0.0.0:4000/xmlrpc.php", "1", "correct", "password")
4
+ @shout_mouth_client.authorized?
5
+
6
+ Check out all the possible calls
7
+ @shout_mouth_client.methods
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,241 @@
1
+ require 'xmlrpc/client'
2
+
3
+ class ShoutMouthCommunicator
4
+
5
+ def initialize(server, blogid, username, password)
6
+ @client = XMLRPC::Client.new2(server)
7
+ @blogid = blogid
8
+ @username = username
9
+ @password = password
10
+ @errors = []
11
+ end
12
+
13
+ def client
14
+ @client
15
+ end
16
+
17
+ def has_errors?
18
+ @errors.count > 0
19
+ end
20
+
21
+ def errors
22
+ @errors
23
+ end
24
+
25
+ def response
26
+ @response
27
+ end
28
+
29
+ def response=(value)
30
+ @errors = error_parser(value["fault"]["faultString"]) if value.is_a?(Hash) && value.has_key?("fault") && value["fault"]["faultCode"] == 4003
31
+ @response = value
32
+ end
33
+
34
+ def authorized?
35
+ self.response = @client.call('blogger.getUserInfo', "1", @username, @password)
36
+ !self.response.key?("fault")
37
+ end
38
+
39
+ def tags
40
+ self.response = @client.call('wp.getTags', "1", @username, @password)
41
+ self.response
42
+ end
43
+
44
+ def edit_tag tag_id, name
45
+ tag = {
46
+ :tag_id => tag_id,
47
+ :name => name
48
+ }
49
+ self.response = @client.call('shoutmouth.editTag', "1", @username, @password, tag)
50
+ self.response
51
+ end
52
+
53
+ def categories
54
+ self.response = @client.call('wp.getCategories', "1", @username, @password)
55
+ self.response
56
+ end
57
+
58
+ def new_category name, description
59
+ category = {:name => name, :slug => "not relevant", :parent_id => "0", :description => description}
60
+ self.response = @client.call('wp.newCategory', "1", @username, @password, category)
61
+ self.response
62
+ end
63
+
64
+ def edit_category category_id, name
65
+ category = {:category_id => category_id, :category => name}
66
+ self.response = @client.call('shoutmouth.editCategory', "1", @username, @password, category)
67
+ self.response
68
+ end
69
+
70
+ def posts limit = 0
71
+ self.response = @client.call('metaweblog.getRecentPosts', "1", @username, @password, limit)
72
+ self.response
73
+ end
74
+
75
+ def post post_id
76
+ self.response = @client.call('metaweblog.getPost', post_id, @username, @password, 2)
77
+ self.response
78
+ end
79
+
80
+ def new_post title, description, categories, status, created, tags
81
+ post = {
82
+ :title => title,
83
+ :description => description,
84
+ :categories => categories.split(","),
85
+ :post_status => status,
86
+ :dateCreated => created,
87
+ :mt_keywords => tags
88
+ }
89
+
90
+ self.response = @client.call('metaweblog.newPost', "1", @username, @password, post)
91
+ self.response
92
+ end
93
+
94
+
95
+ def edit_post post_id, title, description, categories, status, created, tags
96
+ post = {
97
+ :title => title,
98
+ :description => description,
99
+ :categories => categories.split(","),
100
+ :post_status => status,
101
+ :dateCreated => created,
102
+ :mt_keywords => tags
103
+ }
104
+
105
+ self.response = @client.call('metaweblog.editPost', post_id, @username, @password, post)
106
+ self.response
107
+ end
108
+
109
+ def delete_post post_id
110
+ self.response = @client.call('blogger.deletePost', "1", post_id, @username, @password, true)
111
+ self.response
112
+ end
113
+
114
+ def pages limit = 10000000
115
+ self.response = @client.call('wp.getPages', "1", @username, @password, limit)
116
+ self.response
117
+ end
118
+
119
+ def page page_id
120
+ self.response = @client.call('wp.getPage', "1", page_id, @username, @password)
121
+ self.response
122
+ end
123
+
124
+ def new_page title, body, status, order, parent_id
125
+ page = {
126
+ :title => title,
127
+ :description => body,
128
+ :page_status => status,
129
+ :wp_page_order => order,
130
+ :wp_page_parent_id => parent_id
131
+ }
132
+ self.response = @client.call('wp.newPage', "1", @username, @password, page).to_i
133
+ self.response
134
+ end
135
+
136
+ def edit_page page_id, title, body, status, order, parent_id
137
+ page = {
138
+ :postid => page_id,
139
+ :title => title,
140
+ :description => body,
141
+ :page_status => status,
142
+ :wp_page_order => order,
143
+ :wp_page_parent_id => parent_id
144
+ }
145
+ self.response = @client.call('wp.newPage', "1", @username, @password, page).to_i
146
+ self.response
147
+ end
148
+
149
+ def delete_page page_id
150
+ self.response = @client.call('wp.deletePage', "1", @username, @password, page_id)
151
+ self.response
152
+ end
153
+
154
+ #status list = active, spam or hold
155
+ def comments status = "active"
156
+ self.response = @client.call('wp.getComments', "1", @username, @password, { :status => status })
157
+ self.response
158
+ end
159
+
160
+ #status list = active, spam or hold
161
+ def comments_for_post post_id, status = "active"
162
+ self.response = @client.call('wp.getComments', "1", @username, @password, { :post_id => post_id, :status => status })
163
+ self.response
164
+ end
165
+
166
+ #status list = approve, spam or inactive
167
+ def edit_comment comment_id, content, author, author_url, author_email, status
168
+ comment = {
169
+ :content => content,
170
+ :author => author,
171
+ :author_url => author_url,
172
+ :author_email => author_email,
173
+ :status => status
174
+ }
175
+ self.response = @client.call('wp.editComment', "1", @username, @password, comment_id, comment)
176
+ self.response
177
+ end
178
+
179
+ def settings
180
+ self.response = @client.call('wp.getOptions', "1", @username, @password)
181
+ self.response
182
+ end
183
+
184
+ #{"blog_title" => "Hello World!", "blog_tagline" => "tagg!"}
185
+ def edit_settings settings
186
+ self.response = @client.call('wp.setOptions', "1", @username, @password, settings)
187
+ self.response
188
+ end
189
+
190
+ def users
191
+ self.response = @client.call('wp.getAuthors',"1", @username, @password)
192
+ self.response
193
+ end
194
+
195
+ def current_user
196
+ self.response = @client.call('blogger.getUserInfo', "1", @username, @password)
197
+ self.response
198
+ end
199
+
200
+ def add_user email, password, firstname, lastname
201
+ user = {
202
+ :email => email,
203
+ :password => password,
204
+ :firstname => firstname,
205
+ :lastname => lastname
206
+ }
207
+ self.response = @client.call('shoutmouth.addUser', "1", @username, @password, user)
208
+ self.response
209
+ end
210
+
211
+ def edit_user user_id, email, password, firstname, lastname
212
+ user = {
213
+ :user_id => user_id,
214
+ :email => email,
215
+ :password => password,
216
+ :firstname => firstname,
217
+ :lastname => lastname
218
+ }
219
+ self.response = @client.call('shoutmouth.editUser', "1", @username, @password, user)
220
+ self.response
221
+ end
222
+
223
+ def delete_user user_id
224
+ self.response = @client.call('shoutmouth.deleteUser', "1", @username, @password, user_id)
225
+ self.response
226
+ end
227
+
228
+ def upload_file name, bits
229
+ file = {
230
+ :bits => bits,
231
+ :name => name
232
+ }
233
+ self.response = @client.call('metaweblog.newMediaObject', "1", @username, @password, file)
234
+ self.response
235
+ end
236
+
237
+ private
238
+ def error_parser string
239
+ string.gsub("[","").gsub("]","").gsub("\"", "").split(",")
240
+ end
241
+ end
@@ -0,0 +1,7 @@
1
+ module Shout
2
+ module Mouth
3
+ module Communicator
4
+ VERSION = "1.0.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ require 'shout-mouth-communicator/shout-mouth-communicator'
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "shout-mouth-communicator/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "shout-mouth-communicator"
7
+ s.version = Shout::Mouth::Communicator::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Dan Watson"]
10
+ s.email = ["dan@dotnetguy.co.uk"]
11
+ s.homepage = "https://github.com/dotnetguyuk/shout-mouth-communicator"
12
+ s.summary = %q{Shout Mouth Blog Engine API Wrapper}
13
+ s.description = %q{An xmlrpc client that allows administration of the Shout Mouth blog engine"}
14
+
15
+ s.rubyforge_project = "shout-mouth-communicator"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,specs,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency('racksh')
23
+ s.add_development_dependency('thin')
24
+ s.add_development_dependency('rspec')
25
+ end
data/specs/.gitkeep ADDED
File without changes
@@ -0,0 +1,71 @@
1
+ require 'thin'
2
+ require 'xmlrpc/marshal'
3
+
4
+ class XMLrpcServer
5
+
6
+ def initialize(options={})
7
+ port = options[:port] || 4000
8
+ @thread = Thread.new { Rack::Handler::Thin.run(self, :Port => port) }
9
+ sleep 1
10
+ end
11
+
12
+ def call(env)
13
+ begin
14
+ request = Rack::Request.new(env)
15
+ #generate the xml
16
+ xml = load_xml_from_request(request.body.read, request.params)
17
+ #create xmlrpc request call
18
+ call = XMLRPC::Marshal.load_call(xml)
19
+ # convert *.getPost to get_post
20
+ method = call[0].gsub(/(.*)\.(.*)/, '\2').gsub(/([A-Z])/, '_\1').downcase
21
+ # fake authentocation
22
+ does_not_need_authentication?(method) ? authenticated = true : authenticated = authenticated?(call)
23
+ # if the fake reponse header has been set overide the response file that will be sent back to the client
24
+ method = env["HTTP_RESPONSE_FILE"] unless env["HTTP_RESPONSE_FILE"].nil?
25
+ #raise xmlrpc error response or get the xml response from the correct file
26
+ authenticated ? response = get_response_for(method) : response = get_response_for('bad_authentication')
27
+ #send the fake response
28
+ [ 200, { 'Content-Type' => 'text/xml', 'Content-Length' => response.length.to_s}, [response]]
29
+ rescue StandardError => bang
30
+ message = bang.backtrace
31
+ [500, { 'Content-Type' => 'text/plain', 'Content-Length' => message.to_s.length.to_s}, [message.to_s]]
32
+ end
33
+ end
34
+
35
+ def kill
36
+ Thread.kill(@thread)
37
+ end
38
+
39
+ private
40
+ def load_xml_from_request request_body, request_params
41
+ if request_body.empty?
42
+ hash = request_params
43
+ request_body = (hash.keys + hash.values).join
44
+ end
45
+ return request_body.gsub(">true<", ">1<").gsub(">false<", ">0<")
46
+ end
47
+
48
+ def does_not_need_authentication?(method)
49
+ ["list_methods",
50
+ "get_capabilities",
51
+ "multicall",
52
+ "say_hello",
53
+ "add_two_numbers",
54
+ "supported_methods",
55
+ "supported_text_filters",
56
+ "get_trackback_pings",
57
+ "get_pingbacks",
58
+ "ping"].include?(method)
59
+ end
60
+
61
+ def authenticated?(call)
62
+ #this is a dumbed down auth method for the fake server
63
+ #will return true if the call contains the words correct password
64
+ #else it will return false
65
+ call.to_s.gsub(/correct/).any? && call.to_s.gsub(/password/).any?
66
+ end
67
+
68
+ def get_response_for(method)
69
+ File.open(File.join(File.expand_path('../xmlrpc_server_responses', __FILE__), "#{method}.xml")).read
70
+ end
71
+ end
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <boolean>1</boolean>
7
+ </value>
8
+ </param>
9
+ </params>
10
+ </methodResponse>
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <struct>
7
+ <member>
8
+ <name>fault</name>
9
+ <value>
10
+ <struct>
11
+ <member>
12
+ <name>faultCode</name>
13
+ <value>
14
+ <int>403</int>
15
+ </value>
16
+ </member>
17
+ <member>
18
+ <name>faultString</name>
19
+ <value>
20
+ <string>Bad login/pass combination.</string>
21
+ </value>
22
+ </member>
23
+ </struct>
24
+ </value>
25
+ </member>
26
+ </struct>
27
+ </value>
28
+ </param>
29
+ </params>
30
+ </methodResponse>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <boolean>1</boolean>
7
+ </value>
8
+ </param>
9
+ </params>
10
+ </methodResponse>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <boolean>1</boolean>
7
+ </value>
8
+ </param>
9
+ </params>
10
+ </methodResponse>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <boolean>1</boolean>
7
+ </value>
8
+ </param>
9
+ </params>
10
+ </methodResponse>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <boolean>1</boolean>
7
+ </value>
8
+ </param>
9
+ </params>
10
+ </methodResponse>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <boolean>1</boolean>
7
+ </value>
8
+ </param>
9
+ </params>
10
+ </methodResponse>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <string>10</string>
7
+ </value>
8
+ </param>
9
+ </params>
10
+ </methodResponse>
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <boolean>1</boolean>
7
+ </value>
8
+ </param>
9
+ </params>
10
+ </methodResponse>
11
+
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <boolean>1</boolean>
7
+ </value>
8
+ </param>
9
+ </params>
10
+ </methodResponse>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <boolean>1</boolean>
7
+ </value>
8
+ </param>
9
+ </params>
10
+ </methodResponse>
@@ -0,0 +1,41 @@
1
+ <?xml version="1.0"?>
2
+ <methodResponse>
3
+ <params>
4
+ <param>
5
+ <value>
6
+ <array>
7
+ <data>
8
+ <value>
9
+ <struct>
10
+ <member>
11
+ <name>user_id</name>
12
+ <value>
13
+ <string>1</string>
14
+ </value>
15
+ </member>
16
+ <member>
17
+ <name>user_login</name>
18
+ <value>
19
+ <string>dan@shout_mouth.com</string>
20
+ </value>
21
+ </member>
22
+ <member>
23
+ <name>display_name</name>
24
+ <value>
25
+ <string>Daniel Watson</string>
26
+ </value>
27
+ </member>
28
+ <member>
29
+ <name>user_email</name>
30
+ <value>
31
+ <string>dan@shout_mouth.com</string>
32
+ </value>
33
+ </member>
34
+ </struct>
35
+ </value>
36
+ </data>
37
+ </array>
38
+ </value>
39
+ </param>
40
+ </params>
41
+ </methodResponse>