mediawiki-gateway 0.4.5 → 0.5.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/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