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.
- 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>
|