Class: Riki::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/riki/base.rb

Direct Known Subclasses

Page

Constant Summary collapse

HEADERS =
{'User-Agent' => "Riki/v#{Riki::VERSION}"}
DEFAULT_OPTIONS =
{:limit => 500,
:maxlag => 5,
:retry_count => 3,
:retry_delay => 10}

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.cacheObject



22
23
24
# File 'lib/riki/base.rb', line 22

def cache
  @cache ||= ActiveSupport::Cache::NullStore.new
end

.domainObject

Returns the value of attribute domain.



8
9
10
# File 'lib/riki/base.rb', line 8

def domain
  @domain
end

.passwordObject

Returns the value of attribute password.



8
9
10
# File 'lib/riki/base.rb', line 8

def password
  @password
end

.urlObject

Returns the value of attribute url.



8
9
10
# File 'lib/riki/base.rb', line 8

def url
  @url
end

.usernameObject

Returns the value of attribute username.



8
9
10
# File 'lib/riki/base.rb', line 8

def username
  @username
end

Class Method Details

.api_request(form_data, continue_xpath = nil, retry_count = 1, p_options = {}) ⇒ Object

Generic API request to API

form_data

hash or string of attributes to post

continue_xpath

XPath selector for query continue parameter

retry_count

Counter for retries

Returns XML document



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/riki/base.rb', line 58

def api_request(form_data, continue_xpath = nil, retry_count = 1, p_options = {})
  if (!cookies.blank? && cookies["#{cookieprefix}_session"])
    # Attempt to re-use cookies
  else
    # there is no session, we are not currently trying to login, and we gave sufficient auth information
     if form_data['action'] != 'login' && !Riki::Base.username.blank? && !Riki::Base.password.blank?
  end

  options = DEFAULT_OPTIONS.merge(p_options)

  if form_data.kind_of? Hash
    form_data['format'] = 'xml'
    form_data['maxlag'] = options[:maxlag]
    form_data['includexmlnamespace'] = 'true'
  end

  RestClient.post(Riki::Base.url, form_data, HEADERS.merge({:cookies => cookies})) do |response, &block|
    if response.code == 503 and retry_count < options[:retry_count]
      log.warn("503 Service Unavailable: #{response.body}.  Retry in #{options[:retry_delay]} seconds.")
      sleep(options[:retry_delay])
      api_request(form_data, continue_xpath, retry_count + 1)
    end

    # Check response for errors and return XML
    raise "Bad response: #{response}" unless response.code >= 200 and response.code < 300

    doc = parse_response(response.dup)

    # TODO Handle MediaWiki redirects

    if(form_data['action'] == 'login')
       = doc.find_first('m:login')['result']
      Riki::Base.cookieprefix = doc.find_first('m:login')['cookieprefix']

      @cookies.merge!(response.cookies)
      case 
        when "Success"   then Riki::Base.cache.write(cache_key(:cookies), @cookies)
        when "NeedToken" then api_request(form_data.merge('lgtoken' => doc.find('/m:api/m:login').first['token']))
        else raise Unauthorized.new("Login failed: " + )
      end
    end
    continue = (continue_xpath and doc.find('m:query-continue').empty?) ? doc.find_first(continue_xpath).value : nil

    return [doc, continue]
  end
end

.cache_key(key) ⇒ Object



126
127
128
# File 'lib/riki/base.rb', line 126

def cache_key(key)
  "#{Riki::Base.url}##{key}"
end

.cookieprefixObject



136
137
138
# File 'lib/riki/base.rb', line 136

def cookieprefix
  @cookieprefix ||= Riki::Base.cache.read(cache_key(:cookieprefix))
end

.cookieprefix=(cp) ⇒ Object



140
141
142
# File 'lib/riki/base.rb', line 140

def cookieprefix=(cp)
  @cookieprefix ||= Riki::Base.cache.write(cache_key(:cookieprefix), cp)
end

.cookiesObject



130
131
132
133
134
# File 'lib/riki/base.rb', line 130

def cookies
  @cookies ||= Riki::Base.cache.fetch(cache_key(:cookies)) do
    {}
  end
end

.find_by_id(ids) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/riki/base.rb', line 26

def find_by_id(ids)
  expects_array = ids.first.kind_of?(Array)
  return ids.first if expects_array && ids.first.empty?

  ids = ids.flatten.compact.uniq

  case ids.size
    when 0
      raise NotFoundError, "Couldn't find #{name} without an ID"
    when 1
     result = find_one(ids.first)
     expects_array ? [ result ] : result
   else
     find_some(ids)
  end
end

.loginObject

Login to MediaWiki



46
47
48
49
# File 'lib/riki/base.rb', line 46

def 
  raise "No authentication information provided" if Riki::Base.username.nil? || Riki::Base.password.nil?
  api_request({'action' => 'login', 'lgname' => Riki::Base.username, 'lgpassword' => Riki::Base.password, 'lgdomain' => Riki::Base.domain})
end

.parse_response(res) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/riki/base.rb', line 105

def parse_response(res)
  res = res.force_encoding("UTF-8") if res.respond_to?(:force_encoding)
  doc = XML::Parser.string(res).parse.root
  doc.namespaces.default_prefix = 'm'

  raise "Response does not contain Mediawiki API XML: #{res}" unless ["api", "mediawiki"].include? doc.name

  errors = doc.find('/api/error')
  if errors.any?
    code = errors.first["code"]
    info = errors.first["info"]
    raise RikiError.lookup(code).new(info)
  end

  if warnings = doc.find('warnings') && warnings
    warning("API warning: #{warnings.map{|e| e.text}.join(", ")}")
  end

  doc
end