shout-mouth-communicator 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/README.rdoc +7 -0
- data/Rakefile +2 -0
- data/lib/shout-mouth-communicator/shout-mouth-communicator.rb +241 -0
- data/lib/shout-mouth-communicator/version.rb +7 -0
- data/lib/shout-mouth-communicator.rb +1 -0
- data/shout-mouth-communicator.gemspec +25 -0
- data/specs/.gitkeep +0 -0
- data/specs/fakes/xmlrpc_server.rb +71 -0
- data/specs/fakes/xmlrpc_server_responses/add_user.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/bad_authentication.xml +30 -0
- data/specs/fakes/xmlrpc_server_responses/delete_page.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/delete_post.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/delete_user.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/edit_category.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/edit_comment.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/edit_page.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/edit_post.xml +11 -0
- data/specs/fakes/xmlrpc_server_responses/edit_tag.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/edit_user.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/get_authors.xml +41 -0
- data/specs/fakes/xmlrpc_server_responses/get_categories.xml +197 -0
- data/specs/fakes/xmlrpc_server_responses/get_comments.xml +101 -0
- data/specs/fakes/xmlrpc_server_responses/get_comments_all.xml +189 -0
- data/specs/fakes/xmlrpc_server_responses/get_comments_spam.xml +12 -0
- data/specs/fakes/xmlrpc_server_responses/get_options.xml +573 -0
- data/specs/fakes/xmlrpc_server_responses/get_page.xml +182 -0
- data/specs/fakes/xmlrpc_server_responses/get_pages.xml +188 -0
- data/specs/fakes/xmlrpc_server_responses/get_post.xml +193 -0
- data/specs/fakes/xmlrpc_server_responses/get_recent_posts.xml +385 -0
- data/specs/fakes/xmlrpc_server_responses/get_tags.xml +173 -0
- data/specs/fakes/xmlrpc_server_responses/get_user_info.xml +41 -0
- data/specs/fakes/xmlrpc_server_responses/new_category.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/new_media_object.xml +23 -0
- data/specs/fakes/xmlrpc_server_responses/new_page.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/new_post.xml +10 -0
- data/specs/fakes/xmlrpc_server_responses/set_options.xml +36 -0
- data/specs/fakes/xmlrpc_server_responses/validation_error.xml +30 -0
- data/specs/helpers/spec_helper.rb +9 -0
- data/specs/shout_mout_client_specification.rb +172 -0
- metadata +161 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm --create ruby-1.9.2@shout_mouth_communicator
|
data/Gemfile
ADDED
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -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 @@
|
|
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,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,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>
|