mediawiki-gateway 0.6.2 → 1.0.0.rc1
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.
- checksums.yaml +4 -4
- data/COPYING +22 -0
- data/ChangeLog +16 -0
- data/README.md +80 -21
- data/Rakefile +28 -34
- data/bin/mediawiki-gateway +203 -0
- data/lib/media_wiki.rb +4 -9
- data/lib/media_wiki/exception.rb +11 -8
- data/lib/media_wiki/fake_wiki.rb +636 -0
- data/lib/media_wiki/gateway.rb +105 -940
- data/lib/media_wiki/gateway/files.rb +173 -0
- data/lib/media_wiki/gateway/pages.rb +400 -0
- data/lib/media_wiki/gateway/query.rb +98 -0
- data/lib/media_wiki/gateway/site.rb +101 -0
- data/lib/media_wiki/gateway/users.rb +182 -0
- data/lib/media_wiki/utils.rb +47 -13
- data/lib/media_wiki/version.rb +27 -0
- data/lib/mediawiki-gateway.rb +1 -0
- data/spec/{import-test-data.xml → data/import.xml} +0 -0
- data/spec/media_wiki/gateway/files_spec.rb +34 -0
- data/spec/media_wiki/gateway/pages_spec.rb +390 -0
- data/spec/media_wiki/gateway/query_spec.rb +84 -0
- data/spec/media_wiki/gateway/site_spec.rb +122 -0
- data/spec/media_wiki/gateway/users_spec.rb +171 -0
- data/spec/media_wiki/gateway_spec.rb +129 -0
- data/spec/{live_gateway_spec.rb → media_wiki/live_gateway_spec.rb} +31 -35
- data/spec/{utils_spec.rb → media_wiki/utils_spec.rb} +41 -39
- data/spec/spec_helper.rb +17 -16
- metadata +77 -135
- data/.ruby-version +0 -1
- data/.rvmrc +0 -34
- data/Gemfile +0 -19
- data/Gemfile.lock +0 -77
- data/LICENSE +0 -21
- data/config/hosts.yml +0 -17
- data/lib/media_wiki/config.rb +0 -69
- data/mediawiki-gateway.gemspec +0 -113
- data/samples/README +0 -18
- data/samples/create_page.rb +0 -13
- data/samples/delete_batch.rb +0 -14
- data/samples/download_batch.rb +0 -15
- data/samples/email_user.rb +0 -14
- data/samples/export_xml.rb +0 -14
- data/samples/get_page.rb +0 -11
- data/samples/import_xml.rb +0 -14
- data/samples/run_fake_media_wiki.rb +0 -8
- data/samples/search_content.rb +0 -12
- data/samples/semantic_query.rb +0 -17
- data/samples/upload_commons.rb +0 -45
- data/samples/upload_file.rb +0 -13
- data/spec/fake_media_wiki/api_pages.rb +0 -135
- data/spec/fake_media_wiki/app.rb +0 -360
- data/spec/fake_media_wiki/query_handling.rb +0 -136
- data/spec/gateway_spec.rb +0 -888
data/lib/media_wiki.rb
CHANGED
@@ -1,9 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
require File.dirname(__FILE__) + '/media_wiki/gateway'
|
6
|
-
|
7
|
-
module MediaWiki
|
8
|
-
VERSION = "0.6.2"
|
9
|
-
end
|
1
|
+
require_relative 'media_wiki/version'
|
2
|
+
require_relative 'media_wiki/exception'
|
3
|
+
require_relative 'media_wiki/utils'
|
4
|
+
require_relative 'media_wiki/gateway'
|
data/lib/media_wiki/exception.rb
CHANGED
@@ -1,26 +1,29 @@
|
|
1
1
|
module MediaWiki
|
2
|
+
|
2
3
|
# General exception occurred within MediaWiki::Gateway, and parent class for MediaWiki::APIError, MediaWiki::Unauthorized.
|
3
|
-
class Exception < Exception
|
4
|
+
class Exception < ::Exception
|
4
5
|
end
|
5
6
|
|
6
7
|
# Wrapper for errors returned by MediaWiki API. Possible codes are defined in http://www.mediawiki.org/wiki/API:Errors_and_warnings.
|
7
8
|
#
|
8
9
|
# Warnings also throw errors with code 'warning', unless MediaWiki::Gateway#new was called with :ignorewarnings.
|
9
|
-
class APIError <
|
10
|
+
class APIError < Exception
|
11
|
+
|
10
12
|
attr_reader :code, :info, :message
|
11
|
-
|
13
|
+
|
12
14
|
def initialize(code, info)
|
13
|
-
@code = code
|
14
|
-
|
15
|
-
@message = "API error: code '#{code}', info '#{info}'"
|
15
|
+
@code, @info, @message = code, info,
|
16
|
+
"API error: code '#{code}', info '#{info}'"
|
16
17
|
end
|
17
18
|
|
18
19
|
def to_s
|
19
|
-
"#{self.class
|
20
|
+
"#{self.class}: #{@message}"
|
20
21
|
end
|
22
|
+
|
21
23
|
end
|
22
24
|
|
23
25
|
# User is not authorized to perform this operation. Also thrown if MediaWiki::Gateway#login fails.
|
24
|
-
class Unauthorized <
|
26
|
+
class Unauthorized < Exception
|
25
27
|
end
|
28
|
+
|
26
29
|
end
|
@@ -0,0 +1,636 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sham_rack'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
module MediaWiki
|
6
|
+
|
7
|
+
# A simple Rack app that stubs out a web service, for testing.
|
8
|
+
|
9
|
+
module FakeWiki
|
10
|
+
|
11
|
+
class App < Sinatra::Base
|
12
|
+
|
13
|
+
set :show_exceptions, false
|
14
|
+
set :environment, :development
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
reset
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset
|
22
|
+
@sequence_id = 0
|
23
|
+
|
24
|
+
@users = {}
|
25
|
+
add_user('atlasmw', 'wombat', 'local', true)
|
26
|
+
add_user('nonadmin', 'sekrit', 'local', false)
|
27
|
+
add_user('ldapuser', 'ldappass', 'ldapdomain', false)
|
28
|
+
|
29
|
+
@pages = ApiPages.new
|
30
|
+
@pages.add('Main Page', 'Content')
|
31
|
+
@pages.add('Main 2', 'Content')
|
32
|
+
@pages.add('Empty', '')
|
33
|
+
@pages.add('Level/Level/Index', '{{#include:Foo}} {{#include:Bar}}')
|
34
|
+
@pages.add_namespace(100, "Book")
|
35
|
+
@pages.add('Book:Italy', 'Introduction')
|
36
|
+
@pages.add_namespace(200, "Sandbox")
|
37
|
+
@pages.add('Foopage', 'Content')
|
38
|
+
@pages.add('Redirect', '#REDIRECT', true)
|
39
|
+
|
40
|
+
@extensions = { 'FooExtension' => 'r1', 'BarExtension' => 'r2', 'Semantic MediaWiki' => '1.5' }
|
41
|
+
|
42
|
+
@logged_in_users = []
|
43
|
+
end
|
44
|
+
|
45
|
+
def next_id
|
46
|
+
@sequence_id += 1
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_user(username, password, domain, is_admin)
|
50
|
+
@users[username] = {
|
51
|
+
:userid => next_id,
|
52
|
+
:username => username,
|
53
|
+
:password => password,
|
54
|
+
:domain => domain,
|
55
|
+
:is_admin => is_admin
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def logged_in(username)
|
60
|
+
@logged_in_users.include?(username)
|
61
|
+
end
|
62
|
+
|
63
|
+
get "/w/api.php" do
|
64
|
+
handle_request if params[:action] == 'query'
|
65
|
+
end
|
66
|
+
|
67
|
+
post "/w/api.php" do
|
68
|
+
handle_request
|
69
|
+
end
|
70
|
+
|
71
|
+
def handle_request
|
72
|
+
begin
|
73
|
+
halt(503, "Maxlag exceeded") if params[:maxlag].to_i < 0
|
74
|
+
|
75
|
+
@token = ApiToken.new(params)
|
76
|
+
action = params[:action]
|
77
|
+
if respond_to?(action)
|
78
|
+
content_type "application/xml"
|
79
|
+
return send(action)
|
80
|
+
end
|
81
|
+
|
82
|
+
halt(404, "Page not found")
|
83
|
+
rescue ApiError => e
|
84
|
+
return api_error_response(e.code, e.message)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def import
|
89
|
+
@token.validate_admin
|
90
|
+
|
91
|
+
api_response do |_|
|
92
|
+
_.import do
|
93
|
+
_.page(nil, :title => "Main Page", :ns => 0, :revisions => 0)
|
94
|
+
_.page(nil, :title => "Template:Header", :ns => 10, :revisions => 1)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def validate_page_overwrite(current_page)
|
100
|
+
if current_page && params[:createonly]
|
101
|
+
raise ApiError.new("articleexists", "The article you tried to create has been created already")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def edit
|
106
|
+
@token.validate
|
107
|
+
|
108
|
+
title = params[:title]
|
109
|
+
current_page = @pages.get(title)
|
110
|
+
validate_page_overwrite(current_page)
|
111
|
+
|
112
|
+
new_page = @pages.add(title, params[:text])
|
113
|
+
page_info = {:result => "Success", :pageid => new_page[:pageid], :title => new_page[:title], :newrevid => new_page[:pageid]}
|
114
|
+
if current_page
|
115
|
+
page_info.merge!(:oldrevid => current_page[:pageid])
|
116
|
+
else
|
117
|
+
page_info.merge!(:new => "", :oldrevid => 0)
|
118
|
+
end
|
119
|
+
|
120
|
+
api_response do |_|
|
121
|
+
_.edit(nil, page_info)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def delete
|
126
|
+
@token.validate_admin
|
127
|
+
|
128
|
+
title = params[:title]
|
129
|
+
raise ApiError.new("missingtitle", "The page you requested doesn't exist") unless @pages.get(title)
|
130
|
+
@pages.delete(title)
|
131
|
+
|
132
|
+
api_response do |_|
|
133
|
+
_.delete(nil, {:title => title, :reason => "Default reason"})
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def undelete
|
138
|
+
@token.validate_admin
|
139
|
+
|
140
|
+
title = params[:title]
|
141
|
+
revisions = @pages.undelete(title)
|
142
|
+
api_response do |_|
|
143
|
+
_.undelete(nil, {:title => title, :revisions => revisions})
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def upload
|
148
|
+
@token.validate
|
149
|
+
|
150
|
+
filename = params[:filename]
|
151
|
+
@pages.add(filename, params[:file])
|
152
|
+
api_response do |_|
|
153
|
+
_.upload(nil, {:filename => filename, :result => "Success"})
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def parse
|
158
|
+
page = @pages.get(params[:page])
|
159
|
+
api_response do |_|
|
160
|
+
_.parse({ :revid => page ? page[:pageid] : 0}) do
|
161
|
+
if params[:page] == "Foopage"
|
162
|
+
_.text!('Sample <B>HTML</B> content.' \
|
163
|
+
'<img width="150" height="150" class="thumbimage" src="http://upload.wikimedia.org/foo/Ruby_logo.svg" alt="Ruby logo.svg"/>' \
|
164
|
+
'<span class="editsection">[<a title="Edit section: Nomenclature" href="/w/index.php?title=Seat_of_local_government&action=edit&section=1">edit</a>]</span>' \
|
165
|
+
'<a title="Interpreted language" href="/wiki/Interpreted_language">interpreted language</a>'
|
166
|
+
)
|
167
|
+
else
|
168
|
+
_.text!('Sample <B>HTML</B> content.')
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def action
|
175
|
+
[:userrights].each do |action_type|
|
176
|
+
return send(action_type)
|
177
|
+
end
|
178
|
+
halt(404, "Page not found")
|
179
|
+
end
|
180
|
+
|
181
|
+
def query
|
182
|
+
[:prop, :export, :list, :meta].each do |query_type|
|
183
|
+
return send(query_type) if params[query_type]
|
184
|
+
end
|
185
|
+
halt(404, "Page not found")
|
186
|
+
end
|
187
|
+
|
188
|
+
def prop
|
189
|
+
return get_revisions if params[:prop] == "revisions"
|
190
|
+
return get_undelete_token if params[:drprop] == 'token'
|
191
|
+
return get_token if params[:intoken]
|
192
|
+
return get_info if params[:prop] == "info"
|
193
|
+
end
|
194
|
+
|
195
|
+
def export
|
196
|
+
Nokogiri::XML::Builder.new do |_|
|
197
|
+
_.mediawiki do
|
198
|
+
requested_page_titles.each do |requested_title|
|
199
|
+
page = @pages.get(requested_title)
|
200
|
+
_.page do
|
201
|
+
_.title(page[:title])
|
202
|
+
_.id(page[:pageid])
|
203
|
+
_.revision do
|
204
|
+
_.id(page[:pageid])
|
205
|
+
_.text!(page[:content])
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end.to_xml
|
211
|
+
end
|
212
|
+
|
213
|
+
def list
|
214
|
+
list_type = params[:list].to_sym
|
215
|
+
|
216
|
+
# api.php?action=query&list=users&ususers=Bob&ustoken=userrights
|
217
|
+
if list_type == :users && params[:ustoken] && params[:ususers]
|
218
|
+
# This "list" is actually a request for a user rights token
|
219
|
+
return get_userrights_token(params[:ususers])
|
220
|
+
end
|
221
|
+
|
222
|
+
# This is a real list
|
223
|
+
return send(list_type) if respond_to?(list_type)
|
224
|
+
halt(404, "Page not found")
|
225
|
+
end
|
226
|
+
|
227
|
+
def allpages
|
228
|
+
api_response do |_|
|
229
|
+
_.query do
|
230
|
+
_.allpages do
|
231
|
+
prefix = params[:apprefix]
|
232
|
+
namespace = @pages.namespaces_by_id[params[:apnamespace].to_i]
|
233
|
+
prefix = "#{namespace}:#{prefix}" unless namespace.empty?
|
234
|
+
@pages.list(prefix).each do |key, page|
|
235
|
+
_.p(nil, { :title => page[:title], :ns => page[:namespace], :id => page[:pageid] })
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def search
|
243
|
+
api_response do |_|
|
244
|
+
_.query do
|
245
|
+
_.search do
|
246
|
+
namespaces = params[:srnamespace] ? params[:srnamespace].split('|') : [ "0" ]
|
247
|
+
@pages.search(params[:srsearch], namespaces).first(params[:srlimit].to_i).each do |key, page|
|
248
|
+
_.p(nil, { :title => page[:title], :ns => page[:namespace], :id => page[:pageid] })
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def meta
|
256
|
+
meta_type = params[:meta].to_sym
|
257
|
+
return send(meta_type) if respond_to?(meta_type)
|
258
|
+
halt(404, "Page not found")
|
259
|
+
end
|
260
|
+
|
261
|
+
def siteinfo
|
262
|
+
if siteinfo_type = params[:siprop]
|
263
|
+
return send(siteinfo_type) if respond_to?(siteinfo_type)
|
264
|
+
halt(404, "Page not found")
|
265
|
+
else
|
266
|
+
api_response do |_|
|
267
|
+
_.query do
|
268
|
+
_.general(generator: "MediaWiki #{MediaWiki::VERSION}")
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def namespaces
|
275
|
+
api_response do |_|
|
276
|
+
_.query do
|
277
|
+
_.namespaces do
|
278
|
+
@pages.namespaces_by_prefix.each do |prefix, id|
|
279
|
+
attr = { :id => id }
|
280
|
+
attr[:canonical] = prefix unless prefix.empty?
|
281
|
+
_.ns(prefix, attr)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def extensions
|
289
|
+
api_response do |_|
|
290
|
+
_.query do
|
291
|
+
_.extensions do
|
292
|
+
@extensions.each do |name, version|
|
293
|
+
attr = { :version => version }
|
294
|
+
attr[:name] = name unless name.empty?
|
295
|
+
_.ext(name, attr)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def api_response(api_attr = {}, &block)
|
303
|
+
Nokogiri::XML::Builder.new do |_|
|
304
|
+
_.api(api_attr, &block)
|
305
|
+
end.to_xml
|
306
|
+
end
|
307
|
+
|
308
|
+
def api_error_response(code, info)
|
309
|
+
api_response do |_|
|
310
|
+
_.error(nil,
|
311
|
+
:code => code,
|
312
|
+
:info => info)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def query_pages
|
317
|
+
api_response do |_|
|
318
|
+
_.query do
|
319
|
+
_.pages do
|
320
|
+
requested_page_titles.each do |title|
|
321
|
+
yield(_, title, @pages.get(title))
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def get_info
|
329
|
+
query_pages do |_, title, page|
|
330
|
+
attributes = { :title => title, :ns => '0'}
|
331
|
+
if page.nil?
|
332
|
+
attributes[:missing] = ""
|
333
|
+
else
|
334
|
+
attributes[:redirect] = "" if page[:redirect]
|
335
|
+
end
|
336
|
+
_.page(nil, attributes)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def get_revisions
|
341
|
+
query_pages do |_, title, page|
|
342
|
+
if page.nil?
|
343
|
+
_.page(nil, { :title => title, :ns => '0', :missing => "" })
|
344
|
+
else
|
345
|
+
page = page.dup
|
346
|
+
content = page.delete(:content)
|
347
|
+
_.page(page.merge({ :ns => 0 })) do
|
348
|
+
_.revisions do
|
349
|
+
_.rev(content)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def user
|
357
|
+
username = request.cookies['login']
|
358
|
+
@users[username] if logged_in(username)
|
359
|
+
end
|
360
|
+
|
361
|
+
def requested_page_titles
|
362
|
+
params[:titles].split("|")
|
363
|
+
end
|
364
|
+
|
365
|
+
def tokens
|
366
|
+
@token.request(user)
|
367
|
+
|
368
|
+
api_response do |_|
|
369
|
+
_.tokens(:optionstoken => @token.optionstoken)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def get_token
|
374
|
+
token_str = @token.request(user)
|
375
|
+
query_pages do |_, title, page|
|
376
|
+
page = page ? page.dup : {}
|
377
|
+
page[params[:intoken] + "token"] = token_str if token_str
|
378
|
+
_.page(nil, page.merge({ :ns => 0 }))
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def get_undelete_token
|
383
|
+
@token.set_type 'undelete'
|
384
|
+
token_str = @token.request(user)
|
385
|
+
api_response do |_|
|
386
|
+
_.query do
|
387
|
+
_.deletedrevs do
|
388
|
+
requested_page_titles.select {|title| ! @pages.get(title) }.each do |title|
|
389
|
+
_.page(nil, { :title => title, :token => token_str })
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
def get_userrights_token(username)
|
397
|
+
@token.set_type 'userrights'
|
398
|
+
token_str = @token.request(user)
|
399
|
+
|
400
|
+
user_to_manage = @users[username]
|
401
|
+
|
402
|
+
if user_to_manage
|
403
|
+
api_response do |_|
|
404
|
+
_.query do
|
405
|
+
_.users do
|
406
|
+
_.user(nil, { :name => user_to_manage[:username], :userrightstoken => token_str })
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
else
|
411
|
+
api_response do |_|
|
412
|
+
_.error(nil, { :code => 'nosuchuser', :info => "The user '#{params[:ususer].to_s}' does not exist"} )
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def login
|
418
|
+
user = @users[params[:lgname]]
|
419
|
+
if user and user[:domain] == params[:lgdomain]
|
420
|
+
if params[:lgpassword] == user[:password]
|
421
|
+
@logged_in_users << user[:username]
|
422
|
+
response.set_cookie('login', user[:username])
|
423
|
+
result = { :result => "Success", :lguserid => "1", :lgusername => "Atlasmw"}
|
424
|
+
else
|
425
|
+
result = { :result => "WrongPass" }
|
426
|
+
end
|
427
|
+
else
|
428
|
+
result = { :result => "NotExists" }
|
429
|
+
end
|
430
|
+
|
431
|
+
api_response do |_|
|
432
|
+
_.login(nil, result)
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
def createaccount
|
437
|
+
api_response do |_|
|
438
|
+
@token.request(user)
|
439
|
+
|
440
|
+
if params[:token] && !params[:token].empty?
|
441
|
+
@token.validate_admin
|
442
|
+
add_user(params[:name], params[:password], 'local', false)
|
443
|
+
_.createaccount(:token => @token.createusertoken, :userid => @users.length, :username => params[:name], :result => 'success')
|
444
|
+
else
|
445
|
+
_.createaccount(:token => @token.createusertoken, :result => 'needtoken')
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
def options
|
451
|
+
api_response(:options => 'success')
|
452
|
+
end
|
453
|
+
|
454
|
+
def userrights
|
455
|
+
api_response do |_|
|
456
|
+
_.userrights({:user => params[:user]}) do
|
457
|
+
_.removed do
|
458
|
+
params[:remove].split('|').each do |removed_group|
|
459
|
+
_.group(removed_group)
|
460
|
+
end
|
461
|
+
end
|
462
|
+
_.added do
|
463
|
+
params[:add].split('|').each do |added_group|
|
464
|
+
_.group(added_group)
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
end
|
472
|
+
|
473
|
+
class WikiPage
|
474
|
+
|
475
|
+
def initialize(options={})
|
476
|
+
options.each { |k, v| send("#{k}=", v) }
|
477
|
+
end
|
478
|
+
|
479
|
+
attr_accessor :content, :author
|
480
|
+
|
481
|
+
end
|
482
|
+
|
483
|
+
class ApiPages
|
484
|
+
|
485
|
+
def initialize
|
486
|
+
@page_id = 0
|
487
|
+
@pages = {}
|
488
|
+
@namespaces = { "" => 0 }
|
489
|
+
end
|
490
|
+
|
491
|
+
def add_namespace(id, prefix)
|
492
|
+
@namespaces[prefix] = id
|
493
|
+
end
|
494
|
+
|
495
|
+
def namespaces_by_prefix
|
496
|
+
@namespaces
|
497
|
+
end
|
498
|
+
|
499
|
+
def namespaces_by_id
|
500
|
+
@namespaces.invert
|
501
|
+
end
|
502
|
+
|
503
|
+
def add(title, content, redirect=false)
|
504
|
+
@page_id += 1
|
505
|
+
dummy, prefix = title.split(":", 2).reverse
|
506
|
+
@pages[title] = {
|
507
|
+
:pageid => @page_id,
|
508
|
+
:namespace => namespaces_by_prefix[prefix || ""],
|
509
|
+
:title => title,
|
510
|
+
:content => content,
|
511
|
+
:redirect => redirect
|
512
|
+
}
|
513
|
+
end
|
514
|
+
|
515
|
+
def get(title)
|
516
|
+
@pages[title]
|
517
|
+
end
|
518
|
+
|
519
|
+
def list(prefix)
|
520
|
+
@pages.select do |key, page|
|
521
|
+
key =~ /^#{prefix}/
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
def search(searchkey, namespaces)
|
526
|
+
raise ApiError.new("srparam-search", "empty search string is not allowed") if searchkey.empty?
|
527
|
+
@pages.select do |key, page|
|
528
|
+
page[:content] =~ /#{searchkey}/ and namespaces.include? page[:namespace].to_s
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
def delete(title)
|
533
|
+
@pages.delete(title)
|
534
|
+
end
|
535
|
+
|
536
|
+
def undelete(title)
|
537
|
+
if @pages[title]
|
538
|
+
0
|
539
|
+
else
|
540
|
+
add(title, "Undeleted content")
|
541
|
+
1
|
542
|
+
end
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
class ApiToken
|
547
|
+
|
548
|
+
ADMIN_TOKEN = "admin_token+\\"
|
549
|
+
REGULAR_TOKEN = "regular_token+\\"
|
550
|
+
BLANK_TOKEN = "+\\"
|
551
|
+
|
552
|
+
def initialize(params)
|
553
|
+
@token_str = params[:token]
|
554
|
+
@token_in = params[:intoken]
|
555
|
+
end
|
556
|
+
|
557
|
+
def set_type(type)
|
558
|
+
@token_in = type
|
559
|
+
end
|
560
|
+
|
561
|
+
def validate
|
562
|
+
unless @token_str
|
563
|
+
raise ApiError.new("notoken", "The token parameter must be set")
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
def validate_admin
|
568
|
+
validate
|
569
|
+
if @token_str != ADMIN_TOKEN
|
570
|
+
raise ApiError.new("badtoken", "Invalid token")
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
def request(user)
|
575
|
+
@user = user
|
576
|
+
respond_to?(requested_token_type) ? send(requested_token_type) : nil
|
577
|
+
end
|
578
|
+
|
579
|
+
def requested_token_type
|
580
|
+
"#{@token_in}token".to_sym
|
581
|
+
end
|
582
|
+
|
583
|
+
def importtoken
|
584
|
+
if @user && @user[:is_admin]
|
585
|
+
ADMIN_TOKEN
|
586
|
+
else
|
587
|
+
nil
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
alias_method :deletetoken, :importtoken
|
592
|
+
alias_method :undeletetoken, :importtoken
|
593
|
+
alias_method :userrightstoken, :importtoken
|
594
|
+
alias_method :createusertoken, :importtoken
|
595
|
+
|
596
|
+
def edittoken
|
597
|
+
if @user
|
598
|
+
REGULAR_TOKEN
|
599
|
+
else
|
600
|
+
BLANK_TOKEN
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
alias_method :optionstoken, :edittoken
|
605
|
+
|
606
|
+
end
|
607
|
+
|
608
|
+
class ApiError < StandardError
|
609
|
+
|
610
|
+
attr_reader :code, :message
|
611
|
+
|
612
|
+
def initialize(code, message)
|
613
|
+
@code = code
|
614
|
+
@message = message
|
615
|
+
end
|
616
|
+
|
617
|
+
end
|
618
|
+
|
619
|
+
module RSpecAdapter
|
620
|
+
|
621
|
+
ADDRESS = 'dummy-wiki.example'
|
622
|
+
|
623
|
+
def self.enhance(config, *args)
|
624
|
+
ShamRack.mount($fake_media_wiki = App.new!, ADDRESS)
|
625
|
+
|
626
|
+
config.before(*args) {
|
627
|
+
@gateway = Gateway.new("http://#{ADDRESS}/w/api.php")
|
628
|
+
$fake_media_wiki.reset
|
629
|
+
}
|
630
|
+
end
|
631
|
+
|
632
|
+
end
|
633
|
+
|
634
|
+
end
|
635
|
+
|
636
|
+
end
|