mediawiki-gateway 0.4.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/media_wiki.rb CHANGED
@@ -5,5 +5,5 @@ require File.dirname(__FILE__) + '/media_wiki/utils'
5
5
  require File.dirname(__FILE__) + '/media_wiki/gateway'
6
6
 
7
7
  module MediaWiki
8
- VERSION = "0.4.5"
8
+ VERSION = "0.5.0"
9
9
  end
@@ -6,10 +6,10 @@ require 'uri'
6
6
  require 'active_support'
7
7
 
8
8
  module MediaWiki
9
-
9
+
10
10
  class Gateway
11
11
  attr_reader :log
12
-
12
+
13
13
  # Set up a MediaWiki::Gateway for a given MediaWiki installation
14
14
  #
15
15
  # [url] Path to API of target MediaWiki (eg. "http://en.wikipedia.org/w/api.php")
@@ -19,29 +19,31 @@ module MediaWiki
19
19
  # [:bot] When set to true, executes API queries with the bot parameter (see http://www.mediawiki.org/wiki/API:Edit#Parameters). Defaults to false.
20
20
  # [:ignorewarnings] Log API warnings and invalid page titles, instead throwing MediaWiki::APIError
21
21
  # [:limit] Maximum number of results returned per search (see http://www.mediawiki.org/wiki/API:Query_-_Lists#Limits), defaults to the MediaWiki default of 500.
22
+ # [:logdevice] Log device to use. Defaults to STDERR
22
23
  # [:loglevel] Log level to use, defaults to Logger::WARN. Set to Logger::DEBUG to dump every request and response to the log.
23
24
  # [:maxlag] Maximum allowed server lag (see http://www.mediawiki.org/wiki/Manual:Maxlag_parameter), defaults to 5 seconds.
24
25
  # [:retry_count] Number of times to try before giving up if MediaWiki returns 503 Service Unavailable, defaults to 3 (original request plus two retries).
25
26
  # [:retry_delay] Seconds to wait before retry if MediaWiki returns 503 Service Unavailable, defaults to 10 seconds.
26
27
  def initialize(url, options={})
27
28
  default_options = {
29
+ :bot => false,
28
30
  :limit => 500,
31
+ :logdevice => STDERR,
29
32
  :loglevel => Logger::WARN,
30
33
  :maxlag => 5,
31
34
  :retry_count => 3,
32
35
  :retry_delay => 10,
33
- :bot => false
34
36
  }
35
37
  @options = default_options.merge(options)
36
38
  @wiki_url = url
37
- @log = Logger.new(STDERR)
39
+ @log = Logger.new(@options[:logdevice])
38
40
  @log.level = @options[:loglevel]
39
41
  @headers = { "User-Agent" => "MediaWiki::Gateway/#{MediaWiki::VERSION}" }
40
42
  @cookies = {}
41
43
  end
42
-
44
+
43
45
  attr_reader :base_url, :cookies
44
-
46
+
45
47
  # Login to MediaWiki
46
48
  #
47
49
  # [username] Username
@@ -55,7 +57,7 @@ module MediaWiki
55
57
  @password = password
56
58
  @username = username
57
59
  end
58
-
60
+
59
61
  # Fetch MediaWiki page in MediaWiki format. Does not follow redirects.
60
62
  #
61
63
  # [page_title] Page title to fetch
@@ -91,7 +93,7 @@ module MediaWiki
91
93
  # * [:linkbase] supply a String to prefix all internal (relative) links with. '/wiki/' is assumed to be the base of a relative link
92
94
  # * [:noeditsections] strips all edit-links if set to +true+
93
95
  # * [:noimages] strips all +img+ tags from the rendered text if set to +true+
94
- #
96
+ #
95
97
  # Returns rendered page as string, or nil if the page does not exist
96
98
  def render(page_title, options = {})
97
99
  form_data = {'action' => 'parse', 'page' => page_title}
@@ -118,7 +120,7 @@ module MediaWiki
118
120
  end
119
121
  rendered
120
122
  end
121
-
123
+
122
124
  # Create a new page, or overwrite an existing one
123
125
  #
124
126
  # [title] Page title to create or overwrite, string
@@ -220,11 +222,11 @@ module MediaWiki
220
222
  def move(from, to, options={})
221
223
  valid_options = %w(movesubpages movetalk noredirect reason watch unwatch)
222
224
  options.keys.each{|opt| raise ArgumentError.new("Unknown option '#{opt}'") unless valid_options.include?(opt.to_s)}
223
-
225
+
224
226
  form_data = options.merge({'action' => 'move', 'from' => from, 'to' => to, 'token' => get_token('move', from)})
225
227
  make_api_request(form_data)
226
228
  end
227
-
229
+
228
230
  # Delete one page. (MediaWiki API does not support deleting multiple pages at a time.)
229
231
  #
230
232
  # [title] Title of page to delete
@@ -273,6 +275,28 @@ module MediaWiki
273
275
  titles
274
276
  end
275
277
 
278
+ # Get a list of pages that are members of a category
279
+ #
280
+ # [category] Name of the category
281
+ # [options] Optional hash of additional options. See http://www.mediawiki.org/wiki/API:Categorymembers
282
+ #
283
+ # Returns array of page titles (empty if no matches)
284
+ def category_members(category, options = {})
285
+ titles = []
286
+ apfrom = nil
287
+ begin
288
+ form_data = options.merge(
289
+ {'action' => 'query',
290
+ 'list' => 'categorymembers',
291
+ 'apfrom' => apfrom,
292
+ 'cmtitle' => category,
293
+ 'cmlimit' => @options[:limit]})
294
+ res, apfrom = make_api_request(form_data, '//query-continue/categorymembers/@apfrom')
295
+ titles += REXML::XPath.match(res, "//cm").map { |x| x.attributes["title"] }
296
+ end while apfrom
297
+ titles
298
+ end
299
+
276
300
  # Get a list of pages that link to a target page
277
301
  #
278
302
  # [title] Link target page
@@ -326,11 +350,11 @@ module MediaWiki
326
350
  titles
327
351
  end
328
352
 
329
- # Upload a file, or get the status of pending uploads. Several
353
+ # Upload a file, or get the status of pending uploads. Several
330
354
  # methods are available:
331
355
  #
332
356
  # * Upload file contents directly.
333
- # * Have the MediaWiki server fetch a file from a URL, using the
357
+ # * Have the MediaWiki server fetch a file from a URL, using the
334
358
  # "url" parameter
335
359
  #
336
360
  # Requires Mediawiki 1.16+
@@ -338,8 +362,8 @@ module MediaWiki
338
362
  # Arguments:
339
363
  # * [path] Path to file to upload. Set to nil if uploading from URL.
340
364
  # * [options] Hash of additional options
341
- #
342
- # Note that queries using session keys must be done in the same login
365
+ #
366
+ # Note that queries using session keys must be done in the same login
343
367
  # session as the query that originally returned the key (i.e. do not
344
368
  # log out and then log back in).
345
369
  #
@@ -355,7 +379,7 @@ module MediaWiki
355
379
  # * :description - Description of this file. Used as 'text'.
356
380
  # * :target - Target filename, same as 'filename'.
357
381
  # * :summary - Edit summary for history. Used as 'comment'. Also used as 'text' if neither it or :description is specified.
358
- #
382
+ #
359
383
  # Examples:
360
384
  # mw.upload('/path/to/local/file.jpg', 'filename' => "RemoteFile.jpg")
361
385
  # mw.upload(nil, 'filename' => "RemoteFile2.jpg", 'url' => 'http://remote.com/server/file.jpg')
@@ -404,7 +428,7 @@ module MediaWiki
404
428
  page = make_api_request(form_data).first.elements["query/pages/page"]
405
429
  !!(valid_page?(page) and page.attributes["redirect"])
406
430
  end
407
-
431
+
408
432
  # Requests image info from MediaWiki. Follows redirects.
409
433
  #
410
434
  # _file_name_or_page_id_ should be either:
@@ -461,12 +485,12 @@ module MediaWiki
461
485
  end
462
486
  end
463
487
 
464
- # Download _file_name_ (without "File:" or "Image:" prefix). Returns file contents. All options are passed to
488
+ # Download _file_name_ (without "File:" or "Image:" prefix). Returns file contents. All options are passed to
465
489
  # #image_info however options['iiprop'] is forced to url. You can still
466
490
  # set other options to control what file you want to download.
467
491
  def download(file_name, options={})
468
492
  options['iiprop'] = 'url'
469
-
493
+
470
494
  attributes = image_info(file_name, options)
471
495
  if attributes
472
496
  RestClient.get attributes['url']
@@ -479,7 +503,7 @@ module MediaWiki
479
503
  #
480
504
  # [xml] String or array of page names to fetch
481
505
  #
482
- # Returns XML array <api><import><page/><page/>...
506
+ # Returns XML array <api><import><page/><page/>...
483
507
  # <page revisions="1"> (or more) means successfully imported
484
508
  # <page revisions="0"> means duplicate, not imported
485
509
  def import(xmlfile)
@@ -525,7 +549,7 @@ module MediaWiki
525
549
  extensions
526
550
  end
527
551
  end
528
-
552
+
529
553
  # Execute Semantic Mediawiki query
530
554
  #
531
555
  # [query] Semantic Mediawiki query
@@ -538,7 +562,7 @@ module MediaWiki
538
562
  xml, dummy = make_api_request(form_data)
539
563
  return xml.elements["parse/text"].text
540
564
  end
541
-
565
+
542
566
  # Set groups for a user
543
567
  #
544
568
  # [user] Username of user to modify
@@ -599,10 +623,10 @@ module MediaWiki
599
623
  raise Unauthorized.new "User '#{@username}' is not permitted to perform this operation: get_userrights_token"
600
624
  end
601
625
  end
602
-
626
+
603
627
  token
604
628
  end
605
-
629
+
606
630
  def userrights(user, token, groups_to_add, groups_to_remove, reason)
607
631
  # groups_to_add and groups_to_remove can be a string or an array. Turn them into MediaWiki's pipe-delimited list format.
608
632
  if groups_to_add.is_a? Array
@@ -620,7 +644,7 @@ module MediaWiki
620
644
  res, dummy = make_api_request(form_data)
621
645
  res
622
646
  end
623
-
647
+
624
648
  # Make generic request to API
625
649
  #
626
650
  # [form_data] hash or string of attributes to post
@@ -634,15 +658,14 @@ module MediaWiki
634
658
  form_data['maxlag'] = @options[:maxlag]
635
659
  form_data['bot']="1" if @options[:bot]
636
660
  end
637
- log.debug("REQ: #{form_data.inspect}, #{@cookies.inspect}")
638
- RestClient.post(@wiki_url, form_data, @headers.merge({:cookies => @cookies})) do |response, &block|
661
+ http_send(@wiki_url, form_data, @headers.merge({:cookies => @cookies})) do |response, &block|
639
662
  if response.code == 503 and retry_count < @options[:retry_count]
640
663
  log.warn("503 Service Unavailable: #{response.body}. Retry in #{@options[:retry_delay]} seconds.")
641
664
  sleep @options[:retry_delay]
642
665
  make_api_request(form_data, continue_xpath, retry_count + 1)
643
666
  end
644
667
  # Check response for errors and return XML
645
- raise MediaWiki::Exception.new "Bad response: #{response}" unless response.code >= 200 and response.code < 300
668
+ raise MediaWiki::Exception.new "Bad response: #{response}" unless response.code >= 200 and response.code < 300
646
669
  doc = get_response(response.dup)
647
670
  if(form_data['action'] == 'login')
648
671
  login_result = doc.elements["login"].attributes['result']
@@ -657,7 +680,19 @@ module MediaWiki
657
680
  return [doc, continue]
658
681
  end
659
682
  end
660
-
683
+
684
+ # Execute the HTTP request using either GET or POST as appropriate
685
+ def http_send url, form_data, headers, &block
686
+ if form_data['action'] == 'query'
687
+ log.debug("GET: #{form_data.inspect}, #{@cookies.inspect}")
688
+ headers[:params] = form_data
689
+ RestClient.get url, headers, &block
690
+ else
691
+ log.debug("POST: #{form_data.inspect}, #{@cookies.inspect}")
692
+ RestClient.post url, form_data, headers, &block
693
+ end
694
+ end
695
+
661
696
  # Get API XML response
662
697
  # If there are errors or warnings, raise APIError
663
698
  # Otherwise return XML root
@@ -680,7 +715,7 @@ module MediaWiki
680
715
  end
681
716
  doc
682
717
  end
683
-
718
+
684
719
  def valid_page?(page)
685
720
  return false unless page
686
721
  return false if page.attributes["missing"]
@@ -690,7 +725,7 @@ module MediaWiki
690
725
  true
691
726
  end
692
727
  end
693
-
728
+
694
729
  def warning(msg)
695
730
  if @options[:ignorewarnings]
696
731
  log.warn(msg)
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "mediawiki-gateway"
8
- s.version = "0.4.5"
8
+ s.version = "0.5.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jani Patokallio"]
12
- s.date = "2012-04-18"
12
+ s.date = "2012-06-01"
13
13
  s.description = ""
14
14
  s.email = "jpatokal@iki.fi"
15
15
  s.extra_rdoc_files = [
@@ -46,7 +46,7 @@ Gem::Specification.new do |s|
46
46
  ]
47
47
  s.homepage = "http://github.com/jpatokal/mediawiki-gateway"
48
48
  s.require_paths = ["lib"]
49
- s.rubygems_version = "1.8.10"
49
+ s.rubygems_version = "1.8.24"
50
50
  s.summary = "Connect to the mediawiki API"
51
51
 
52
52
  if s.respond_to? :specification_version then
@@ -8,7 +8,7 @@ require 'spec/fake_media_wiki/query_handling'
8
8
  module FakeMediaWiki
9
9
 
10
10
  class App < Sinatra::Base
11
-
11
+
12
12
  set :show_exceptions, false
13
13
  set :environment, :development
14
14
 
@@ -16,7 +16,7 @@ module FakeMediaWiki
16
16
  reset
17
17
  super
18
18
  end
19
-
19
+
20
20
  def reset
21
21
  @sequence_id = 0
22
22
 
@@ -24,7 +24,7 @@ module FakeMediaWiki
24
24
  add_user('atlasmw', 'wombat', 'local', true)
25
25
  add_user('nonadmin', 'sekrit', 'local', false)
26
26
  add_user('ldapuser', 'ldappass', 'ldapdomain', false)
27
-
27
+
28
28
  @pages = ApiPages.new
29
29
  @pages.add('Main Page', 'Content')
30
30
  @pages.add('Main 2', 'Content')
@@ -37,7 +37,7 @@ module FakeMediaWiki
37
37
  @pages.add('Redirect', '#REDIRECT', true)
38
38
 
39
39
  @extensions = { 'FooExtension' => 'r1', 'BarExtension' => 'r2' }
40
-
40
+
41
41
  @logged_in_users = []
42
42
  end
43
43
 
@@ -54,14 +54,22 @@ module FakeMediaWiki
54
54
  :is_admin => is_admin
55
55
  }
56
56
  end
57
-
57
+
58
58
  def logged_in(username)
59
59
  @logged_in_users.include?(username)
60
60
  end
61
61
 
62
+ get "/w/api.php" do
63
+ handle_request if params[:action] == 'query'
64
+ end
65
+
62
66
  post "/w/api.php" do
67
+ handle_request
68
+ end
69
+
70
+ def handle_request
63
71
  begin
64
- halt(503, "Maxlag exceeded") if params[:maxlag].to_i < 0
72
+ halt(503, "Maxlag exceeded") if params[:maxlag].to_i < 0
65
73
 
66
74
  @token = ApiToken.new(params)
67
75
  action = params[:action]
@@ -69,7 +77,7 @@ module FakeMediaWiki
69
77
  content_type "application/xml"
70
78
  return send(action)
71
79
  end
72
-
80
+
73
81
  halt(404, "Page not found")
74
82
  rescue FakeMediaWiki::ApiError => e
75
83
  return api_error_response(e.code, e.message)
@@ -127,24 +135,24 @@ module FakeMediaWiki
127
135
 
128
136
  def undelete
129
137
  @token.validate_admin
130
-
138
+
131
139
  title = params[:title]
132
140
  revisions = @pages.undelete(title)
133
141
  api_response do |_|
134
142
  _.undelete(nil, {:title => title, :revisions => revisions})
135
143
  end
136
144
  end
137
-
145
+
138
146
  def upload
139
147
  @token.validate
140
-
148
+
141
149
  filename = params[:filename]
142
150
  @pages.add(filename, params[:file])
143
151
  api_response do |_|
144
152
  _.upload(nil, {:filename => filename, :result => "Success"})
145
153
  end
146
154
  end
147
-
155
+
148
156
  def parse
149
157
  page = @pages.get(params[:page])
150
158
  api_response do |_|
@@ -161,7 +169,7 @@ module FakeMediaWiki
161
169
  end
162
170
  end
163
171
  end
164
-
172
+
165
173
  include QueryHandling
166
174
 
167
175
  def api_response
@@ -203,7 +211,7 @@ module FakeMediaWiki
203
211
  _.page(nil, attributes)
204
212
  end
205
213
  end
206
-
214
+
207
215
  def get_revisions
208
216
  query_pages do |_, title, page|
209
217
  if page.nil?
@@ -224,11 +232,11 @@ module FakeMediaWiki
224
232
  username = request.cookies['login']
225
233
  @users[username] if logged_in(username)
226
234
  end
227
-
235
+
228
236
  def requested_page_titles
229
237
  params[:titles].split("|")
230
238
  end
231
-
239
+
232
240
  def get_token
233
241
  token_str = @token.request(user)
234
242
  query_pages do |_, title, page|
@@ -255,9 +263,9 @@ module FakeMediaWiki
255
263
  def get_userrights_token(username)
256
264
  @token.set_type 'userrights'
257
265
  token_str = @token.request(user)
258
-
266
+
259
267
  user_to_manage = @users[username]
260
-
268
+
261
269
  if user_to_manage
262
270
  api_response do |_|
263
271
  _.query do
@@ -271,7 +279,7 @@ module FakeMediaWiki
271
279
  _.error(nil, { :code => 'nosuchuser', :info => "The user '#{params[:ususer].to_s}' does not exist"} )
272
280
  end
273
281
  end
274
- end
282
+ end
275
283
 
276
284
  def login
277
285
  user = @users[params[:lgname]]
@@ -312,11 +320,11 @@ module FakeMediaWiki
312
320
  end
313
321
 
314
322
  class WikiPage
315
-
323
+
316
324
  def initialize(options={})
317
325
  options.each { |k, v| send("#{k}=", v) }
318
326
  end
319
-
327
+
320
328
  attr_accessor :content, :author
321
329
 
322
330
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mediawiki-gateway
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 11
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 4
9
8
  - 5
10
- version: 0.4.5
9
+ - 0
10
+ version: 0.5.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jani Patokallio
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-04-19 00:00:00 Z
18
+ date: 2012-06-01 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rest-client
@@ -225,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
225
  requirements: []
226
226
 
227
227
  rubyforge_project:
228
- rubygems_version: 1.8.10
228
+ rubygems_version: 1.8.24
229
229
  signing_key:
230
230
  specification_version: 3
231
231
  summary: Connect to the mediawiki API